DPDK patches and discussions
 help / color / mirror / Atom feed
* [dpdk-dev] [PATCH 0/3] security: support for pdcp
@ 2018-08-28 13:01 akhil.goyal
  2018-08-28 13:01 ` [dpdk-dev] [PATCH 1/3] security: support pdcp protocol akhil.goyal
                   ` (4 more replies)
  0 siblings, 5 replies; 41+ messages in thread
From: akhil.goyal @ 2018-08-28 13:01 UTC (permalink / raw)
  To: dev; +Cc: Akhil Goyal

From: Akhil Goyal <akhil.goyal@nxp.com>

Security library currently only has support for IPSec protocol.
This patchset defines structures for pdcp protocol in rte_security
and provide a sample driver implementation for lookaside protocol
offload to support PDCP.

Akhil Goyal (3):
  security: support pdcp protocol
  crypto/dpaa2_sec: add sample pdcp descriptor apis
  crypto/dpaa2_sec: support pdcp offload

 doc/guides/prog_guide/rte_security.rst      |   90 +-
 drivers/crypto/dpaa2_sec/dpaa2_sec_dpseci.c |  294 +++
 drivers/crypto/dpaa2_sec/dpaa2_sec_priv.h   |  172 ++
 drivers/crypto/dpaa2_sec/hw/desc.h          |    2 +-
 drivers/crypto/dpaa2_sec/hw/desc/pdcp.h     | 2642 +++++++++++++++++++
 lib/librte_security/rte_security.c          |    4 +
 lib/librte_security/rte_security.h          |   62 +
 7 files changed, 3258 insertions(+), 8 deletions(-)
 create mode 100644 drivers/crypto/dpaa2_sec/hw/desc/pdcp.h

-- 
2.17.1

^ permalink raw reply	[flat|nested] 41+ messages in thread

* [dpdk-dev] [PATCH 1/3] security: support pdcp protocol
  2018-08-28 13:01 [dpdk-dev] [PATCH 0/3] security: support for pdcp akhil.goyal
@ 2018-08-28 13:01 ` akhil.goyal
  2018-09-06  4:15   ` Joseph, Anoob
  2018-08-28 13:01 ` [dpdk-dev] [PATCH 2/3] crypto/dpaa2_sec: add sample pdcp descriptor apis akhil.goyal
                   ` (3 subsequent siblings)
  4 siblings, 1 reply; 41+ messages in thread
From: akhil.goyal @ 2018-08-28 13:01 UTC (permalink / raw)
  To: dev; +Cc: Akhil Goyal

From: Akhil Goyal <akhil.goyal@nxp.com>

Signed-off-by: Hemant Agrawal <hemant.agrawal@nxp.com>
Signed-off-by: Akhil Goyal <akhil.goyal@nxp.com>
---
 doc/guides/prog_guide/rte_security.rst | 90 ++++++++++++++++++++++++--
 lib/librte_security/rte_security.c     |  4 ++
 lib/librte_security/rte_security.h     | 62 ++++++++++++++++++
 3 files changed, 149 insertions(+), 7 deletions(-)

diff --git a/doc/guides/prog_guide/rte_security.rst b/doc/guides/prog_guide/rte_security.rst
index 0812abe77..412fff016 100644
--- a/doc/guides/prog_guide/rte_security.rst
+++ b/doc/guides/prog_guide/rte_security.rst
@@ -10,8 +10,8 @@ The security library provides a framework for management and provisioning
 of security protocol operations offloaded to hardware based devices. The
 library defines generic APIs to create and free security sessions which can
 support full protocol offload as well as inline crypto operation with
-NIC or crypto devices. The framework currently only supports the IPSec protocol
-and associated operations, other protocols will be added in future.
+NIC or crypto devices. The framework currently only supports the IPSec and PDCP
+protocol and associated operations, other protocols will be added in future.
 
 Design Principles
 -----------------
@@ -253,6 +253,46 @@ for any protocol header addition.
         +--------|--------+
                  V
 
+PDCP Flow Diagram
+~~~~~~~~~~~~~~~~~
+
+.. code-block:: c
+
+        Transmitting PDCP Entity          Receiving PDCP Entity
+                  |                                   ^
+                  |                       +-----------|-----------+
+                  V                       | In order delivery and |
+        +---------|----------+            | Duplicate detection   |
+        | Sequence Numbering |            |  (Data Plane only)    |
+        +---------|----------+            +-----------|-----------+
+                  |                                   |
+        +---------|----------+            +-----------|----------+
+        | Header Compression*|            | Header Decompression*|
+        | (Data-Plane only)  |            |   (Data Plane only)  |
+        +---------|----------+            +-----------|----------+
+                  |                                   |
+        +---------|-----------+           +-----------|----------+
+        | Integrity Protection|           |Integrity Verification|
+        | (Control Plane only)|           | (Control Plane only) |
+        +---------|-----------+           +-----------|----------+
+        +---------|-----------+            +----------|----------+
+        |     Ciphering       |            |     Deciphering     |
+        +---------|-----------+            +----------|----------+
+        +---------|-----------+            +----------|----------+
+        |   Add PDCP header   |            | Remove PDCP Header  |
+        +---------|-----------+            +----------|----------+
+                  |                                   |
+                  +----------------->>----------------+
+
+
+.. note::
+
+    * Header Compression and decompression are not supported currently.
+
+Just like IPSec, in case of PDCP also header addition/deletion, cipher/
+de-cipher, integrity protection/verification is done based on the action
+type chosen.
+
 Device Features and Capabilities
 ---------------------------------
 
@@ -271,7 +311,7 @@ structure in the *DPDK API Reference*.
 
 Each driver (crypto or ethernet) defines its own private array of capabilities
 for the operations it supports. Below is an example of the capabilities for a
-PMD which supports the IPSec protocol.
+PMD which supports the IPSec and PDCP protocol.
 
 .. code-block:: c
 
@@ -298,6 +338,22 @@ PMD which supports the IPSec protocol.
                 },
                 .crypto_capabilities = pmd_capabilities
         },
+        { /* PDCP Lookaside Protocol offload Data Plane */
+                .action = RTE_SECURITY_ACTION_TYPE_LOOKASIDE_PROTOCOL,
+                .protocol = RTE_SECURITY_PROTOCOL_PDCP,
+                .pdcp = {
+                        .domain = RTE_SECURITY_PDCP_MODE_DATA,
+                },
+                .crypto_capabilities = pmd_capabilities
+        },
+        { /* PDCP Lookaside Protocol offload Control */
+                .action = RTE_SECURITY_ACTION_TYPE_LOOKASIDE_PROTOCOL,
+                .protocol = RTE_SECURITY_PROTOCOL_PDCP,
+                .pdcp = {
+                        .domain = RTE_SECURITY_PDCP_MODE_CONTROL,
+                },
+                .crypto_capabilities = pmd_capabilities
+        },
         {
                 .action = RTE_SECURITY_ACTION_TYPE_NONE
         }
@@ -429,6 +485,7 @@ Security Session configuration structure is defined as ``rte_security_session_co
         union {
                 struct rte_security_ipsec_xform ipsec;
                 struct rte_security_macsec_xform macsec;
+                struct rte_security_pdcp_xform pdcp;
         };
         /**< Configuration parameters for security session */
         struct rte_crypto_sym_xform *crypto_xform;
@@ -463,15 +520,17 @@ The ``rte_security_session_protocol`` is defined as
 .. code-block:: c
 
     enum rte_security_session_protocol {
-        RTE_SECURITY_PROTOCOL_IPSEC,
+        RTE_SECURITY_PROTOCOL_IPSEC = 1,
         /**< IPsec Protocol */
         RTE_SECURITY_PROTOCOL_MACSEC,
         /**< MACSec Protocol */
+        RTE_SECURITY_PROTOCOL_PDCP,
+        /**< PDCP Protocol */
     };
 
-Currently the library defines configuration parameters for IPSec only. For other
-protocols like MACSec, structures and enums are defined as place holders which
-will be updated in the future.
+Currently the library defines configuration parameters for IPSec and PDCP only.
+For other protocols like MACSec, structures and enums are defined as place holders
+which will be updated in the future.
 
 IPsec related configuration parameters are defined in ``rte_security_ipsec_xform``
 
@@ -494,6 +553,23 @@ IPsec related configuration parameters are defined in ``rte_security_ipsec_xform
         /**< Tunnel parameters, NULL for transport mode */
     };
 
+PDCP related configuration parameters are defined in ``rte_security_pdcp_xform``
+
+.. code-block:: c
+
+    struct rte_security_pdcp_xform {
+        int8_t bearer;	/**< PDCP bearer ID */
+        enum rte_security_pdcp_domain domain;
+        /** < PDCP mode of operation: Control or data */
+        enum rte_security_pdcp_direction pkt_dir;
+        /**< PDCP Frame Direction 0:UL 1:DL */
+        enum rte_security_pdcp_sn_size sn_size;
+        /**< Sequence number size, 5/7/12/15 */
+        int8_t hfn_ovd; /**< Overwrite HFN per operation */
+        uint32_t hfn;	/**< Hyper Frame Number */
+        uint32_t hfn_threshold;	/**< HFN Threashold for key renegotiation */
+    };
+
 
 Security API
 ~~~~~~~~~~~~
diff --git a/lib/librte_security/rte_security.c b/lib/librte_security/rte_security.c
index 1954960a5..c6355de95 100644
--- a/lib/librte_security/rte_security.c
+++ b/lib/librte_security/rte_security.c
@@ -131,6 +131,10 @@ rte_security_capability_get(struct rte_security_ctx *instance,
 					capability->ipsec.direction ==
 							idx->ipsec.direction)
 					return capability;
+			} else if (idx->protocol == RTE_SECURITY_PROTOCOL_PDCP) {
+				if (capability->pdcp.domain ==
+							idx->pdcp.domain)
+					return capability;
 			}
 		}
 	}
diff --git a/lib/librte_security/rte_security.h b/lib/librte_security/rte_security.h
index b0d1b97ee..e625bc656 100644
--- a/lib/librte_security/rte_security.h
+++ b/lib/librte_security/rte_security.h
@@ -206,6 +206,52 @@ struct rte_security_macsec_xform {
 	int dummy;
 };
 
+/**
+ * PDCP Mode of session
+ */
+enum rte_security_pdcp_domain {
+	RTE_SECURITY_PDCP_MODE_CONTROL,	/**< PDCP control plane */
+	RTE_SECURITY_PDCP_MODE_DATA,	/**< PDCP data plane */
+};
+
+/** PDCP Frame direction */
+enum rte_security_pdcp_direction {
+	RTE_SECURITY_PDCP_UPLINK,	/**< Uplink */
+	RTE_SECURITY_PDCP_DOWNLINK,	/**< Downlink */
+};
+
+/**
+ * PDCP Sequence Number Size selectors
+ * @PDCP_SN_SIZE_5: 5bit sequence number
+ * @PDCP_SN_SIZE_7: 7bit sequence number
+ * @PDCP_SN_SIZE_12: 12bit sequence number
+ * @PDCP_SN_SIZE_15: 15bit sequence number
+ */
+enum rte_security_pdcp_sn_size {
+	RTE_SECURITY_PDCP_SN_SIZE_5 = 5,
+	RTE_SECURITY_PDCP_SN_SIZE_7 = 7,
+	RTE_SECURITY_PDCP_SN_SIZE_12 = 12,
+	RTE_SECURITY_PDCP_SN_SIZE_15 = 15
+};
+
+/**
+ * PDCP security association configuration data.
+ *
+ * This structure contains data required to create a PDCP security session.
+ */
+struct rte_security_pdcp_xform {
+	int8_t bearer;	/**< PDCP bearer ID */
+	enum rte_security_pdcp_domain domain;
+		/** < PDCP mode of operation: Control or data */
+	enum rte_security_pdcp_direction pkt_dir;
+		/**< PDCP Frame Direction 0:UL 1:DL */
+	enum rte_security_pdcp_sn_size sn_size;
+		/**< Sequence number size, 5/7/12/15 */
+	int8_t hfn_ovd; /**< Overwrite HFN per operation */
+	uint32_t hfn;	/**< Hyper Frame Number */
+	uint32_t hfn_threshold;	/**< HFN Threashold for key renegotiation */
+};
+
 /**
  * Security session action type.
  */
@@ -232,6 +278,8 @@ enum rte_security_session_protocol {
 	/**< IPsec Protocol */
 	RTE_SECURITY_PROTOCOL_MACSEC,
 	/**< MACSec Protocol */
+	RTE_SECURITY_PROTOCOL_PDCP,
+	/**< PDCP Protocol */
 };
 
 /**
@@ -246,6 +294,7 @@ struct rte_security_session_conf {
 	union {
 		struct rte_security_ipsec_xform ipsec;
 		struct rte_security_macsec_xform macsec;
+		struct rte_security_pdcp_xform pdcp;
 	};
 	/**< Configuration parameters for security session */
 	struct rte_crypto_sym_xform *crypto_xform;
@@ -413,6 +462,10 @@ struct rte_security_ipsec_stats {
 
 };
 
+struct rte_security_pdcp_stats {
+	uint64_t reserved;
+};
+
 struct rte_security_stats {
 	enum rte_security_session_protocol protocol;
 	/**< Security protocol to be configured */
@@ -421,6 +474,7 @@ struct rte_security_stats {
 	union {
 		struct rte_security_macsec_stats macsec;
 		struct rte_security_ipsec_stats ipsec;
+		struct rte_security_pdcp_stats pdcp;
 	};
 };
 
@@ -465,6 +519,11 @@ struct rte_security_capability {
 			int dummy;
 		} macsec;
 		/**< MACsec capability */
+		struct {
+			enum rte_security_pdcp_domain domain;
+			/** < PDCP mode of operation: Control or data */
+		} pdcp;
+		/**< PDCP capability */
 	};
 
 	const struct rte_cryptodev_capabilities *crypto_capabilities;
@@ -506,6 +565,9 @@ struct rte_security_capability_idx {
 			enum rte_security_ipsec_sa_mode mode;
 			enum rte_security_ipsec_sa_direction direction;
 		} ipsec;
+		struct {
+			enum rte_security_pdcp_domain domain;
+		} pdcp;
 	};
 };
 
-- 
2.17.1

^ permalink raw reply	[flat|nested] 41+ messages in thread

* [dpdk-dev] [PATCH 2/3] crypto/dpaa2_sec: add sample pdcp descriptor apis
  2018-08-28 13:01 [dpdk-dev] [PATCH 0/3] security: support for pdcp akhil.goyal
  2018-08-28 13:01 ` [dpdk-dev] [PATCH 1/3] security: support pdcp protocol akhil.goyal
@ 2018-08-28 13:01 ` akhil.goyal
  2018-08-28 13:01 ` [dpdk-dev] [PATCH 3/3] crypto/dpaa2_sec: support pdcp offload akhil.goyal
                   ` (2 subsequent siblings)
  4 siblings, 0 replies; 41+ messages in thread
From: akhil.goyal @ 2018-08-28 13:01 UTC (permalink / raw)
  To: dev; +Cc: Akhil Goyal

From: Akhil Goyal <akhil.goyal@nxp.com>

Signed-off-by: Hemant Agrawal <hemant.agrawal@nxp.com>
Signed-off-by: Horia Geanta Neag <horia.geanta@nxp.com>
Signed-off-by: Alex Porosanu <alexandru.porosanu@nxp.com>
Signed-off-by: Akhil Goyal <akhil.goyal@nxp.com>
---
 drivers/crypto/dpaa2_sec/hw/desc.h      |    2 +-
 drivers/crypto/dpaa2_sec/hw/desc/pdcp.h | 2642 +++++++++++++++++++++++
 2 files changed, 2643 insertions(+), 1 deletion(-)
 create mode 100644 drivers/crypto/dpaa2_sec/hw/desc/pdcp.h

diff --git a/drivers/crypto/dpaa2_sec/hw/desc.h b/drivers/crypto/dpaa2_sec/hw/desc.h
index e92558329..f0e575922 100644
--- a/drivers/crypto/dpaa2_sec/hw/desc.h
+++ b/drivers/crypto/dpaa2_sec/hw/desc.h
@@ -1332,7 +1332,7 @@
 #define OP_PCL_LTE_MIXED_AUTH_SHIFT	0
 #define OP_PCL_LTE_MIXED_AUTH_MASK	(3 << OP_PCL_LTE_MIXED_AUTH_SHIFT)
 #define OP_PCL_LTE_MIXED_ENC_SHIFT	8
-#define OP_PCL_LTE_MIXED_ENC_MASK	(3 < OP_PCL_LTE_MIXED_ENC_SHIFT)
+#define OP_PCL_LTE_MIXED_ENC_MASK	(3 << OP_PCL_LTE_MIXED_ENC_SHIFT)
 #define OP_PCL_LTE_MIXED_AUTH_NULL	(OP_PCL_LTE_NULL << \
 					 OP_PCL_LTE_MIXED_AUTH_SHIFT)
 #define OP_PCL_LTE_MIXED_AUTH_SNOW	(OP_PCL_LTE_SNOW << \
diff --git a/drivers/crypto/dpaa2_sec/hw/desc/pdcp.h b/drivers/crypto/dpaa2_sec/hw/desc/pdcp.h
new file mode 100644
index 000000000..4e218f513
--- /dev/null
+++ b/drivers/crypto/dpaa2_sec/hw/desc/pdcp.h
@@ -0,0 +1,2642 @@
+/*
+ * Copyright 2008-2013 Freescale Semiconductor, Inc.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause or GPL-2.0+
+ */
+
+#ifndef __DESC_PDCP_H__
+#define __DESC_PDCP_H__
+
+#include "hw/rta.h"
+#include "common.h"
+
+/**
+ * DOC: PDCP Shared Descriptor Constructors
+ *
+ * Shared descriptors for PDCP protocol.
+ */
+
+/**
+ * PDCP_NULL_MAX_FRAME_LEN - The maximum frame frame length that is supported by
+ *                           PDCP NULL protocol.
+ */
+#define PDCP_NULL_MAX_FRAME_LEN		0x00002FFF
+
+/**
+ * PDCP_MAC_I_LEN - The length of the MAC-I for PDCP protocol operation
+ */
+#define PDCP_MAC_I_LEN			0x00000004
+
+/**
+ * PDCP_MAX_FRAME_LEN_STATUS - The status returned in FD status/command field in
+ *                             case the input frame is larger than
+ *                             PDCP_NULL_MAX_FRAME_LEN.
+ */
+#define PDCP_MAX_FRAME_LEN_STATUS	0xF1
+
+/**
+ * PDCP_C_PLANE_SN_MASK - This mask is used in the PDCP descriptors for
+ *                        extracting the sequence number (SN) from the PDCP
+ *                        Control Plane header. For PDCP Control Plane, the SN
+ *                        is constant (5 bits) as opposed to PDCP Data Plane
+ *                        (7/12/15 bits).
+ */
+#define PDCP_C_PLANE_SN_MASK		0x0000001F
+
+/**
+ * PDCP_U_PLANE_15BIT_SN_MASK - This mask is used in the PDCP descriptors for
+ *                              extracting the sequence number (SN) from the
+ *                              PDCP User Plane header. For PDCP Control Plane,
+ *                              the SN is constant (5 bits) as opposed to PDCP
+ *                              Data Plane (7/12/15 bits).
+ */
+#define PDCP_U_PLANE_15BIT_SN_MASK	0x00007FFF
+
+/**
+ * PDCP_BEARER_MASK - This mask is used masking out the bearer for PDCP
+ *                    processing with SNOW f9 in LTE.
+ *
+ * The value on which this mask is applied is formatted as below:
+ *     Count-C (32 bit) | Bearer (5 bit) | Direction (1 bit) | 0 (26 bits)
+ *
+ * Applying this mask is done for creating the upper 64 bits of the IV needed
+ * for SNOW f9.
+ *
+ * The lower 32 bits of the mask are used for masking the direction for AES
+ * CMAC IV.
+ */
+#define PDCP_BEARER_MASK		0xFFFFFFFF04000000ull
+
+/**
+ * PDCP_DIR_MASK - This mask is used masking out the direction for PDCP
+ *                 processing with SNOW f9 in LTE.
+ *
+ * The value on which this mask is applied is formatted as below:
+ *     Bearer (5 bit) | Direction (1 bit) | 0 (26 bits)
+ *
+ * Applying this mask is done for creating the lower 32 bits of the IV needed
+ * for SNOW f9.
+ *
+ * The upper 32 bits of the mask are used for masking the direction for AES
+ * CMAC IV.
+ */
+#define PDCP_DIR_MASK			0xF800000000000000ull
+
+/**
+ * PDCP_NULL_INT_MAC_I_VAL - The value of the PDCP PDU MAC-I in case NULL
+ *                           integrity is used.
+ */
+
+#define PDCP_NULL_INT_MAC_I_VAL		0x00000000
+
+/**
+ * PDCP_NULL_INT_ICV_CHECK_FAILED_STATUS - The status used to report ICV check
+ *                                         failed in case of NULL integrity
+ *                                         Control Plane processing.
+ */
+#define PDCP_NULL_INT_ICV_CHECK_FAILED_STATUS	0x0A
+/**
+ * PDCP_DPOVRD_HFN_OV_EN - Value to be used in the FD status/cmd field to
+ *                         indicate the HFN override mechanism is active for the
+ *                         frame.
+ */
+#define PDCP_DPOVRD_HFN_OV_EN		0x80000000
+
+/**
+ * PDCP_P4080REV2_HFN_OV_BUFLEN - The length in bytes of the supplementary space
+ *                                that must be provided by the user at the
+ *                                beginning of the input frame buffer for
+ *                                P4080 REV 2.
+ *
+ * The format of the frame buffer is the following:
+ *
+ *  |<---PDCP_P4080REV2_HFN_OV_BUFLEN-->|
+ * //===================================||============||==============\\
+ * || PDCP_DPOVRD_HFN_OV_EN | HFN value || PDCP Header|| PDCP Payload ||
+ * \\===================================||============||==============//
+ *
+ * If HFN override mechanism is not desired, then the MSB of the first 4 bytes
+ * must be set to 0b.
+ */
+#define PDCP_P4080REV2_HFN_OV_BUFLEN	4
+
+/**
+ * enum cipher_type_pdcp - Type selectors for cipher types in PDCP protocol OP
+ *                         instructions.
+ * @PDCP_CIPHER_TYPE_NULL: NULL
+ * @PDCP_CIPHER_TYPE_SNOW: SNOW F8
+ * @PDCP_CIPHER_TYPE_AES: AES
+ * @PDCP_CIPHER_TYPE_ZUC: ZUCE
+ * @PDCP_CIPHER_TYPE_INVALID: invalid option
+ */
+enum cipher_type_pdcp {
+	PDCP_CIPHER_TYPE_NULL,
+	PDCP_CIPHER_TYPE_SNOW,
+	PDCP_CIPHER_TYPE_AES,
+	PDCP_CIPHER_TYPE_ZUC,
+	PDCP_CIPHER_TYPE_INVALID
+};
+
+/**
+ * enum auth_type_pdcp - Type selectors for integrity types in PDCP protocol OP
+ *                       instructions.
+ * @PDCP_AUTH_TYPE_NULL: NULL
+ * @PDCP_AUTH_TYPE_SNOW: SNOW F9
+ * @PDCP_AUTH_TYPE_AES: AES CMAC
+ * @PDCP_AUTH_TYPE_ZUC: ZUCA
+ * @PDCP_AUTH_TYPE_INVALID: invalid option
+ */
+enum auth_type_pdcp {
+	PDCP_AUTH_TYPE_NULL,
+	PDCP_AUTH_TYPE_SNOW,
+	PDCP_AUTH_TYPE_AES,
+	PDCP_AUTH_TYPE_ZUC,
+	PDCP_AUTH_TYPE_INVALID
+};
+
+/**
+ * enum pdcp_dir - Type selectors for direction for PDCP protocol
+ * @PDCP_DIR_UPLINK: uplink direction
+ * @PDCP_DIR_DOWNLINK: downlink direction
+ * @PDCP_DIR_INVALID: invalid option
+ */
+enum pdcp_dir {
+	PDCP_DIR_UPLINK = 0,
+	PDCP_DIR_DOWNLINK = 1,
+	PDCP_DIR_INVALID
+};
+
+/**
+ * enum pdcp_plane - PDCP domain selectors
+ * @PDCP_CONTROL_PLANE: Control Plane
+ * @PDCP_DATA_PLANE: Data Plane
+ * @PDCP_SHORT_MAC: Short MAC
+ */
+enum pdcp_plane {
+	PDCP_CONTROL_PLANE,
+	PDCP_DATA_PLANE,
+	PDCP_SHORT_MAC
+};
+
+/**
+ * enum pdcp_sn_size - Sequence Number Size selectors for PDCP protocol
+ * @PDCP_SN_SIZE_5: 5bit sequence number
+ * @PDCP_SN_SIZE_7: 7bit sequence number
+ * @PDCP_SN_SIZE_12: 12bit sequence number
+ * @PDCP_SN_SIZE_15: 15bit sequence number
+ */
+enum pdcp_sn_size {
+	PDCP_SN_SIZE_5 = 5,
+	PDCP_SN_SIZE_7 = 7,
+	PDCP_SN_SIZE_12 = 12,
+	PDCP_SN_SIZE_15 = 15
+};
+
+/*
+ * PDCP Control Plane Protocol Data Blocks
+ */
+#define PDCP_C_PLANE_PDB_HFN_SHIFT		5
+#define PDCP_C_PLANE_PDB_BEARER_SHIFT		27
+#define PDCP_C_PLANE_PDB_DIR_SHIFT		26
+#define PDCP_C_PLANE_PDB_HFN_THR_SHIFT		5
+
+#define PDCP_U_PLANE_PDB_OPT_SHORT_SN		0x2
+#define PDCP_U_PLANE_PDB_OPT_15B_SN		0x4
+#define PDCP_U_PLANE_PDB_SHORT_SN_HFN_SHIFT	7
+#define PDCP_U_PLANE_PDB_LONG_SN_HFN_SHIFT	12
+#define PDCP_U_PLANE_PDB_15BIT_SN_HFN_SHIFT	15
+#define PDCP_U_PLANE_PDB_BEARER_SHIFT		27
+#define PDCP_U_PLANE_PDB_DIR_SHIFT		26
+#define PDCP_U_PLANE_PDB_SHORT_SN_HFN_THR_SHIFT	7
+#define PDCP_U_PLANE_PDB_LONG_SN_HFN_THR_SHIFT	12
+#define PDCP_U_PLANE_PDB_15BIT_SN_HFN_THR_SHIFT	15
+
+struct pdcp_pdb {
+	union {
+		uint32_t opt;
+		uint32_t rsvd;
+	} opt_res;
+	uint32_t hfn_res;	/* HyperFrame number,(27, 25 or 21 bits),
+				 * left aligned & right-padded with zeros. */
+	uint32_t bearer_dir_res;/* Bearer(5 bits), packet direction (1 bit),
+				 * left aligned & right-padded with zeros. */
+	uint32_t hfn_thr_res;	/* HyperFrame number threshold (27, 25 or 21
+				 * bits), left aligned & right-padded with
+				 * zeros. */
+};
+
+/*
+ * PDCP internal PDB types
+ */
+enum pdb_type_e {
+	PDCP_PDB_TYPE_NO_PDB,
+	PDCP_PDB_TYPE_FULL_PDB,
+	PDCP_PDB_TYPE_REDUCED_PDB,
+	PDCP_PDB_TYPE_INVALID
+};
+
+/*
+ * Function for appending the portion of a PDCP Control Plane shared descriptor
+ * which performs NULL encryption and integrity (i.e. copies the input frame
+ * to the output frame, appending 32 bits of zeros at the end (MAC-I for
+ * NULL integrity).
+ */
+static inline int pdcp_insert_cplane_null_op(struct program *p,
+		struct alginfo *cipherdata __maybe_unused,
+		struct alginfo *authdata __maybe_unused,
+		unsigned dir,
+		unsigned char era_2_sw_hfn_override __maybe_unused)
+{
+	LABEL(local_offset);
+	REFERENCE(move_cmd_read_descbuf);
+	REFERENCE(move_cmd_write_descbuf);
+
+	if (rta_sec_era > RTA_SEC_ERA_2) {
+		MATHB(p, SEQINSZ, ADD, ZERO, VSEQINSZ, 4, 0);
+		if (dir == OP_TYPE_ENCAP_PROTOCOL)
+			MATHB(p, SEQINSZ, ADD, PDCP_MAC_I_LEN, VSEQOUTSZ, 4,
+			      IMMED2);
+		else
+			MATHB(p, SEQINSZ, SUB, PDCP_MAC_I_LEN, VSEQOUTSZ, 4,
+			      IMMED2);
+	} else {
+		MATHB(p, SEQINSZ, ADD, ONE, VSEQINSZ, 4, 0);
+		MATHB(p, VSEQINSZ, SUB, ONE, VSEQINSZ, 4, 0);
+
+		if (dir == OP_TYPE_ENCAP_PROTOCOL) {
+			MATHB(p, SEQINSZ, ADD, PDCP_MAC_I_LEN, VSEQOUTSZ, 4,
+			      IMMED2);
+			MATHB(p, VSEQINSZ, SUB, ONE, MATH0, 4, 0);
+		} else {
+			MATHB(p, VSEQINSZ, SUB, PDCP_MAC_I_LEN, VSEQINSZ, 4,
+			      IMMED2);
+			MATHB(p, SEQINSZ, SUB, PDCP_MAC_I_LEN, VSEQOUTSZ, 4,
+			      IMMED2);
+			MATHB(p, VSEQOUTSZ, SUB, ONE, MATH0, 4, 0);
+		}
+
+		MATHB(p, MATH0, ADD, ONE, MATH0, 4, 0);
+
+		/*
+		 * Since MOVELEN is available only starting with
+		 * SEC ERA 3, use poor man's MOVELEN: create a MOVE
+		 * command dynamically by writing the length from M1 by
+		 * OR-ing the command in the M1 register and MOVE the
+		 * result into the descriptor buffer. Care must be taken
+		 * wrt. the location of the command because of SEC
+		 * pipelining. The actual MOVEs are written at the end
+		 * of the descriptor due to calculations needed on the
+		 * offset in the descriptor for the MOVE command.
+		 */
+		move_cmd_read_descbuf = MOVE(p, DESCBUF, 0, MATH0, 0, 6,
+					     IMMED);
+		move_cmd_write_descbuf = MOVE(p, MATH0, 0, DESCBUF, 0, 8,
+					      WAITCOMP | IMMED);
+	}
+	MATHB(p, VSEQINSZ, SUB, PDCP_NULL_MAX_FRAME_LEN, NONE, 4,
+	      IMMED2);
+	JUMP(p, PDCP_MAX_FRAME_LEN_STATUS, HALT_STATUS, ALL_FALSE, MATH_N);
+
+	if (rta_sec_era > RTA_SEC_ERA_2) {
+		if (dir == OP_TYPE_ENCAP_PROTOCOL)
+			MATHB(p, VSEQINSZ, ADD, ZERO, MATH0, 4, 0);
+		else
+			MATHB(p, VSEQOUTSZ, ADD, ZERO, MATH0, 4, 0);
+	}
+	SEQFIFOSTORE(p, MSG, 0, 0, VLF);
+	SEQFIFOLOAD(p, MSG1, 0, VLF | LAST1 | FLUSH1);
+
+	if (rta_sec_era > RTA_SEC_ERA_2) {
+		MOVE(p, AB1, 0, OFIFO, 0, MATH0, 0);
+	} else {
+		SET_LABEL(p, local_offset);
+
+		/* Shut off automatic Info FIFO entries */
+		LOAD(p, 0, DCTRL, LDOFF_DISABLE_AUTO_NFIFO, 0, IMMED);
+		/* Placeholder for MOVE command with length from M1 register */
+		MOVE(p, IFIFOAB1, 0, OFIFO, 0, 0, IMMED);
+		/* Enable automatic Info FIFO entries */
+		LOAD(p, 0, DCTRL, LDOFF_ENABLE_AUTO_NFIFO, 0, IMMED);
+	}
+
+	if (dir == OP_TYPE_ENCAP_PROTOCOL) {
+		MATHB(p, MATH1, XOR, MATH1, MATH0, 8, 0);
+		MOVE(p, MATH0, 0, OFIFO, 0, 4, IMMED);
+	}
+
+	if (rta_sec_era < RTA_SEC_ERA_3) {
+		PATCH_MOVE(p, move_cmd_read_descbuf, local_offset);
+		PATCH_MOVE(p, move_cmd_write_descbuf, local_offset);
+	}
+
+	return 0;
+}
+
+static inline int insert_copy_frame_op(struct program *p,
+				struct alginfo *cipherdata __maybe_unused,
+				unsigned dir __maybe_unused)
+{
+	LABEL(local_offset);
+	REFERENCE(move_cmd_read_descbuf);
+	REFERENCE(move_cmd_write_descbuf);
+
+	if (rta_sec_era > RTA_SEC_ERA_2) {
+		MATHB(p, SEQINSZ, ADD, ZERO, VSEQINSZ,  4, 0);
+		MATHB(p, SEQINSZ, ADD, ZERO, VSEQOUTSZ,  4, 0);
+	} else {
+		MATHB(p, SEQINSZ, ADD, ONE, VSEQINSZ,  4, 0);
+		MATHB(p, VSEQINSZ, SUB, ONE, VSEQINSZ,  4, 0);
+		MATHB(p, SEQINSZ, ADD, ONE, VSEQOUTSZ,  4, 0);
+		MATHB(p, VSEQOUTSZ, SUB, ONE, VSEQOUTSZ,  4, 0);
+		MATHB(p, VSEQINSZ, SUB, ONE, MATH0,  4, 0);
+		MATHB(p, MATH0, ADD, ONE, MATH0,  4, 0);
+
+		/*
+		 * Since MOVELEN is available only starting with
+		 * SEC ERA 3, use poor man's MOVELEN: create a MOVE
+		 * command dynamically by writing the length from M1 by
+		 * OR-ing the command in the M1 register and MOVE the
+		 * result into the descriptor buffer. Care must be taken
+		 * wrt. the location of the command because of SEC
+		 * pipelining. The actual MOVEs are written at the end
+		 * of the descriptor due to calculations needed on the
+		 * offset in the descriptor for the MOVE command.
+		 */
+		move_cmd_read_descbuf = MOVE(p, DESCBUF, 0, MATH0, 0, 6,
+					     IMMED);
+		move_cmd_write_descbuf = MOVE(p, MATH0, 0, DESCBUF, 0, 8,
+					      WAITCOMP | IMMED);
+	}
+	MATHB(p, SEQINSZ, SUB, PDCP_NULL_MAX_FRAME_LEN, NONE,  4,
+	      IFB | IMMED2);
+	JUMP(p, PDCP_MAX_FRAME_LEN_STATUS, HALT_STATUS, ALL_FALSE, MATH_N);
+
+	if (rta_sec_era > RTA_SEC_ERA_2)
+		MATHB(p, VSEQINSZ, ADD, ZERO, MATH0,  4, 0);
+
+	SEQFIFOLOAD(p, MSG1, 0, VLF | LAST1 | FLUSH1);
+	if (rta_sec_era > RTA_SEC_ERA_2) {
+		MOVE(p, AB1, 0, OFIFO, 0, MATH0, 0);
+	} else {
+		SET_LABEL(p, local_offset);
+
+		/* Shut off automatic Info FIFO entries */
+		LOAD(p, 0, DCTRL, LDOFF_DISABLE_AUTO_NFIFO, 0, IMMED);
+
+		/* Placeholder for MOVE command with length from M0 register */
+		MOVE(p, IFIFOAB1, 0, OFIFO, 0, 0, IMMED);
+
+		/* Enable automatic Info FIFO entries */
+		LOAD(p, 0, DCTRL, LDOFF_ENABLE_AUTO_NFIFO, 0, IMMED);
+	}
+
+	SEQFIFOSTORE(p, MSG, 0, 0, VLF);
+
+	if (rta_sec_era < RTA_SEC_ERA_3) {
+		PATCH_MOVE(p, move_cmd_read_descbuf, local_offset);
+		PATCH_MOVE(p, move_cmd_write_descbuf, local_offset);
+	}
+	return 0;
+}
+
+static inline int pdcp_insert_cplane_int_only_op(struct program *p,
+		struct alginfo *cipherdata __maybe_unused,
+		struct alginfo *authdata,
+		unsigned dir,
+		unsigned char era_2_sw_hfn_override)
+{
+	LABEL(local_offset);
+	REFERENCE(move_cmd_read_descbuf);
+	REFERENCE(move_cmd_write_descbuf);
+
+	switch (authdata->algtype) {
+	case PDCP_AUTH_TYPE_SNOW:
+		/* Insert Auth Key */
+		KEY(p, KEY2, authdata->key_enc_flags, authdata->key,
+		    authdata->keylen, INLINE_KEY(authdata));
+		SEQLOAD(p, MATH0, 7, 1, 0);
+		JUMP(p, 1, LOCAL_JUMP, ALL_TRUE, CALM);
+
+		if (rta_sec_era > RTA_SEC_ERA_2 ||
+		    (rta_sec_era == RTA_SEC_ERA_2 &&
+				   era_2_sw_hfn_override == 0)) {
+			SEQINPTR(p, 0, 1, RTO);
+		} else {
+			SEQINPTR(p, 0, 5, RTO);
+			SEQFIFOLOAD(p, SKIP, 4, 0);
+		}
+
+		MATHB(p, MATH0, AND, PDCP_C_PLANE_SN_MASK, MATH1,  8,
+		      IFB | IMMED2);
+		MATHB(p, MATH1, SHLD, MATH1, MATH1,  8, 0);
+		MOVE(p, DESCBUF, 8, MATH2, 0, 8, WAITCOMP | IMMED);
+		MATHB(p, MATH2, AND, PDCP_BEARER_MASK, MATH2, 8,
+		      IMMED2);
+		MOVE(p, DESCBUF, 0x0C, MATH3, 0, 4, WAITCOMP | IMMED);
+		MATHB(p, MATH3, AND, PDCP_DIR_MASK, MATH3, 8,
+		      IMMED2);
+		MATHB(p, MATH1, OR, MATH2, MATH2, 8, 0);
+		MOVE(p, MATH2, 0, CONTEXT2, 0, 0x0C, WAITCOMP | IMMED);
+
+		if (dir == OP_TYPE_DECAP_PROTOCOL) {
+			MATHB(p, SEQINSZ, SUB, PDCP_MAC_I_LEN, MATH1, 4,
+			      IMMED2);
+		} else {
+			if (rta_sec_era > RTA_SEC_ERA_2) {
+				MATHB(p, SEQINSZ, SUB, ZERO, MATH1, 4,
+				      0);
+			} else {
+				MATHB(p, SEQINSZ, ADD, ONE, MATH1, 4,
+				      0);
+				MATHB(p, MATH1, SUB, ONE, MATH1, 4,
+				      0);
+			}
+		}
+
+		if (rta_sec_era > RTA_SEC_ERA_2) {
+			MATHB(p, MATH1, SUB, ZERO, VSEQINSZ, 4, 0);
+			MATHB(p, MATH1, SUB, ZERO, VSEQOUTSZ, 4, 0);
+		} else {
+			MATHB(p, ZERO, ADD, MATH1, VSEQINSZ, 4, 0);
+			MATHB(p, ZERO, ADD, MATH1, VSEQOUTSZ, 4, 0);
+
+			/*
+			 * Since MOVELEN is available only starting with
+			 * SEC ERA 3, use poor man's MOVELEN: create a MOVE
+			 * command dynamically by writing the length from M1 by
+			 * OR-ing the command in the M1 register and MOVE the
+			 * result into the descriptor buffer. Care must be taken
+			 * wrt. the location of the command because of SEC
+			 * pipelining. The actual MOVEs are written at the end
+			 * of the descriptor due to calculations needed on the
+			 * offset in the descriptor for the MOVE command.
+			 */
+			move_cmd_read_descbuf = MOVE(p, DESCBUF, 0, MATH1, 0, 6,
+						     IMMED);
+			move_cmd_write_descbuf = MOVE(p, MATH1, 0, DESCBUF, 0,
+						      8, WAITCOMP | IMMED);
+		}
+
+		SEQFIFOSTORE(p, MSG, 0, 0, VLF);
+		ALG_OPERATION(p, OP_ALG_ALGSEL_SNOW_F9, OP_ALG_AAI_F9,
+			      OP_ALG_AS_INITFINAL,
+			      dir == OP_TYPE_ENCAP_PROTOCOL ?
+				     ICV_CHECK_DISABLE : ICV_CHECK_ENABLE,
+			      DIR_ENC);
+
+		if (rta_sec_era > RTA_SEC_ERA_2) {
+			SEQFIFOLOAD(p, MSGINSNOOP, 0,
+				    VLF | LAST1 | LAST2 | FLUSH1);
+			MOVE(p, AB1, 0, OFIFO, 0, MATH1, 0);
+		} else {
+			SEQFIFOLOAD(p, MSGINSNOOP, 0,
+				    VLF | LAST1 | LAST2 | FLUSH1);
+			SET_LABEL(p, local_offset);
+
+			/* Shut off automatic Info FIFO entries */
+			LOAD(p, 0, DCTRL, LDOFF_DISABLE_AUTO_NFIFO, 0, IMMED);
+			/*
+			 * Placeholder for MOVE command with length from M1
+			 * register
+			 */
+			MOVE(p, IFIFOAB1, 0, OFIFO, 0, 0, IMMED);
+			/* Enable automatic Info FIFO entries */
+			LOAD(p, 0, DCTRL, LDOFF_ENABLE_AUTO_NFIFO, 0, IMMED);
+		}
+
+		if (dir == OP_TYPE_DECAP_PROTOCOL)
+			SEQFIFOLOAD(p, ICV2, 4, LAST2);
+		else
+			SEQSTORE(p, CONTEXT2, 0, 4, 0);
+
+		break;
+
+	case PDCP_AUTH_TYPE_AES:
+		/* Insert Auth Key */
+		KEY(p, KEY1, authdata->key_enc_flags, authdata->key,
+		    authdata->keylen, INLINE_KEY(authdata));
+		SEQLOAD(p, MATH0, 7, 1, 0);
+		JUMP(p, 1, LOCAL_JUMP, ALL_TRUE, CALM);
+		if (rta_sec_era > RTA_SEC_ERA_2 ||
+		    (rta_sec_era == RTA_SEC_ERA_2 &&
+		     era_2_sw_hfn_override == 0)) {
+			SEQINPTR(p, 0, 1, RTO);
+		} else {
+			SEQINPTR(p, 0, 5, RTO);
+			SEQFIFOLOAD(p, SKIP, 4, 0);
+		}
+
+		MATHB(p, MATH0, AND, PDCP_C_PLANE_SN_MASK, MATH1, 8,
+		      IFB | IMMED2);
+		MATHB(p, MATH1, SHLD, MATH1, MATH1, 8, 0);
+		MOVE(p, DESCBUF, 8, MATH2, 0, 8, WAITCOMP | IMMED);
+		MATHB(p, MATH1, OR, MATH2, MATH2, 8, 0);
+		MOVE(p, MATH2, 0, IFIFOAB1, 0, 8, IMMED);
+		if (dir == OP_TYPE_DECAP_PROTOCOL) {
+			MATHB(p, SEQINSZ, SUB, PDCP_MAC_I_LEN, MATH1, 4,
+			      IMMED2);
+		} else {
+			if (rta_sec_era > RTA_SEC_ERA_2) {
+				MATHB(p, SEQINSZ, SUB, ZERO, MATH1, 4,
+				      0);
+			} else {
+				MATHB(p, SEQINSZ, ADD, ONE, MATH1, 4,
+				      0);
+				MATHB(p, MATH1, SUB, ONE, MATH1, 4,
+				      0);
+			}
+		}
+
+		if (rta_sec_era > RTA_SEC_ERA_2) {
+			MATHB(p, MATH1, SUB, ZERO, VSEQINSZ, 4, 0);
+			MATHB(p, MATH1, SUB, ZERO, VSEQOUTSZ, 4, 0);
+		} else {
+			MATHB(p, ZERO, ADD, MATH1, VSEQINSZ, 4, 0);
+			MATHB(p, ZERO, ADD, MATH1, VSEQOUTSZ, 4, 0);
+
+			/*
+			 * Since MOVELEN is available only starting with
+			 * SEC ERA 3, use poor man's MOVELEN: create a MOVE
+			 * command dynamically by writing the length from M1 by
+			 * OR-ing the command in the M1 register and MOVE the
+			 * result into the descriptor buffer. Care must be taken
+			 * wrt. the location of the command because of SEC
+			 * pipelining. The actual MOVEs are written at the end
+			 * of the descriptor due to calculations needed on the
+			 * offset in the descriptor for the MOVE command.
+			 */
+			move_cmd_read_descbuf = MOVE(p, DESCBUF, 0, MATH1, 0, 6,
+						     IMMED);
+			move_cmd_write_descbuf = MOVE(p, MATH1, 0, DESCBUF, 0,
+						      8, WAITCOMP | IMMED);
+		}
+		SEQFIFOSTORE(p, MSG, 0, 0, VLF);
+		ALG_OPERATION(p, OP_ALG_ALGSEL_AES,
+			      OP_ALG_AAI_CMAC,
+			      OP_ALG_AS_INITFINAL,
+			      dir == OP_TYPE_ENCAP_PROTOCOL ?
+				     ICV_CHECK_DISABLE : ICV_CHECK_ENABLE,
+			      DIR_ENC);
+
+		if (rta_sec_era > RTA_SEC_ERA_2) {
+			MOVE(p, AB2, 0, OFIFO, 0, MATH1, 0);
+			SEQFIFOLOAD(p, MSGINSNOOP, 0,
+				    VLF | LAST1 | LAST2 | FLUSH1);
+		} else {
+			SEQFIFOLOAD(p, MSGINSNOOP, 0,
+				    VLF | LAST1 | LAST2 | FLUSH1);
+			SET_LABEL(p, local_offset);
+
+			/* Shut off automatic Info FIFO entries */
+			LOAD(p, 0, DCTRL, LDOFF_DISABLE_AUTO_NFIFO, 0, IMMED);
+
+			/*
+			 * Placeholder for MOVE command with length from
+			 * M1 register
+			 * */
+			MOVE(p, IFIFOAB2, 0, OFIFO, 0, 0, IMMED);
+
+			/* Enable automatic Info FIFO entries */
+			LOAD(p, 0, DCTRL, LDOFF_ENABLE_AUTO_NFIFO, 0, IMMED);
+		}
+
+		if (dir == OP_TYPE_DECAP_PROTOCOL)
+			SEQFIFOLOAD(p, ICV1, 4, LAST1 | FLUSH1);
+		else
+			SEQSTORE(p, CONTEXT1, 0, 4, 0);
+
+		break;
+
+	case PDCP_AUTH_TYPE_ZUC:
+		if (rta_sec_era < RTA_SEC_ERA_5) {
+			pr_err("Invalid era for selected algorithm\n");
+			return -ENOTSUP;
+		}
+		/* Insert Auth Key */
+		KEY(p, KEY2, authdata->key_enc_flags, authdata->key,
+		    authdata->keylen, INLINE_KEY(authdata));
+		SEQLOAD(p, MATH0, 7, 1, 0);
+		JUMP(p, 1, LOCAL_JUMP, ALL_TRUE, CALM);
+		SEQINPTR(p, 0, 1, RTO);
+		MATHB(p, MATH0, AND, PDCP_C_PLANE_SN_MASK, MATH1, 8,
+		      IFB | IMMED2);
+		MATHB(p, MATH1, SHLD, MATH1, MATH1, 8, 0);
+		MOVE(p, DESCBUF, 8, MATH2, 0, 8, WAITCOMP | IMMED);
+		MATHB(p, MATH1, OR, MATH2, MATH2, 8, 0);
+		MOVE(p, MATH2, 0, CONTEXT2, 0, 8, IMMED);
+
+		if (dir == OP_TYPE_DECAP_PROTOCOL)
+			MATHB(p, SEQINSZ, SUB, PDCP_MAC_I_LEN, MATH1, 4,
+			      IMMED2);
+		else
+			MATHB(p, SEQINSZ, SUB, ZERO, MATH1, 4, 0);
+
+		MATHB(p, MATH1, SUB, ZERO, VSEQINSZ, 4, 0);
+		MATHB(p, MATH1, SUB, ZERO, VSEQOUTSZ, 4, 0);
+		SEQFIFOSTORE(p, MSG, 0, 0, VLF);
+		ALG_OPERATION(p, OP_ALG_ALGSEL_ZUCA,
+			      OP_ALG_AAI_F9,
+			      OP_ALG_AS_INITFINAL,
+			      dir == OP_TYPE_ENCAP_PROTOCOL ?
+				     ICV_CHECK_DISABLE : ICV_CHECK_ENABLE,
+			      DIR_ENC);
+		SEQFIFOLOAD(p, MSGINSNOOP, 0, VLF | LAST1 | LAST2 | FLUSH1);
+		MOVE(p, AB1, 0, OFIFO, 0, MATH1, 0);
+
+		if (dir == OP_TYPE_DECAP_PROTOCOL)
+			SEQFIFOLOAD(p, ICV2, 4, LAST2);
+		else
+			SEQSTORE(p, CONTEXT2, 0, 4, 0);
+
+		break;
+
+	default:
+		pr_err("%s: Invalid integrity algorithm selected: %d\n",
+		       "pdcp_insert_cplane_int_only_op", authdata->algtype);
+		return -EINVAL;
+	}
+
+	if (rta_sec_era < RTA_SEC_ERA_3) {
+		PATCH_MOVE(p, move_cmd_read_descbuf, local_offset);
+		PATCH_MOVE(p, move_cmd_write_descbuf, local_offset);
+	}
+
+	return 0;
+}
+
+static inline int pdcp_insert_cplane_enc_only_op(struct program *p,
+		struct alginfo *cipherdata,
+		struct alginfo *authdata __maybe_unused,
+		unsigned dir,
+		unsigned char era_2_sw_hfn_override __maybe_unused)
+{
+	/* Insert Cipher Key */
+	KEY(p, KEY1, cipherdata->key_enc_flags, cipherdata->key,
+	    cipherdata->keylen, INLINE_KEY(cipherdata));
+
+	if (rta_sec_era >= RTA_SEC_ERA_8) {
+		PROTOCOL(p, dir, OP_PCLID_LTE_PDCP_CTRL_MIXED,
+				(uint16_t)cipherdata->algtype << 8);
+		return 0;
+	}
+
+	SEQLOAD(p, MATH0, 7, 1, 0);
+	JUMP(p, 1, LOCAL_JUMP, ALL_TRUE, CALM);
+	MATHB(p, MATH0, AND, PDCP_C_PLANE_SN_MASK, MATH1, 8, IFB | IMMED2);
+	SEQSTORE(p, MATH0, 7, 1, 0);
+	MATHB(p, MATH1, SHLD, MATH1, MATH1, 8, 0);
+	MOVE(p, DESCBUF, 8, MATH2, 0, 8, WAITCOMP | IMMED);
+	MATHB(p, MATH1, OR, MATH2, MATH2, 8, 0);
+
+	switch (cipherdata->algtype) {
+	case PDCP_CIPHER_TYPE_SNOW:
+		MOVE(p, MATH2, 0, CONTEXT1, 0, 8, WAITCOMP | IMMED);
+
+		if (rta_sec_era > RTA_SEC_ERA_2) {
+			MATHB(p, SEQINSZ, SUB, ZERO, VSEQINSZ, 4, 0);
+		} else {
+			MATHB(p, SEQINSZ, SUB, ONE, MATH1, 4, 0);
+			MATHB(p, MATH1, ADD, ONE, VSEQINSZ, 4, 0);
+		}
+
+		if (dir == OP_TYPE_ENCAP_PROTOCOL)
+			MATHB(p, SEQINSZ, ADD, PDCP_MAC_I_LEN, VSEQOUTSZ, 4,
+			      IMMED2);
+		else
+			MATHB(p, SEQINSZ, SUB, PDCP_MAC_I_LEN, VSEQOUTSZ, 4,
+			      IMMED2);
+		SEQFIFOSTORE(p, MSG, 0, 0, VLF | CONT);
+		ALG_OPERATION(p, OP_ALG_ALGSEL_SNOW_F8,
+			      OP_ALG_AAI_F8,
+			      OP_ALG_AS_INITFINAL, ICV_CHECK_DISABLE,
+			      dir == OP_TYPE_ENCAP_PROTOCOL ?
+					DIR_ENC : DIR_DEC);
+		break;
+
+	case PDCP_CIPHER_TYPE_AES:
+		MOVE(p, MATH2, 0, CONTEXT1, 0x10, 0x10, WAITCOMP | IMMED);
+
+		if (rta_sec_era > RTA_SEC_ERA_2) {
+			MATHB(p, SEQINSZ, SUB, ZERO, VSEQINSZ, 4, 0);
+		} else {
+			MATHB(p, SEQINSZ, SUB, ONE, MATH1, 4, 0);
+			MATHB(p, MATH1, ADD, ONE, VSEQINSZ, 4, 0);
+		}
+
+		if (dir == OP_TYPE_ENCAP_PROTOCOL)
+			MATHB(p, SEQINSZ, ADD, PDCP_MAC_I_LEN, VSEQOUTSZ, 4,
+			      IMMED2);
+		else
+			MATHB(p, SEQINSZ, SUB, PDCP_MAC_I_LEN, VSEQOUTSZ, 4,
+			      IMMED2);
+
+		SEQFIFOSTORE(p, MSG, 0, 0, VLF | CONT);
+		ALG_OPERATION(p, OP_ALG_ALGSEL_AES,
+			      OP_ALG_AAI_CTR,
+			      OP_ALG_AS_INITFINAL,
+			      ICV_CHECK_DISABLE,
+			      dir == OP_TYPE_ENCAP_PROTOCOL ?
+					DIR_ENC : DIR_DEC);
+		break;
+
+	case PDCP_CIPHER_TYPE_ZUC:
+		if (rta_sec_era < RTA_SEC_ERA_5) {
+			pr_err("Invalid era for selected algorithm\n");
+			return -ENOTSUP;
+		}
+
+		MOVE(p, MATH2, 0, CONTEXT1, 0, 0x08, IMMED);
+		MOVE(p, MATH2, 0, CONTEXT1, 0x08, 0x08, WAITCOMP | IMMED);
+		MATHB(p, SEQINSZ, SUB, ZERO, VSEQINSZ, 4, 0);
+		if (dir == OP_TYPE_ENCAP_PROTOCOL)
+			MATHB(p, SEQINSZ, ADD, PDCP_MAC_I_LEN, VSEQOUTSZ, 4,
+			      IMMED2);
+		else
+			MATHB(p, SEQINSZ, SUB, PDCP_MAC_I_LEN, VSEQOUTSZ, 4,
+			      IMMED2);
+
+		SEQFIFOSTORE(p, MSG, 0, 0, VLF | CONT);
+		ALG_OPERATION(p, OP_ALG_ALGSEL_ZUCE,
+			      OP_ALG_AAI_F8,
+			      OP_ALG_AS_INITFINAL,
+			      ICV_CHECK_DISABLE,
+			      dir == OP_TYPE_ENCAP_PROTOCOL ?
+					DIR_ENC : DIR_DEC);
+		break;
+
+	default:
+		pr_err("%s: Invalid encrypt algorithm selected: %d\n",
+		       "pdcp_insert_cplane_enc_only_op", cipherdata->algtype);
+		return -EINVAL;
+	}
+
+	if (dir == OP_TYPE_ENCAP_PROTOCOL) {
+		SEQFIFOLOAD(p, MSG1, 0, VLF);
+		FIFOLOAD(p, MSG1, PDCP_NULL_INT_MAC_I_VAL, 4,
+			 LAST1 | FLUSH1 | IMMED);
+	} else {
+		SEQFIFOLOAD(p, MSG1, 0, VLF | LAST1 | FLUSH1);
+		MOVE(p, OFIFO, 0, MATH1, 4, PDCP_MAC_I_LEN, WAITCOMP | IMMED);
+		MATHB(p, MATH1, XOR, PDCP_NULL_INT_MAC_I_VAL, NONE, 4, IMMED2);
+		JUMP(p, PDCP_NULL_INT_ICV_CHECK_FAILED_STATUS,
+		     HALT_STATUS, ALL_FALSE, MATH_Z);
+	}
+
+	return 0;
+}
+
+static inline int pdcp_insert_cplane_acc_op(struct program *p,
+		struct alginfo *cipherdata,
+		struct alginfo *authdata,
+		unsigned dir,
+		unsigned char era_2_hfn_override __maybe_unused)
+{
+	/* Insert Auth Key */
+	KEY(p, KEY2, authdata->key_enc_flags, authdata->key, authdata->keylen,
+	    INLINE_KEY(authdata));
+
+	/* Insert Cipher Key */
+	KEY(p, KEY1, cipherdata->key_enc_flags, cipherdata->key,
+	    cipherdata->keylen, INLINE_KEY(cipherdata));
+	PROTOCOL(p, dir, OP_PCLID_LTE_PDCP_CTRL, (uint16_t)cipherdata->algtype);
+
+	return 0;
+}
+
+static inline int pdcp_insert_cplane_snow_aes_op(struct program *p,
+		struct alginfo *cipherdata,
+		struct alginfo *authdata,
+		unsigned dir,
+		unsigned char era_2_sw_hfn_override)
+{
+	LABEL(back_to_sd_offset);
+	LABEL(end_desc);
+	LABEL(local_offset);
+	LABEL(jump_to_beginning);
+	LABEL(fifo_load_mac_i_offset);
+	REFERENCE(seqin_ptr_read);
+	REFERENCE(seqin_ptr_write);
+	REFERENCE(seq_out_read);
+	REFERENCE(jump_back_to_sd_cmd);
+	REFERENCE(move_mac_i_to_desc_buf);
+
+	if (rta_sec_era >= RTA_SEC_ERA_8) {
+		KEY(p, KEY1, cipherdata->key_enc_flags, cipherdata->key,
+				cipherdata->keylen, INLINE_KEY(cipherdata));
+		KEY(p, KEY2, authdata->key_enc_flags, authdata->key,
+				authdata->keylen, INLINE_KEY(authdata));
+
+		PROTOCOL(p, dir, OP_PCLID_LTE_PDCP_CTRL_MIXED,
+			 ((uint16_t)cipherdata->algtype << 8) |
+			 (uint16_t)authdata->algtype);
+
+		return 0;
+	}
+
+	SEQLOAD(p, MATH0, 7, 1, 0);
+	JUMP(p, 1, LOCAL_JUMP, ALL_TRUE, CALM);
+	MATHB(p, MATH0, AND, PDCP_C_PLANE_SN_MASK, MATH1, 8, IFB | IMMED2);
+	MATHB(p, MATH1, SHLD, MATH1, MATH1, 8, 0);
+	MOVE(p, DESCBUF, 4, MATH2, 0, 0x08, WAITCOMP | IMMED);
+	MATHB(p, MATH1, OR, MATH2, MATH2, 8, 0);
+	SEQSTORE(p, MATH0, 7, 1, 0);
+	if (dir == OP_TYPE_ENCAP_PROTOCOL) {
+		if (rta_sec_era > RTA_SEC_ERA_2 ||
+		    (rta_sec_era == RTA_SEC_ERA_2 &&
+				   era_2_sw_hfn_override == 0)) {
+			SEQINPTR(p, 0, 1, RTO);
+		} else {
+			SEQINPTR(p, 0, 5, RTO);
+			SEQFIFOLOAD(p, SKIP, 4, 0);
+		}
+		KEY(p, KEY1, authdata->key_enc_flags, authdata->key,
+		    authdata->keylen, INLINE_KEY(authdata));
+		MOVE(p, MATH2, 0, IFIFOAB1, 0, 0x08, IMMED);
+
+		if (rta_sec_era > RTA_SEC_ERA_2) {
+			MATHB(p, SEQINSZ, SUB, ZERO, VSEQINSZ, 4, 0);
+			MATHB(p, SEQINSZ, SUB, ZERO, MATH1, 4, 0);
+			MATHB(p, VSEQINSZ, ADD, PDCP_MAC_I_LEN - 1, VSEQOUTSZ,
+			      4, IMMED2);
+		} else {
+			MATHB(p, SEQINSZ, SUB, MATH3, VSEQINSZ, 4, 0);
+			MATHB(p, VSEQINSZ, ADD, PDCP_MAC_I_LEN - 1, VSEQOUTSZ,
+			      4, IMMED2);
+			/*
+			 * Note: Although the calculations below might seem a
+			 * little off, the logic is the following:
+			 *
+			 * - SEQ IN PTR RTO below needs the full length of the
+			 *   frame; in case of P4080_REV_2_HFN_OV_WORKAROUND,
+			 *   this means the length of the frame to be processed
+			 *   + 4 bytes (the HFN override flag and value).
+			 *   The length of the frame to be processed minus 1
+			 *   byte is in the VSIL register (because
+			 *   VSIL = SIL + 3, due to 1 byte, the header being
+			 *   already written by the SEQ STORE above). So for
+			 *   calculating the length to use in RTO, I add one
+			 *   to the VSIL value in order to obtain the total
+			 *   frame length. This helps in case of P4080 which
+			 *   can have the value 0 as an operand in a MATH
+			 *   command only as SRC1 When the HFN override
+			 *   workaround is not enabled, the length of the
+			 *   frame is given by the SIL register; the
+			 *   calculation is similar to the one in the SEC 4.2
+			 *   and SEC 5.3 cases.
+			 */
+			if (era_2_sw_hfn_override)
+				MATHB(p, VSEQOUTSZ, ADD, ONE, MATH1, 4,
+				      0);
+			else
+				MATHB(p, SEQINSZ, ADD, MATH3, MATH1, 4,
+				      0);
+		}
+		/*
+		 * Placeholder for filling the length in
+		 * SEQIN PTR RTO below
+		 */
+		seqin_ptr_read = MOVE(p, DESCBUF, 0, MATH1, 0, 6, IMMED);
+		seqin_ptr_write = MOVE(p, MATH1, 0, DESCBUF, 0, 8,
+				       WAITCOMP | IMMED);
+		ALG_OPERATION(p, OP_ALG_ALGSEL_AES,
+			      OP_ALG_AAI_CMAC,
+			      OP_ALG_AS_INITFINAL,
+			      ICV_CHECK_DISABLE,
+			      DIR_DEC);
+		SEQFIFOLOAD(p, MSG1, 0, VLF | LAST1 | FLUSH1);
+		MOVE(p, CONTEXT1, 0, MATH3, 0, 4, WAITCOMP | IMMED);
+		if (rta_sec_era <= RTA_SEC_ERA_3)
+			LOAD(p, CLRW_CLR_C1KEY |
+			     CLRW_CLR_C1CTX |
+			     CLRW_CLR_C1ICV |
+			     CLRW_CLR_C1DATAS |
+			     CLRW_CLR_C1MODE,
+			     CLRW, 0, 4, IMMED);
+		else
+			LOAD(p, CLRW_RESET_CLS1_CHA |
+			     CLRW_CLR_C1KEY |
+			     CLRW_CLR_C1CTX |
+			     CLRW_CLR_C1ICV |
+			     CLRW_CLR_C1DATAS |
+			     CLRW_CLR_C1MODE,
+			     CLRW, 0, 4, IMMED);
+
+		if (rta_sec_era <= RTA_SEC_ERA_3)
+			LOAD(p, CCTRL_RESET_CHA_ALL, CCTRL, 0, 4, IMMED);
+
+		KEY(p, KEY1, cipherdata->key_enc_flags, cipherdata->key,
+		    cipherdata->keylen, INLINE_KEY(cipherdata));
+		SET_LABEL(p, local_offset);
+		MOVE(p, MATH2, 0, CONTEXT1, 0, 8, IMMED);
+		SEQINPTR(p, 0, 0, RTO);
+
+		if (rta_sec_era == RTA_SEC_ERA_2 && era_2_sw_hfn_override) {
+			SEQFIFOLOAD(p, SKIP, 5, 0);
+			MATHB(p, SEQINSZ, ADD, ONE, SEQINSZ, 4, 0);
+		}
+
+		MATHB(p, SEQINSZ, SUB, ONE, VSEQINSZ, 4, 0);
+		ALG_OPERATION(p, OP_ALG_ALGSEL_SNOW_F8,
+			      OP_ALG_AAI_F8,
+			      OP_ALG_AS_INITFINAL,
+			      ICV_CHECK_DISABLE,
+			      DIR_ENC);
+		SEQFIFOSTORE(p, MSG, 0, 0, VLF);
+
+		if (rta_sec_era > RTA_SEC_ERA_2 ||
+		    (rta_sec_era == RTA_SEC_ERA_2 &&
+				   era_2_sw_hfn_override == 0))
+			SEQFIFOLOAD(p, SKIP, 1, 0);
+
+		SEQFIFOLOAD(p, MSG1, 0, VLF);
+		MOVE(p, MATH3, 0, IFIFOAB1, 0, 4, LAST1 | FLUSH1 | IMMED);
+		PATCH_MOVE(p, seqin_ptr_read, local_offset);
+		PATCH_MOVE(p, seqin_ptr_write, local_offset);
+	} else {
+		MOVE(p, MATH2, 0, CONTEXT1, 0, 8, IMMED);
+
+		if (rta_sec_era >= RTA_SEC_ERA_5)
+			MOVE(p, CONTEXT1, 0, CONTEXT2, 0, 8, IMMED);
+
+		if (rta_sec_era > RTA_SEC_ERA_2)
+			MATHB(p, SEQINSZ, SUB, ZERO, VSEQINSZ, 4, 0);
+		else
+			MATHB(p, SEQINSZ, SUB, MATH3, VSEQINSZ, 4, 0);
+
+		MATHB(p, SEQINSZ, SUB, PDCP_MAC_I_LEN, VSEQOUTSZ, 4, IMMED2);
+/*
+ * TODO: To be changed when proper support is added in RTA (can't load a
+ * command that is also written by RTA (or patch it for that matter).
+ * Change when proper RTA support is added.
+ */
+		if (p->ps)
+			WORD(p, 0x168B0004);
+		else
+			WORD(p, 0x16880404);
+
+		jump_back_to_sd_cmd = JUMP(p, 0, LOCAL_JUMP, ALL_TRUE, 0);
+		/*
+		 * Placeholder for command reading  the SEQ OUT command in
+		 * JD. Done for rereading the decrypted data and performing
+		 * the integrity check
+		 */
+/*
+ * TODO: RTA currently doesn't support patching of length of a MOVE command
+ * Thus, it is inserted as a raw word, as per PS setting.
+ */
+		if (p->ps)
+			seq_out_read = MOVE(p, DESCBUF, 0, MATH1, 0, 20,
+					    WAITCOMP | IMMED);
+		else
+			seq_out_read = MOVE(p, DESCBUF, 0, MATH1, 0, 16,
+					    WAITCOMP | IMMED);
+
+		MATHB(p, MATH1, XOR, CMD_SEQ_IN_PTR ^ CMD_SEQ_OUT_PTR, MATH1, 4,
+		      IMMED2);
+		/* Placeholder for overwriting the SEQ IN  with SEQ OUT */
+/*
+ * TODO: RTA currently doesn't support patching of length of a MOVE command
+ * Thus, it is inserted as a raw word, as per PS setting.
+ */
+		if (p->ps)
+			MOVE(p, MATH1, 0, DESCBUF, 0, 24, IMMED);
+		else
+			MOVE(p, MATH1, 0, DESCBUF, 0, 20, IMMED);
+
+		KEY(p, KEY1, cipherdata->key_enc_flags, cipherdata->key,
+		    cipherdata->keylen, INLINE_KEY(cipherdata));
+
+		if (rta_sec_era >= RTA_SEC_ERA_4)
+			MOVE(p, CONTEXT1, 0, CONTEXT2, 0, 8, IMMED);
+		else
+			MOVE(p, CONTEXT1, 0, MATH3, 0, 8, IMMED);
+
+		ALG_OPERATION(p, OP_ALG_ALGSEL_SNOW_F8,
+			      OP_ALG_AAI_F8,
+			      OP_ALG_AS_INITFINAL,
+			      ICV_CHECK_DISABLE,
+			      DIR_DEC);
+		SEQFIFOSTORE(p, MSG, 0, 0, VLF | CONT);
+		SEQFIFOLOAD(p, MSG1, 0, VLF | LAST1 | FLUSH1);
+
+		if (rta_sec_era <= RTA_SEC_ERA_3)
+			move_mac_i_to_desc_buf = MOVE(p, OFIFO, 0, DESCBUF, 0,
+						      4, WAITCOMP | IMMED);
+		else
+			MOVE(p, OFIFO, 0, MATH3, 0, 4, IMMED);
+
+		if (rta_sec_era <= RTA_SEC_ERA_3)
+			LOAD(p, CCTRL_RESET_CHA_ALL, CCTRL, 0, 4, IMMED);
+		else
+			LOAD(p, CLRW_RESET_CLS1_CHA |
+			     CLRW_CLR_C1KEY |
+			     CLRW_CLR_C1CTX |
+			     CLRW_CLR_C1ICV |
+			     CLRW_CLR_C1DATAS |
+			     CLRW_CLR_C1MODE,
+			     CLRW, 0, 4, IMMED);
+
+		KEY(p, KEY1, authdata->key_enc_flags, authdata->key,
+		    authdata->keylen, INLINE_KEY(authdata));
+		/*
+		 * Placeholder for jump in SD for executing the new SEQ IN PTR
+		 * command (which is actually the old SEQ OUT PTR command
+		 * copied over from JD.
+		 */
+		SET_LABEL(p, jump_to_beginning);
+		JUMP(p, 1 - jump_to_beginning, LOCAL_JUMP, ALL_TRUE, 0);
+		SET_LABEL(p, back_to_sd_offset);
+		ALG_OPERATION(p, OP_ALG_ALGSEL_AES,
+			      OP_ALG_AAI_CMAC,
+			      OP_ALG_AS_INITFINAL,
+			      ICV_CHECK_ENABLE,
+			      DIR_DEC);
+
+		/* Read the # of bytes written in the output buffer + 1 (HDR) */
+		MATHB(p, VSEQOUTSZ, ADD, ONE, VSEQINSZ, 4, 0);
+
+		if (rta_sec_era <= RTA_SEC_ERA_3)
+			MOVE(p, MATH3, 0, IFIFOAB1, 0, 8, IMMED);
+		else
+			MOVE(p, CONTEXT2, 0, IFIFOAB1, 0, 8, IMMED);
+
+		if (rta_sec_era == RTA_SEC_ERA_2 && era_2_sw_hfn_override)
+			SEQFIFOLOAD(p, SKIP, 4, 0);
+
+		SEQFIFOLOAD(p, MSG1, 0, VLF | LAST1 | FLUSH1);
+
+		if (rta_sec_era >= RTA_SEC_ERA_4) {
+			LOAD(p, NFIFOENTRY_STYPE_ALTSOURCE |
+			     NFIFOENTRY_DEST_CLASS1 |
+			     NFIFOENTRY_DTYPE_ICV |
+			     NFIFOENTRY_LC1 |
+			     NFIFOENTRY_FC1 | 4, NFIFO_SZL, 0, 4, IMMED);
+			MOVE(p, MATH3, 0, ALTSOURCE, 0, 4, IMMED);
+		} else {
+			SET_LABEL(p, fifo_load_mac_i_offset);
+			FIFOLOAD(p, ICV1, fifo_load_mac_i_offset, 4,
+				 LAST1 | FLUSH1 | IMMED);
+		}
+
+		SET_LABEL(p, end_desc);
+
+		if (!p->ps) {
+			PATCH_MOVE(p, seq_out_read, end_desc + 1);
+			PATCH_JUMP(p, jump_back_to_sd_cmd,
+				   back_to_sd_offset + jump_back_to_sd_cmd - 5);
+
+			if (rta_sec_era <= RTA_SEC_ERA_3)
+				PATCH_MOVE(p, move_mac_i_to_desc_buf,
+					   fifo_load_mac_i_offset + 1);
+		} else {
+			PATCH_MOVE(p, seq_out_read, end_desc + 2);
+			PATCH_JUMP(p, jump_back_to_sd_cmd,
+				   back_to_sd_offset + jump_back_to_sd_cmd - 5);
+
+			if (rta_sec_era <= RTA_SEC_ERA_3)
+				PATCH_MOVE(p, move_mac_i_to_desc_buf,
+					   fifo_load_mac_i_offset + 1);
+		}
+	}
+
+	return 0;
+}
+
+static inline int pdcp_insert_cplane_aes_snow_op(struct program *p,
+		struct alginfo *cipherdata,
+		struct alginfo *authdata,
+		unsigned dir,
+		unsigned char era_2_sw_hfn_override __maybe_unused)
+{
+	KEY(p, KEY1, cipherdata->key_enc_flags, cipherdata->key,
+	    cipherdata->keylen, INLINE_KEY(cipherdata));
+	KEY(p, KEY2, authdata->key_enc_flags, authdata->key, authdata->keylen,
+	    INLINE_KEY(authdata));
+
+	if (rta_sec_era >= RTA_SEC_ERA_8) {
+		PROTOCOL(p, dir, OP_PCLID_LTE_PDCP_CTRL_MIXED,
+			 ((uint16_t)cipherdata->algtype << 8) |
+			 (uint16_t)authdata->algtype);
+
+		return 0;
+	}
+
+	if (dir == OP_TYPE_ENCAP_PROTOCOL)
+		MATHB(p, SEQINSZ, SUB, ONE, VSEQINSZ, 4, 0);
+
+	SEQLOAD(p, MATH0, 7, 1, 0);
+	JUMP(p, 1, LOCAL_JUMP, ALL_TRUE, CALM);
+	MOVE(p, MATH0, 7, IFIFOAB2, 0, 1, IMMED);
+	MATHB(p, MATH0, AND, PDCP_C_PLANE_SN_MASK, MATH1, 8, IFB | IMMED2);
+	SEQSTORE(p, MATH0, 7, 1, 0);
+	MATHB(p, MATH1, SHLD, MATH1, MATH1, 8, 0);
+	MOVE(p, DESCBUF, 4, MATH2, 0, 8, WAITCOMP | IMMED);
+	MATHB(p, MATH1, OR, MATH2, MATH1, 8, 0);
+	MOVE(p, MATH1, 0, CONTEXT1, 16, 8, IMMED);
+	MOVE(p, MATH1, 0, CONTEXT2, 0, 4, IMMED);
+	MATHB(p, MATH1, AND, lower_32_bits(PDCP_BEARER_MASK), MATH2, 4, IMMED2);
+	MATHB(p, MATH1, AND, upper_32_bits(PDCP_DIR_MASK), MATH3, 4, IMMED2);
+	MATHB(p, MATH3, SHLD, MATH3, MATH3, 8, 0);
+	MOVE(p, MATH2, 4, OFIFO, 0, 12, IMMED);
+	MOVE(p, OFIFO, 0, CONTEXT2, 4, 12, IMMED);
+	if (dir == OP_TYPE_ENCAP_PROTOCOL) {
+		MATHB(p, SEQINSZ, ADD, PDCP_MAC_I_LEN, VSEQOUTSZ, 4, IMMED2);
+	} else {
+		MATHB(p, SEQINSZ, SUB, PDCP_MAC_I_LEN, MATH1, 4, IMMED2);
+
+		MATHB(p, ZERO, ADD, MATH1, VSEQOUTSZ, 4, 0);
+		MATHB(p, ZERO, ADD, MATH1, VSEQINSZ, 4, 0);
+	}
+
+	if (dir == OP_TYPE_ENCAP_PROTOCOL)
+		SEQFIFOSTORE(p, MSG, 0, 0, VLF);
+	else
+		SEQFIFOSTORE(p, MSG, 0, 0, VLF | CONT);
+
+	ALG_OPERATION(p, OP_ALG_ALGSEL_SNOW_F9,
+		      OP_ALG_AAI_F9,
+		      OP_ALG_AS_INITFINAL,
+		      dir == OP_TYPE_ENCAP_PROTOCOL ?
+			     ICV_CHECK_DISABLE : ICV_CHECK_ENABLE,
+		      DIR_DEC);
+	ALG_OPERATION(p, OP_ALG_ALGSEL_AES,
+		      OP_ALG_AAI_CTR,
+		      OP_ALG_AS_INITFINAL,
+		      ICV_CHECK_DISABLE,
+		      dir == OP_TYPE_ENCAP_PROTOCOL ? DIR_ENC : DIR_DEC);
+
+	if (dir == OP_TYPE_ENCAP_PROTOCOL) {
+		SEQFIFOLOAD(p, MSGINSNOOP, 0, VLF | LAST2);
+		MOVE(p, CONTEXT2, 0, IFIFOAB1, 0, 4, LAST1 | FLUSH1 | IMMED);
+	} else {
+		SEQFIFOLOAD(p, MSGOUTSNOOP, 0, VLF | LAST2);
+		SEQFIFOLOAD(p, MSG1, 4, LAST1 | FLUSH1);
+		JUMP(p, 1, LOCAL_JUMP, ALL_TRUE, CLASS1 | NOP | NIFP);
+
+		if (rta_sec_era >= RTA_SEC_ERA_6)
+			LOAD(p, 0, DCTRL, 0, LDLEN_RST_CHA_OFIFO_PTR, IMMED);
+
+		MOVE(p, OFIFO, 0, MATH0, 0, 4, WAITCOMP | IMMED);
+
+		NFIFOADD(p, IFIFO, ICV2, 4, LAST2);
+
+		if (rta_sec_era <= RTA_SEC_ERA_2) {
+			/* Shut off automatic Info FIFO entries */
+			LOAD(p, 0, DCTRL, LDOFF_DISABLE_AUTO_NFIFO, 0, IMMED);
+			MOVE(p, MATH0, 0, IFIFOAB2, 0, 4, WAITCOMP | IMMED);
+		} else {
+			MOVE(p, MATH0, 0, IFIFO, 0, 4, WAITCOMP | IMMED);
+		}
+	}
+
+	return 0;
+}
+
+static inline int pdcp_insert_cplane_snow_zuc_op(struct program *p,
+		struct alginfo *cipherdata,
+		struct alginfo *authdata,
+		unsigned dir,
+		unsigned char era_2_sw_hfn_override __maybe_unused)
+{
+	LABEL(keyjump);
+	REFERENCE(pkeyjump);
+
+	if (rta_sec_era < RTA_SEC_ERA_5) {
+		pr_err("Invalid era for selected algorithm\n");
+		return -ENOTSUP;
+	}
+
+	pkeyjump = JUMP(p, keyjump, LOCAL_JUMP, ALL_TRUE, SHRD | SELF | BOTH);
+	KEY(p, KEY1, cipherdata->key_enc_flags, cipherdata->key,
+	    cipherdata->keylen, INLINE_KEY(cipherdata));
+	KEY(p, KEY2, authdata->key_enc_flags, authdata->key, authdata->keylen,
+	    INLINE_KEY(authdata));
+
+	SET_LABEL(p, keyjump);
+
+	if (rta_sec_era >= RTA_SEC_ERA_8) {
+		PROTOCOL(p, dir, OP_PCLID_LTE_PDCP_CTRL_MIXED,
+			 ((uint16_t)cipherdata->algtype << 8) |
+			 (uint16_t)authdata->algtype);
+		return 0;
+	}
+
+	SEQLOAD(p, MATH0, 7, 1, 0);
+	JUMP(p, 1, LOCAL_JUMP, ALL_TRUE, CALM);
+	MOVE(p, MATH0, 7, IFIFOAB2, 0, 1, IMMED);
+	MATHB(p, MATH0, AND, PDCP_C_PLANE_SN_MASK, MATH1, 8, IFB | IMMED2);
+	MATHB(p, MATH1, SHLD, MATH1, MATH1, 8, 0);
+	MOVE(p, DESCBUF, 4, MATH2, 0, 8, WAITCOMP | IMMED);
+	MATHB(p, MATH1, OR, MATH2, MATH2, 8, 0);
+	MOVE(p, MATH2, 0, CONTEXT1, 0, 8, IMMED);
+	MOVE(p, MATH2, 0, CONTEXT2, 0, 8, WAITCOMP | IMMED);
+
+	if (dir == OP_TYPE_ENCAP_PROTOCOL)
+		MATHB(p, SEQINSZ, ADD, PDCP_MAC_I_LEN, VSEQOUTSZ, 4, IMMED2);
+	else
+		MATHB(p, SEQINSZ, SUB, PDCP_MAC_I_LEN, VSEQOUTSZ, 4, IMMED2);
+
+	MATHB(p, SEQINSZ, SUB, ZERO, VSEQINSZ, 4, 0);
+	SEQSTORE(p, MATH0, 7, 1, 0);
+
+	if (dir == OP_TYPE_ENCAP_PROTOCOL) {
+		SEQFIFOSTORE(p, MSG, 0, 0, VLF);
+		SEQFIFOLOAD(p, MSGINSNOOP, 0, VLF | LAST2);
+	} else {
+		SEQFIFOSTORE(p, MSG, 0, 0, VLF | CONT);
+		SEQFIFOLOAD(p, MSGOUTSNOOP, 0, VLF | LAST1 | FLUSH1);
+	}
+
+	ALG_OPERATION(p, OP_ALG_ALGSEL_ZUCA,
+		      OP_ALG_AAI_F9,
+		      OP_ALG_AS_INITFINAL,
+		      dir == OP_TYPE_ENCAP_PROTOCOL ?
+			     ICV_CHECK_DISABLE : ICV_CHECK_ENABLE,
+		      DIR_ENC);
+
+	ALG_OPERATION(p, OP_ALG_ALGSEL_SNOW_F8,
+		      OP_ALG_AAI_F8,
+		      OP_ALG_AS_INITFINAL,
+		      ICV_CHECK_DISABLE,
+		      dir == OP_TYPE_ENCAP_PROTOCOL ? DIR_ENC : DIR_DEC);
+	if (dir == OP_TYPE_ENCAP_PROTOCOL) {
+		MOVE(p, CONTEXT2, 0, IFIFOAB1, 0, 4, LAST1 | FLUSH1 | IMMED);
+	} else {
+		/* Save ICV */
+		MOVE(p, OFIFO, 0, MATH0, 0, 4, IMMED);
+		LOAD(p, NFIFOENTRY_STYPE_ALTSOURCE |
+		     NFIFOENTRY_DEST_CLASS2 |
+		     NFIFOENTRY_DTYPE_ICV |
+		     NFIFOENTRY_LC2 | 4, NFIFO_SZL, 0, 4, IMMED);
+		MOVE(p, MATH0, 0, ALTSOURCE, 0, 4, WAITCOMP | IMMED);
+	}
+
+	/* Reset ZUCA mode and done interrupt */
+	LOAD(p, CLRW_CLR_C2MODE, CLRW, 0, 4, IMMED);
+	LOAD(p, CIRQ_ZADI, ICTRL, 0, 4, IMMED);
+
+	PATCH_JUMP(p, pkeyjump, keyjump);
+	return 0;
+}
+
+static inline int pdcp_insert_cplane_aes_zuc_op(struct program *p,
+		struct alginfo *cipherdata,
+		struct alginfo *authdata,
+		unsigned dir,
+		unsigned char era_2_sw_hfn_override __maybe_unused)
+{
+	LABEL(keyjump);
+	REFERENCE(pkeyjump);
+
+	if (rta_sec_era < RTA_SEC_ERA_5) {
+		pr_err("Invalid era for selected algorithm\n");
+		return -ENOTSUP;
+	}
+
+	pkeyjump = JUMP(p, keyjump, LOCAL_JUMP, ALL_TRUE, SHRD | SELF | BOTH);
+	KEY(p, KEY1, cipherdata->key_enc_flags, cipherdata->key,
+	    cipherdata->keylen, INLINE_KEY(cipherdata));
+	KEY(p, KEY2, authdata->key_enc_flags, authdata->key, authdata->keylen,
+	    INLINE_KEY(authdata));
+
+	if (rta_sec_era >= RTA_SEC_ERA_8) {
+		PROTOCOL(p, dir, OP_PCLID_LTE_PDCP_CTRL_MIXED,
+			 ((uint16_t)cipherdata->algtype << 8) |
+			 (uint16_t)authdata->algtype);
+
+		return 0;
+	}
+
+	SET_LABEL(p, keyjump);
+	SEQLOAD(p, MATH0, 7, 1, 0);
+	JUMP(p, 1, LOCAL_JUMP, ALL_TRUE, CALM);
+	MOVE(p, MATH0, 7, IFIFOAB2, 0, 1, IMMED);
+	MATHB(p, MATH0, AND, PDCP_C_PLANE_SN_MASK, MATH1, 8, IFB | IMMED2);
+
+	MATHB(p, MATH1, SHLD, MATH1, MATH1, 8, 0);
+	MOVE(p, DESCBUF, 4, MATH2, 0, 8, WAITCOMP | IMMED);
+	MATHB(p, MATH1, OR, MATH2, MATH2, 8, 0);
+	MOVE(p, MATH2, 0, CONTEXT1, 16, 8, IMMED);
+	MOVE(p, MATH2, 0, CONTEXT2, 0, 8, WAITCOMP | IMMED);
+
+	if (dir == OP_TYPE_ENCAP_PROTOCOL)
+		MATHB(p, SEQINSZ, ADD, PDCP_MAC_I_LEN, VSEQOUTSZ, 4, IMMED2);
+	else
+		MATHB(p, SEQINSZ, SUB, PDCP_MAC_I_LEN, VSEQOUTSZ, 4, IMMED2);
+
+	MATHB(p, SEQINSZ, SUB, ZERO, VSEQINSZ, 4, 0);
+	SEQSTORE(p, MATH0, 7, 1, 0);
+
+	if (dir == OP_TYPE_ENCAP_PROTOCOL) {
+		SEQFIFOSTORE(p, MSG, 0, 0, VLF);
+		SEQFIFOLOAD(p, MSGINSNOOP, 0, VLF | LAST2);
+	} else {
+		SEQFIFOSTORE(p, MSG, 0, 0, VLF | CONT);
+		SEQFIFOLOAD(p, MSGOUTSNOOP, 0, VLF | LAST1 | FLUSH1);
+	}
+
+	ALG_OPERATION(p, OP_ALG_ALGSEL_ZUCA,
+		      OP_ALG_AAI_F9,
+		      OP_ALG_AS_INITFINAL,
+		      dir == OP_TYPE_ENCAP_PROTOCOL ?
+			     ICV_CHECK_DISABLE : ICV_CHECK_ENABLE,
+		      DIR_ENC);
+
+	ALG_OPERATION(p, OP_ALG_ALGSEL_AES,
+		      OP_ALG_AAI_CTR,
+		      OP_ALG_AS_INITFINAL,
+		      ICV_CHECK_DISABLE,
+		      dir == OP_TYPE_ENCAP_PROTOCOL ? DIR_ENC : DIR_DEC);
+
+	if (dir == OP_TYPE_ENCAP_PROTOCOL) {
+		MOVE(p, CONTEXT2, 0, IFIFOAB1, 0, 4, LAST1 | FLUSH1 | IMMED);
+	} else {
+		/* Save ICV */
+		MOVE(p, OFIFO, 0, MATH0, 0, 4, IMMED);
+
+		LOAD(p, NFIFOENTRY_STYPE_ALTSOURCE |
+		     NFIFOENTRY_DEST_CLASS2 |
+		     NFIFOENTRY_DTYPE_ICV |
+		     NFIFOENTRY_LC2 | 4, NFIFO_SZL, 0, 4, IMMED);
+		MOVE(p, MATH0, 0, ALTSOURCE, 0, 4, WAITCOMP | IMMED);
+	}
+
+	/* Reset ZUCA mode and done interrupt */
+	LOAD(p, CLRW_CLR_C2MODE, CLRW, 0, 4, IMMED);
+	LOAD(p, CIRQ_ZADI, ICTRL, 0, 4, IMMED);
+
+	PATCH_JUMP(p, pkeyjump, keyjump);
+
+	return 0;
+}
+
+static inline int pdcp_insert_cplane_zuc_snow_op(struct program *p,
+		struct alginfo *cipherdata,
+		struct alginfo *authdata,
+		unsigned dir,
+		unsigned char era_2_sw_hfn_override __maybe_unused)
+{
+	LABEL(keyjump);
+	REFERENCE(pkeyjump);
+
+	if (rta_sec_era < RTA_SEC_ERA_5) {
+		pr_err("Invalid era for selected algorithm\n");
+		return -ENOTSUP;
+	}
+
+	pkeyjump = JUMP(p, keyjump, LOCAL_JUMP, ALL_TRUE, SHRD | SELF | BOTH);
+	KEY(p, KEY1, cipherdata->key_enc_flags, cipherdata->key,
+	    cipherdata->keylen, INLINE_KEY(cipherdata));
+	KEY(p, KEY2, authdata->key_enc_flags, authdata->key, authdata->keylen,
+	    INLINE_KEY(authdata));
+
+	if (rta_sec_era >= RTA_SEC_ERA_8) {
+		PROTOCOL(p, dir, OP_PCLID_LTE_PDCP_CTRL_MIXED,
+			 ((uint16_t)cipherdata->algtype << 8) |
+			 (uint16_t)authdata->algtype);
+
+		return 0;
+	}
+
+	SET_LABEL(p, keyjump);
+	SEQLOAD(p, MATH0, 7, 1, 0);
+	JUMP(p, 1, LOCAL_JUMP, ALL_TRUE, CALM);
+	MOVE(p, MATH0, 7, IFIFOAB2, 0, 1, IMMED);
+	MATHB(p, MATH0, AND, PDCP_C_PLANE_SN_MASK, MATH1, 8, IFB | IMMED2);
+	MATHB(p, MATH1, SHLD, MATH1, MATH1, 8, 0);
+	MOVE(p, DESCBUF, 4, MATH2, 0, 8, WAITCOMP | IMMED);
+	MATHB(p, MATH1, OR, MATH2, MATH1, 8, 0);
+	MOVE(p, MATH1, 0, CONTEXT1, 0, 8, IMMED);
+	MOVE(p, MATH1, 0, CONTEXT2, 0, 4, IMMED);
+	MATHB(p, MATH1, AND, lower_32_bits(PDCP_BEARER_MASK), MATH2, 4, IMMED2);
+	MATHB(p, MATH1, AND, upper_32_bits(PDCP_DIR_MASK), MATH3, 4, IMMED2);
+	MATHB(p, MATH3, SHLD, MATH3, MATH3, 8, 0);
+	MOVE(p, MATH2, 4, OFIFO, 0, 12, IMMED);
+	MOVE(p, OFIFO, 0, CONTEXT2, 4, 12, IMMED);
+
+	if (dir == OP_TYPE_ENCAP_PROTOCOL) {
+		MATHB(p, SEQINSZ, ADD, PDCP_MAC_I_LEN, VSEQOUTSZ, 4, IMMED2);
+		MATHB(p, SEQINSZ, SUB, ZERO, VSEQINSZ, 4, 0);
+	} else {
+		MATHB(p, SEQINSZ, SUB, PDCP_MAC_I_LEN, VSEQOUTSZ, 4, IMMED2);
+		MATHB(p, VSEQOUTSZ, SUB, ZERO, VSEQINSZ, 4, 0);
+	}
+
+	SEQSTORE(p, MATH0, 7, 1, 0);
+
+	if (dir == OP_TYPE_ENCAP_PROTOCOL) {
+		SEQFIFOSTORE(p, MSG, 0, 0, VLF);
+		SEQFIFOLOAD(p, MSGINSNOOP, 0, VLF | LAST2);
+	} else {
+		SEQFIFOSTORE(p, MSG, 0, 0, VLF | CONT);
+		SEQFIFOLOAD(p, MSGOUTSNOOP, 0, VLF | LAST2);
+	}
+
+	ALG_OPERATION(p, OP_ALG_ALGSEL_SNOW_F9,
+		      OP_ALG_AAI_F9,
+		      OP_ALG_AS_INITFINAL,
+		      dir == OP_TYPE_ENCAP_PROTOCOL ?
+			     ICV_CHECK_DISABLE : ICV_CHECK_ENABLE,
+		      DIR_DEC);
+
+	ALG_OPERATION(p, OP_ALG_ALGSEL_ZUCE,
+		      OP_ALG_AAI_F8,
+		      OP_ALG_AS_INITFINAL,
+		      ICV_CHECK_DISABLE,
+		      dir == OP_TYPE_ENCAP_PROTOCOL ? DIR_ENC : DIR_DEC);
+
+	if (dir == OP_TYPE_ENCAP_PROTOCOL) {
+		MOVE(p, CONTEXT2, 0, IFIFOAB1, 0, 4, LAST1 | FLUSH1 | IMMED);
+	} else {
+		SEQFIFOLOAD(p, MSG1, 4, LAST1 | FLUSH1);
+		JUMP(p, 1, LOCAL_JUMP, ALL_TRUE, CLASS1 | NOP | NIFP);
+
+		if (rta_sec_era >= RTA_SEC_ERA_6)
+			/*
+			 * For SEC ERA 6, there's a problem with the OFIFO
+			 * pointer, and thus it needs to be reset here before
+			 * moving to M0.
+			 */
+			LOAD(p, 0, DCTRL, 0, LDLEN_RST_CHA_OFIFO_PTR, IMMED);
+
+		/* Put ICV to M0 before sending it to C2 for comparison. */
+		MOVE(p, OFIFO, 0, MATH0, 0, 4, WAITCOMP | IMMED);
+
+		LOAD(p, NFIFOENTRY_STYPE_ALTSOURCE |
+		     NFIFOENTRY_DEST_CLASS2 |
+		     NFIFOENTRY_DTYPE_ICV |
+		     NFIFOENTRY_LC2 | 4, NFIFO_SZL, 0, 4, IMMED);
+		MOVE(p, MATH0, 0, ALTSOURCE, 0, 4, IMMED);
+	}
+
+	PATCH_JUMP(p, pkeyjump, keyjump);
+	return 0;
+}
+
+static inline int pdcp_insert_cplane_zuc_aes_op(struct program *p,
+		struct alginfo *cipherdata,
+		struct alginfo *authdata,
+		unsigned dir,
+		unsigned char era_2_sw_hfn_override __maybe_unused)
+{
+	if (rta_sec_era < RTA_SEC_ERA_5) {
+		pr_err("Invalid era for selected algorithm\n");
+		return -ENOTSUP;
+	}
+
+	if (rta_sec_era >= RTA_SEC_ERA_8) {
+		KEY(p, KEY1, cipherdata->key_enc_flags, cipherdata->key,
+				cipherdata->keylen, INLINE_KEY(cipherdata));
+		KEY(p, KEY2, authdata->key_enc_flags, authdata->key,
+				authdata->keylen, INLINE_KEY(authdata));
+
+		PROTOCOL(p, dir, OP_PCLID_LTE_PDCP_CTRL_MIXED,
+			 ((uint16_t)cipherdata->algtype << 8) |
+			 (uint16_t)authdata->algtype);
+		return 0;
+	}
+
+	SEQLOAD(p, MATH0, 7, 1, 0);
+	JUMP(p, 1, LOCAL_JUMP, ALL_TRUE, CALM);
+	MATHB(p, MATH0, AND, PDCP_C_PLANE_SN_MASK, MATH1, 8, IFB | IMMED2);
+	MATHB(p, MATH1, SHLD, MATH1, MATH1, 8, 0);
+	MOVE(p, DESCBUF, 4, MATH2, 0, 0x08, WAITCOMP | IMMED);
+	MATHB(p, MATH1, OR, MATH2, MATH2, 8, 0);
+	SEQSTORE(p, MATH0, 7, 1, 0);
+	if (dir == OP_TYPE_ENCAP_PROTOCOL) {
+		KEY(p, KEY1, authdata->key_enc_flags, authdata->key,
+		    authdata->keylen, INLINE_KEY(authdata));
+		MOVE(p, MATH2, 0, IFIFOAB1, 0, 0x08, IMMED);
+		MOVE(p, MATH0, 7, IFIFOAB1, 0, 1, IMMED);
+
+		MATHB(p, SEQINSZ, SUB, ZERO, VSEQINSZ, 4, 0);
+		MATHB(p, VSEQINSZ, ADD, PDCP_MAC_I_LEN, VSEQOUTSZ, 4, IMMED2);
+
+		ALG_OPERATION(p, OP_ALG_ALGSEL_AES,
+			      OP_ALG_AAI_CMAC,
+			      OP_ALG_AS_INITFINAL,
+			      ICV_CHECK_DISABLE,
+			      DIR_DEC);
+		SEQFIFOLOAD(p, MSG1, 0, VLF | LAST1 | FLUSH1);
+		MOVE(p, CONTEXT1, 0, MATH3, 0, 4, WAITCOMP | IMMED);
+		LOAD(p, CLRW_RESET_CLS1_CHA |
+		     CLRW_CLR_C1KEY |
+		     CLRW_CLR_C1CTX |
+		     CLRW_CLR_C1ICV |
+		     CLRW_CLR_C1DATAS |
+		     CLRW_CLR_C1MODE,
+		     CLRW, 0, 4, IMMED);
+
+		KEY(p, KEY1, cipherdata->key_enc_flags, cipherdata->key,
+		    cipherdata->keylen, INLINE_KEY(cipherdata));
+
+		MOVE(p, MATH2, 0, CONTEXT1, 0, 8, IMMED);
+		SEQINPTR(p, 0, PDCP_NULL_MAX_FRAME_LEN, RTO);
+
+		ALG_OPERATION(p, OP_ALG_ALGSEL_ZUCE,
+			      OP_ALG_AAI_F8,
+			      OP_ALG_AS_INITFINAL,
+			      ICV_CHECK_DISABLE,
+			      DIR_ENC);
+		SEQFIFOSTORE(p, MSG, 0, 0, VLF);
+
+		SEQFIFOLOAD(p, SKIP, 1, 0);
+
+		SEQFIFOLOAD(p, MSG1, 0, VLF);
+		MOVE(p, MATH3, 0, IFIFOAB1, 0, 4, LAST1 | FLUSH1 | IMMED);
+	} else {
+		MOVE(p, MATH2, 0, CONTEXT1, 0, 8, IMMED);
+
+		MOVE(p, CONTEXT1, 0, CONTEXT2, 0, 8, IMMED);
+
+		MATHB(p, SEQINSZ, SUB, ZERO, VSEQINSZ, 4, 0);
+
+		MATHB(p, SEQINSZ, SUB, PDCP_MAC_I_LEN, VSEQOUTSZ, 4, IMMED2);
+
+		KEY(p, KEY1, cipherdata->key_enc_flags, cipherdata->key,
+		    cipherdata->keylen, INLINE_KEY(cipherdata));
+
+		MOVE(p, CONTEXT1, 0, CONTEXT2, 0, 8, IMMED);
+
+		ALG_OPERATION(p, OP_ALG_ALGSEL_ZUCE,
+			      OP_ALG_AAI_F8,
+			      OP_ALG_AS_INITFINAL,
+			      ICV_CHECK_DISABLE,
+			      DIR_DEC);
+		SEQFIFOSTORE(p, MSG, 0, 0, VLF | CONT);
+		SEQFIFOLOAD(p, MSG1, 0, VLF | LAST1 | FLUSH1);
+
+		MOVE(p, OFIFO, 0, MATH3, 0, 4, IMMED);
+
+		LOAD(p, CLRW_RESET_CLS1_CHA |
+		     CLRW_CLR_C1KEY |
+		     CLRW_CLR_C1CTX |
+		     CLRW_CLR_C1ICV |
+		     CLRW_CLR_C1DATAS |
+		     CLRW_CLR_C1MODE,
+		     CLRW, 0, 4, IMMED);
+
+		KEY(p, KEY1, authdata->key_enc_flags, authdata->key,
+		    authdata->keylen, INLINE_KEY(authdata));
+
+		SEQINPTR(p, 0, 0, SOP);
+
+		ALG_OPERATION(p, OP_ALG_ALGSEL_AES,
+			      OP_ALG_AAI_CMAC,
+			      OP_ALG_AS_INITFINAL,
+			      ICV_CHECK_ENABLE,
+			      DIR_DEC);
+
+		MATHB(p, SEQINSZ, SUB, ZERO, VSEQINSZ, 4, 0);
+
+		MOVE(p, CONTEXT2, 0, IFIFOAB1, 0, 8, IMMED);
+
+		SEQFIFOLOAD(p, MSG1, 0, VLF | LAST1 | FLUSH1);
+
+		LOAD(p, NFIFOENTRY_STYPE_ALTSOURCE |
+		     NFIFOENTRY_DEST_CLASS1 |
+		     NFIFOENTRY_DTYPE_ICV |
+		     NFIFOENTRY_LC1 |
+		     NFIFOENTRY_FC1 | 4, NFIFO_SZL, 0, 4, IMMED);
+		MOVE(p, MATH3, 0, ALTSOURCE, 0, 4, IMMED);
+	}
+
+	return 0;
+}
+
+static inline int pdcp_insert_uplane_15bit_op(struct program *p,
+					      struct alginfo *cipherdata,
+					      unsigned dir)
+{
+	int op;
+	/* Insert Cipher Key */
+	KEY(p, KEY1, cipherdata->key_enc_flags, cipherdata->key,
+	    cipherdata->keylen, INLINE_KEY(cipherdata));
+
+	if (rta_sec_era >= RTA_SEC_ERA_8) {
+		PROTOCOL(p, dir, OP_PCLID_LTE_PDCP_USER,
+			 (uint16_t)cipherdata->algtype);
+		return 0;
+	}
+
+	SEQLOAD(p, MATH0, 6, 2, 0);
+	JUMP(p, 1, LOCAL_JUMP, ALL_TRUE, CALM);
+	MATHB(p, MATH0, AND, PDCP_U_PLANE_15BIT_SN_MASK, MATH1, 8,
+	      IFB | IMMED2);
+	SEQSTORE(p, MATH0, 6, 2, 0);
+	MATHB(p, MATH1, SHLD, MATH1, MATH1, 8, 0);
+	MOVE(p, DESCBUF, 8, MATH2, 0, 8, WAITCOMP | IMMED);
+	MATHB(p, MATH1, OR, MATH2, MATH2, 8, 0);
+
+	MATHB(p, SEQINSZ, SUB, MATH3, VSEQINSZ, 4, 0);
+	MATHB(p, SEQINSZ, SUB, MATH3, VSEQOUTSZ, 4, 0);
+
+	SEQFIFOSTORE(p, MSG, 0, 0, VLF);
+
+	op = dir == OP_TYPE_ENCAP_PROTOCOL ? DIR_ENC : DIR_DEC;
+	switch (cipherdata->algtype) {
+	case PDCP_CIPHER_TYPE_SNOW:
+		MOVE(p, MATH2, 0, CONTEXT1, 0, 8, WAITCOMP | IMMED);
+		ALG_OPERATION(p, OP_ALG_ALGSEL_SNOW_F8,
+			      OP_ALG_AAI_F8,
+			      OP_ALG_AS_INITFINAL,
+			      ICV_CHECK_DISABLE,
+			      op);
+		break;
+
+	case PDCP_CIPHER_TYPE_AES:
+		MOVE(p, MATH2, 0, CONTEXT1, 0x10, 0x10, WAITCOMP | IMMED);
+		ALG_OPERATION(p, OP_ALG_ALGSEL_AES,
+			      OP_ALG_AAI_CTR,
+			      OP_ALG_AS_INITFINAL,
+			      ICV_CHECK_DISABLE,
+			      op);
+		break;
+
+	case PDCP_CIPHER_TYPE_ZUC:
+		if (rta_sec_era < RTA_SEC_ERA_5) {
+			pr_err("Invalid era for selected algorithm\n");
+			return -ENOTSUP;
+		}
+		MOVE(p, MATH2, 0, CONTEXT1, 0, 0x08, IMMED);
+		MOVE(p, MATH2, 0, CONTEXT1, 0x08, 0x08, WAITCOMP | IMMED);
+
+		ALG_OPERATION(p, OP_ALG_ALGSEL_ZUCE,
+			      OP_ALG_AAI_F8,
+			      OP_ALG_AS_INITFINAL,
+			      ICV_CHECK_DISABLE,
+			      op);
+		break;
+
+	default:
+		pr_err("%s: Invalid encrypt algorithm selected: %d\n",
+		       "pdcp_insert_uplane_15bit_op", cipherdata->algtype);
+		return -EINVAL;
+	}
+
+	SEQFIFOLOAD(p, MSG1, 0, VLF | LAST1 | FLUSH1);
+
+	return 0;
+}
+
+/*
+ * Function for inserting the snippet of code responsible for creating
+ * the HFN override code via either DPOVRD or via the input frame.
+ */
+static inline int insert_hfn_ov_op(struct program *p,
+				   uint32_t shift,
+				   enum pdb_type_e pdb_type,
+				   unsigned char era_2_sw_hfn_override)
+{
+	uint32_t imm = 0x80000000;
+	uint16_t hfn_pdb_offset;
+
+	if (rta_sec_era == RTA_SEC_ERA_2 && !era_2_sw_hfn_override)
+		return 0;
+
+	switch (pdb_type) {
+	case PDCP_PDB_TYPE_NO_PDB:
+		/*
+		 * If there is no PDB, then HFN override mechanism does not
+		 * make any sense, thus in this case the function will
+		 * return the pointer to the current position in the
+		 * descriptor buffer
+		 */
+		return 0;
+
+	case PDCP_PDB_TYPE_REDUCED_PDB:
+		hfn_pdb_offset = 4;
+		break;
+
+	case PDCP_PDB_TYPE_FULL_PDB:
+		hfn_pdb_offset = 8;
+		break;
+
+	default:
+		return -EINVAL;
+	}
+
+	if (rta_sec_era > RTA_SEC_ERA_2) {
+		MATHB(p, DPOVRD, AND, imm, NONE, 8, IFB | IMMED2);
+	} else {
+		SEQLOAD(p, MATH0, 4, 4, 0);
+		JUMP(p, 1, LOCAL_JUMP, ALL_TRUE, CALM);
+		MATHB(p, MATH0, AND, imm, NONE, 8, IFB | IMMED2);
+		SEQSTORE(p, MATH0, 4, 4, 0);
+	}
+
+	JUMP(p, 5, LOCAL_JUMP, ALL_TRUE, MATH_Z);
+
+	if (rta_sec_era > RTA_SEC_ERA_2)
+		MATHB(p, DPOVRD, LSHIFT, shift, MATH0, 4, IMMED2);
+	else
+		MATHB(p, MATH0, LSHIFT, shift, MATH0, 4, IMMED2);
+
+	MATHB(p, MATH0, SHLD, MATH0, MATH0, 8, 0);
+	MOVE(p, MATH0, 0, DESCBUF, hfn_pdb_offset, 4, IMMED);
+
+	return 0;
+}
+
+/*
+ * PDCP Control PDB creation function
+ */
+static inline enum pdb_type_e cnstr_pdcp_c_plane_pdb(struct program *p,
+		uint32_t hfn,
+		unsigned char bearer,
+		unsigned char direction,
+		uint32_t hfn_threshold,
+		struct alginfo *cipherdata,
+		struct alginfo *authdata)
+{
+	struct pdcp_pdb pdb;
+	enum pdb_type_e
+		pdb_mask[PDCP_CIPHER_TYPE_INVALID][PDCP_AUTH_TYPE_INVALID] = {
+			{	/* NULL */
+				PDCP_PDB_TYPE_NO_PDB,		/* NULL */
+				PDCP_PDB_TYPE_FULL_PDB,		/* SNOW f9 */
+				PDCP_PDB_TYPE_FULL_PDB,		/* AES CMAC */
+				PDCP_PDB_TYPE_FULL_PDB		/* ZUC-I */
+			},
+			{	/* SNOW f8 */
+				PDCP_PDB_TYPE_FULL_PDB,		/* NULL */
+				PDCP_PDB_TYPE_FULL_PDB,		/* SNOW f9 */
+				PDCP_PDB_TYPE_REDUCED_PDB,	/* AES CMAC */
+				PDCP_PDB_TYPE_REDUCED_PDB	/* ZUC-I */
+			},
+			{	/* AES CTR */
+				PDCP_PDB_TYPE_FULL_PDB,		/* NULL */
+				PDCP_PDB_TYPE_REDUCED_PDB,	/* SNOW f9 */
+				PDCP_PDB_TYPE_FULL_PDB,		/* AES CMAC */
+				PDCP_PDB_TYPE_REDUCED_PDB	/* ZUC-I */
+			},
+			{	/* ZUC-E */
+				PDCP_PDB_TYPE_FULL_PDB,		/* NULL */
+				PDCP_PDB_TYPE_REDUCED_PDB,	/* SNOW f9 */
+				PDCP_PDB_TYPE_REDUCED_PDB,	/* AES CMAC */
+				PDCP_PDB_TYPE_FULL_PDB		/* ZUC-I */
+			},
+	};
+
+	if (rta_sec_era >= RTA_SEC_ERA_8) {
+		memset(&pdb, 0x00, sizeof(struct pdcp_pdb));
+
+		/* This is a HW issue. Bit 2 should be set to zero,
+		 * but it does not work this way. Override here.
+		 */
+		pdb.opt_res.rsvd = 0x00000002;
+
+		/* Copy relevant information from user to PDB */
+		pdb.hfn_res = hfn << PDCP_C_PLANE_PDB_HFN_SHIFT;
+		pdb.bearer_dir_res = (uint32_t)
+				((bearer << PDCP_C_PLANE_PDB_BEARER_SHIFT) |
+				 (direction << PDCP_C_PLANE_PDB_DIR_SHIFT));
+		pdb.hfn_thr_res =
+				hfn_threshold << PDCP_C_PLANE_PDB_HFN_THR_SHIFT;
+
+		/* copy PDB in descriptor*/
+		__rta_out32(p, pdb.opt_res.opt);
+		__rta_out32(p, pdb.hfn_res);
+		__rta_out32(p, pdb.bearer_dir_res);
+		__rta_out32(p, pdb.hfn_thr_res);
+
+		return PDCP_PDB_TYPE_FULL_PDB;
+	}
+
+	switch (pdb_mask[cipherdata->algtype][authdata->algtype]) {
+	case PDCP_PDB_TYPE_NO_PDB:
+		break;
+
+	case PDCP_PDB_TYPE_REDUCED_PDB:
+		__rta_out32(p, (hfn << PDCP_C_PLANE_PDB_HFN_SHIFT));
+		__rta_out32(p,
+			    (uint32_t)((bearer <<
+					PDCP_C_PLANE_PDB_BEARER_SHIFT) |
+					(direction <<
+					 PDCP_C_PLANE_PDB_DIR_SHIFT)));
+		break;
+
+	case PDCP_PDB_TYPE_FULL_PDB:
+		memset(&pdb, 0x00, sizeof(struct pdcp_pdb));
+
+		/* This is a HW issue. Bit 2 should be set to zero,
+		 * but it does not work this way. Override here.
+		 */
+		pdb.opt_res.rsvd = 0x00000002;
+
+		/* Copy relevant information from user to PDB */
+		pdb.hfn_res = hfn << PDCP_C_PLANE_PDB_HFN_SHIFT;
+		pdb.bearer_dir_res = (uint32_t)
+			((bearer << PDCP_C_PLANE_PDB_BEARER_SHIFT) |
+			 (direction << PDCP_C_PLANE_PDB_DIR_SHIFT));
+		pdb.hfn_thr_res =
+			hfn_threshold << PDCP_C_PLANE_PDB_HFN_THR_SHIFT;
+
+		/* copy PDB in descriptor*/
+		__rta_out32(p, pdb.opt_res.opt);
+		__rta_out32(p, pdb.hfn_res);
+		__rta_out32(p, pdb.bearer_dir_res);
+		__rta_out32(p, pdb.hfn_thr_res);
+
+		break;
+
+	default:
+		return PDCP_PDB_TYPE_INVALID;
+	}
+
+	return pdb_mask[cipherdata->algtype][authdata->algtype];
+}
+
+/*
+ * PDCP UPlane PDB creation function
+ */
+static inline int cnstr_pdcp_u_plane_pdb(struct program *p,
+					 enum pdcp_sn_size sn_size,
+					 uint32_t hfn, unsigned short bearer,
+					 unsigned short direction,
+					 uint32_t hfn_threshold)
+{
+	struct pdcp_pdb pdb;
+	/* Read options from user */
+	/* Depending on sequence number length, the HFN and HFN threshold
+	 * have different lengths.
+	 */
+	memset(&pdb, 0x00, sizeof(struct pdcp_pdb));
+
+	switch (sn_size) {
+	case PDCP_SN_SIZE_7:
+		pdb.opt_res.opt |= PDCP_U_PLANE_PDB_OPT_SHORT_SN;
+		pdb.hfn_res = hfn << PDCP_U_PLANE_PDB_SHORT_SN_HFN_SHIFT;
+		pdb.hfn_thr_res =
+			hfn_threshold<<PDCP_U_PLANE_PDB_SHORT_SN_HFN_THR_SHIFT;
+		break;
+
+	case PDCP_SN_SIZE_12:
+		pdb.opt_res.opt &= (uint32_t)(~PDCP_U_PLANE_PDB_OPT_SHORT_SN);
+		pdb.hfn_res = hfn << PDCP_U_PLANE_PDB_LONG_SN_HFN_SHIFT;
+		pdb.hfn_thr_res =
+			hfn_threshold<<PDCP_U_PLANE_PDB_LONG_SN_HFN_THR_SHIFT;
+		break;
+
+	case PDCP_SN_SIZE_15:
+		pdb.opt_res.opt = (uint32_t)(PDCP_U_PLANE_PDB_OPT_15B_SN);
+		pdb.hfn_res = hfn << PDCP_U_PLANE_PDB_15BIT_SN_HFN_SHIFT;
+		pdb.hfn_thr_res =
+			hfn_threshold<<PDCP_U_PLANE_PDB_15BIT_SN_HFN_THR_SHIFT;
+		break;
+
+	default:
+		pr_err("Invalid Sequence Number Size setting in PDB\n");
+		return -EINVAL;
+	}
+
+	pdb.bearer_dir_res = (uint32_t)
+				((bearer << PDCP_U_PLANE_PDB_BEARER_SHIFT) |
+				 (direction << PDCP_U_PLANE_PDB_DIR_SHIFT));
+
+	/* copy PDB in descriptor*/
+	__rta_out32(p, pdb.opt_res.opt);
+	__rta_out32(p, pdb.hfn_res);
+	__rta_out32(p, pdb.bearer_dir_res);
+	__rta_out32(p, pdb.hfn_thr_res);
+
+	return 0;
+}
+/**
+ * cnstr_shdsc_pdcp_c_plane_encap - Function for creating a PDCP Control Plane
+ *                                  encapsulation descriptor.
+ * @descbuf: pointer to buffer for descriptor construction
+ * @ps: if 36/40bit addressing is desired, this parameter must be true
+ * @swap: must be true when core endianness doesn't match SEC endianness
+ * @hfn: starting Hyper Frame Number to be used together with the SN from the
+ *       PDCP frames.
+ * @bearer: radio bearer ID
+ * @direction: the direction of the PDCP frame (UL/DL)
+ * @hfn_threshold: HFN value that once reached triggers a warning from SEC that
+ *                 keys should be renegotiated at the earliest convenience.
+ * @cipherdata: pointer to block cipher transform definitions
+ *              Valid algorithm values are those from cipher_type_pdcp enum.
+ * @authdata: pointer to authentication transform definitions
+ *            Valid algorithm values are those from auth_type_pdcp enum.
+ * @era_2_sw_hfn_override: if software HFN override mechanism is desired for
+ *                         this descriptor. Note: Can only be used for
+ *                         SEC ERA 2.
+ * Return: size of descriptor written in words or negative number on error.
+ *         Once the function returns, the value of this parameter can be used
+ *         for reclaiming the space that wasn't used for the descriptor.
+ *
+ * Note: descbuf must be large enough to contain a full 256 byte long
+ * descriptor; after the function returns, by subtracting the actual number of
+ * bytes used, the user can reuse the remaining buffer space for other purposes.
+ */
+static inline int cnstr_shdsc_pdcp_c_plane_encap(uint32_t *descbuf,
+		bool ps,
+		bool swap,
+		uint32_t hfn,
+		unsigned char bearer,
+		unsigned char direction,
+		uint32_t hfn_threshold,
+		struct alginfo *cipherdata,
+		struct alginfo *authdata,
+		unsigned char era_2_sw_hfn_override)
+{
+	static int
+		(*pdcp_cp_fp[PDCP_CIPHER_TYPE_INVALID][PDCP_AUTH_TYPE_INVALID])
+			(struct program*, struct alginfo *,
+			 struct alginfo *, unsigned,
+			unsigned char __maybe_unused) = {
+		{	/* NULL */
+			pdcp_insert_cplane_null_op,	/* NULL */
+			pdcp_insert_cplane_int_only_op,	/* SNOW f9 */
+			pdcp_insert_cplane_int_only_op,	/* AES CMAC */
+			pdcp_insert_cplane_int_only_op	/* ZUC-I */
+		},
+		{	/* SNOW f8 */
+			pdcp_insert_cplane_enc_only_op,	/* NULL */
+			pdcp_insert_cplane_acc_op,	/* SNOW f9 */
+			pdcp_insert_cplane_snow_aes_op,	/* AES CMAC */
+			pdcp_insert_cplane_snow_zuc_op	/* ZUC-I */
+		},
+		{	/* AES CTR */
+			pdcp_insert_cplane_enc_only_op,	/* NULL */
+			pdcp_insert_cplane_aes_snow_op,	/* SNOW f9 */
+			pdcp_insert_cplane_acc_op,	/* AES CMAC */
+			pdcp_insert_cplane_aes_zuc_op	/* ZUC-I */
+		},
+		{	/* ZUC-E */
+			pdcp_insert_cplane_enc_only_op,	/* NULL */
+			pdcp_insert_cplane_zuc_snow_op,	/* SNOW f9 */
+			pdcp_insert_cplane_zuc_aes_op,	/* AES CMAC */
+			pdcp_insert_cplane_acc_op	/* ZUC-I */
+		},
+	};
+	static enum rta_share_type
+		desc_share[PDCP_CIPHER_TYPE_INVALID][PDCP_AUTH_TYPE_INVALID] = {
+		{	/* NULL */
+			SHR_WAIT,	/* NULL */
+			SHR_ALWAYS,	/* SNOW f9 */
+			SHR_ALWAYS,	/* AES CMAC */
+			SHR_ALWAYS	/* ZUC-I */
+		},
+		{	/* SNOW f8 */
+			SHR_ALWAYS,	/* NULL */
+			SHR_ALWAYS,	/* SNOW f9 */
+			SHR_WAIT,	/* AES CMAC */
+			SHR_WAIT	/* ZUC-I */
+		},
+		{	/* AES CTR */
+			SHR_ALWAYS,	/* NULL */
+			SHR_ALWAYS,	/* SNOW f9 */
+			SHR_ALWAYS,	/* AES CMAC */
+			SHR_WAIT	/* ZUC-I */
+		},
+		{	/* ZUC-E */
+			SHR_ALWAYS,	/* NULL */
+			SHR_WAIT,	/* SNOW f9 */
+			SHR_WAIT,	/* AES CMAC */
+			SHR_ALWAYS	/* ZUC-I */
+		},
+	};
+	enum pdb_type_e pdb_type;
+	struct program prg;
+	struct program *p = &prg;
+	int err;
+	LABEL(pdb_end);
+
+	if (rta_sec_era != RTA_SEC_ERA_2 && era_2_sw_hfn_override) {
+		pr_err("Cannot select SW HFN override for other era than 2");
+		return -EINVAL;
+	}
+
+	PROGRAM_CNTXT_INIT(p, descbuf, 0);
+	if (swap)
+		PROGRAM_SET_BSWAP(p);
+	if (ps)
+		PROGRAM_SET_36BIT_ADDR(p);
+
+	SHR_HDR(p, desc_share[cipherdata->algtype][authdata->algtype], 0, 0);
+
+	pdb_type = cnstr_pdcp_c_plane_pdb(p,
+			hfn,
+			bearer,
+			direction,
+			hfn_threshold,
+			cipherdata,
+			authdata);
+
+	SET_LABEL(p, pdb_end);
+
+	err = insert_hfn_ov_op(p, PDCP_SN_SIZE_5, pdb_type,
+			       era_2_sw_hfn_override);
+	if (err)
+		return err;
+
+	err = pdcp_cp_fp[cipherdata->algtype][authdata->algtype](p,
+		cipherdata,
+		authdata,
+		OP_TYPE_ENCAP_PROTOCOL,
+		era_2_sw_hfn_override);
+	if (err)
+		return err;
+
+	PATCH_HDR(p, 0, pdb_end);
+
+	return PROGRAM_FINALIZE(p);
+}
+
+/**
+ * cnstr_shdsc_pdcp_c_plane_decap - Function for creating a PDCP Control Plane
+ *                                  decapsulation descriptor.
+ * @descbuf: pointer to buffer for descriptor construction
+ * @ps: if 36/40bit addressing is desired, this parameter must be true
+ * @swap: must be true when core endianness doesn't match SEC endianness
+ * @hfn: starting Hyper Frame Number to be used together with the SN from the
+ *       PDCP frames.
+ * @bearer: radio bearer ID
+ * @direction: the direction of the PDCP frame (UL/DL)
+ * @hfn_threshold: HFN value that once reached triggers a warning from SEC that
+ *                 keys should be renegotiated at the earliest convenience.
+ * @cipherdata: pointer to block cipher transform definitions
+ *              Valid algorithm values are those from cipher_type_pdcp enum.
+ * @authdata: pointer to authentication transform definitions
+ *            Valid algorithm values are those from auth_type_pdcp enum.
+ * @era_2_sw_hfn_override: if software HFN override mechanism is desired for
+ *                         this descriptor. Note: Can only be used for
+ *                         SEC ERA 2.
+ *
+ * Return: size of descriptor written in words or negative number on error.
+ *         Once the function returns, the value of this parameter can be used
+ *         for reclaiming the space that wasn't used for the descriptor.
+ *
+ * Note: descbuf must be large enough to contain a full 256 byte long
+ * descriptor; after the function returns, by subtracting the actual number of
+ * bytes used, the user can reuse the remaining buffer space for other purposes.
+ */
+static inline int cnstr_shdsc_pdcp_c_plane_decap(uint32_t *descbuf,
+		bool ps,
+		bool swap,
+		uint32_t hfn,
+		unsigned char bearer,
+		unsigned char direction,
+		uint32_t hfn_threshold,
+		struct alginfo *cipherdata,
+		struct alginfo *authdata,
+		unsigned char era_2_sw_hfn_override)
+{
+	static int
+		(*pdcp_cp_fp[PDCP_CIPHER_TYPE_INVALID][PDCP_AUTH_TYPE_INVALID])
+			(struct program*, struct alginfo *,
+			 struct alginfo *, unsigned, unsigned char) = {
+		{	/* NULL */
+			pdcp_insert_cplane_null_op,	/* NULL */
+			pdcp_insert_cplane_int_only_op,	/* SNOW f9 */
+			pdcp_insert_cplane_int_only_op,	/* AES CMAC */
+			pdcp_insert_cplane_int_only_op	/* ZUC-I */
+		},
+		{	/* SNOW f8 */
+			pdcp_insert_cplane_enc_only_op,	/* NULL */
+			pdcp_insert_cplane_acc_op,	/* SNOW f9 */
+			pdcp_insert_cplane_snow_aes_op,	/* AES CMAC */
+			pdcp_insert_cplane_snow_zuc_op	/* ZUC-I */
+		},
+		{	/* AES CTR */
+			pdcp_insert_cplane_enc_only_op,	/* NULL */
+			pdcp_insert_cplane_aes_snow_op,	/* SNOW f9 */
+			pdcp_insert_cplane_acc_op,	/* AES CMAC */
+			pdcp_insert_cplane_aes_zuc_op	/* ZUC-I */
+		},
+		{	/* ZUC-E */
+			pdcp_insert_cplane_enc_only_op,	/* NULL */
+			pdcp_insert_cplane_zuc_snow_op,	/* SNOW f9 */
+			pdcp_insert_cplane_zuc_aes_op,	/* AES CMAC */
+			pdcp_insert_cplane_acc_op	/* ZUC-I */
+		},
+	};
+	static enum rta_share_type
+		desc_share[PDCP_CIPHER_TYPE_INVALID][PDCP_AUTH_TYPE_INVALID] = {
+		{	/* NULL */
+			SHR_WAIT,	/* NULL */
+			SHR_ALWAYS,	/* SNOW f9 */
+			SHR_ALWAYS,	/* AES CMAC */
+			SHR_ALWAYS	/* ZUC-I */
+		},
+		{	/* SNOW f8 */
+			SHR_ALWAYS,	/* NULL */
+			SHR_ALWAYS,	/* SNOW f9 */
+			SHR_WAIT,	/* AES CMAC */
+			SHR_WAIT	/* ZUC-I */
+		},
+		{	/* AES CTR */
+			SHR_ALWAYS,	/* NULL */
+			SHR_ALWAYS,	/* SNOW f9 */
+			SHR_ALWAYS,	/* AES CMAC */
+			SHR_WAIT	/* ZUC-I */
+		},
+		{	/* ZUC-E */
+			SHR_ALWAYS,	/* NULL */
+			SHR_WAIT,	/* SNOW f9 */
+			SHR_WAIT,	/* AES CMAC */
+			SHR_ALWAYS	/* ZUC-I */
+		},
+	};
+	enum pdb_type_e pdb_type;
+	struct program prg;
+	struct program *p = &prg;
+	int err;
+	LABEL(pdb_end);
+
+	if (rta_sec_era != RTA_SEC_ERA_2 && era_2_sw_hfn_override) {
+		pr_err("Cannot select SW HFN override for other era than 2");
+		return -EINVAL;
+	}
+
+	PROGRAM_CNTXT_INIT(p, descbuf, 0);
+	if (swap)
+		PROGRAM_SET_BSWAP(p);
+	if (ps)
+		PROGRAM_SET_36BIT_ADDR(p);
+
+	SHR_HDR(p, desc_share[cipherdata->algtype][authdata->algtype], 0, 0);
+
+	pdb_type = cnstr_pdcp_c_plane_pdb(p,
+			hfn,
+			bearer,
+			direction,
+			hfn_threshold,
+			cipherdata,
+			authdata);
+
+	SET_LABEL(p, pdb_end);
+
+	err = insert_hfn_ov_op(p, PDCP_SN_SIZE_5, pdb_type,
+			       era_2_sw_hfn_override);
+	if (err)
+		return err;
+
+	err = pdcp_cp_fp[cipherdata->algtype][authdata->algtype](p,
+		cipherdata,
+		authdata,
+		OP_TYPE_DECAP_PROTOCOL,
+		era_2_sw_hfn_override);
+	if (err)
+		return err;
+
+	PATCH_HDR(p, 0, pdb_end);
+
+	return PROGRAM_FINALIZE(p);
+}
+
+/**
+ * cnstr_shdsc_pdcp_u_plane_encap - Function for creating a PDCP User Plane
+ *                                  encapsulation descriptor.
+ * @descbuf: pointer to buffer for descriptor construction
+ * @ps: if 36/40bit addressing is desired, this parameter must be true
+ * @swap: must be true when core endianness doesn't match SEC endianness
+ * @sn_size: selects Sequence Number Size: 7/12/15 bits
+ * @hfn: starting Hyper Frame Number to be used together with the SN from the
+ *       PDCP frames.
+ * @bearer: radio bearer ID
+ * @direction: the direction of the PDCP frame (UL/DL)
+ * @hfn_threshold: HFN value that once reached triggers a warning from SEC that
+ *                 keys should be renegotiated at the earliest convenience.
+ * @cipherdata: pointer to block cipher transform definitions
+ *              Valid algorithm values are those from cipher_type_pdcp enum.
+ * @era_2_sw_hfn_override: if software HFN override mechanism is desired for
+ *                         this descriptor. Note: Can only be used for
+ *                         SEC ERA 2.
+ *
+ * Return: size of descriptor written in words or negative number on error.
+ *         Once the function returns, the value of this parameter can be used
+ *         for reclaiming the space that wasn't used for the descriptor.
+ *
+ * Note: descbuf must be large enough to contain a full 256 byte long
+ * descriptor; after the function returns, by subtracting the actual number of
+ * bytes used, the user can reuse the remaining buffer space for other purposes.
+ */
+static inline int cnstr_shdsc_pdcp_u_plane_encap(uint32_t *descbuf,
+		bool ps,
+		bool swap,
+		enum pdcp_sn_size sn_size,
+		uint32_t hfn,
+		unsigned short bearer,
+		unsigned short direction,
+		uint32_t hfn_threshold,
+		struct alginfo *cipherdata,
+		unsigned char era_2_sw_hfn_override)
+{
+	struct program prg;
+	struct program *p = &prg;
+	int err;
+	LABEL(pdb_end);
+
+	if (rta_sec_era != RTA_SEC_ERA_2 && era_2_sw_hfn_override) {
+		pr_err("Cannot select SW HFN override for other era than 2");
+		return -EINVAL;
+	}
+
+	PROGRAM_CNTXT_INIT(p, descbuf, 0);
+	if (swap)
+		PROGRAM_SET_BSWAP(p);
+	if (ps)
+		PROGRAM_SET_36BIT_ADDR(p);
+
+	SHR_HDR(p, SHR_ALWAYS, 0, 0);
+	if (cnstr_pdcp_u_plane_pdb(p, sn_size, hfn, bearer, direction,
+				   hfn_threshold)) {
+		pr_err("Error creating PDCP UPlane PDB\n");
+		return -EINVAL;
+	}
+	SET_LABEL(p, pdb_end);
+
+	err = insert_hfn_ov_op(p, sn_size, PDCP_PDB_TYPE_FULL_PDB,
+			       era_2_sw_hfn_override);
+	if (err)
+		return err;
+
+	switch (sn_size) {
+	case PDCP_SN_SIZE_7:
+	case PDCP_SN_SIZE_12:
+		switch (cipherdata->algtype) {
+		case PDCP_CIPHER_TYPE_ZUC:
+			if (rta_sec_era < RTA_SEC_ERA_5) {
+				pr_err("Invalid era for selected algorithm\n");
+				return -ENOTSUP;
+			}
+		case PDCP_CIPHER_TYPE_AES:
+		case PDCP_CIPHER_TYPE_SNOW:
+			/* Insert Cipher Key */
+			KEY(p, KEY1, cipherdata->key_enc_flags,
+			    (uint64_t)cipherdata->key, cipherdata->keylen,
+			    INLINE_KEY(cipherdata));
+			PROTOCOL(p, OP_TYPE_ENCAP_PROTOCOL,
+				 OP_PCLID_LTE_PDCP_USER,
+				 (uint16_t)cipherdata->algtype);
+			break;
+		case PDCP_CIPHER_TYPE_NULL:
+			insert_copy_frame_op(p,
+					     cipherdata,
+					     OP_TYPE_ENCAP_PROTOCOL);
+			break;
+		default:
+			pr_err("%s: Invalid encrypt algorithm selected: %d\n",
+			       "cnstr_pcl_shdsc_pdcp_u_plane_decap",
+			       cipherdata->algtype);
+			return -EINVAL;
+		}
+		break;
+
+	case PDCP_SN_SIZE_15:
+		switch (cipherdata->algtype) {
+		case PDCP_CIPHER_TYPE_NULL:
+			insert_copy_frame_op(p,
+					     cipherdata,
+					     OP_TYPE_ENCAP_PROTOCOL);
+			break;
+
+		default:
+			err = pdcp_insert_uplane_15bit_op(p, cipherdata,
+				OP_TYPE_ENCAP_PROTOCOL);
+			if (err)
+				return err;
+			break;
+		}
+		break;
+
+	case PDCP_SN_SIZE_5:
+	default:
+		pr_err("Invalid SN size selected\n");
+		return -ENOTSUP;
+	}
+
+	PATCH_HDR(p, 0, pdb_end);
+	return PROGRAM_FINALIZE(p);
+}
+
+/**
+ * cnstr_shdsc_pdcp_u_plane_decap - Function for creating a PDCP User Plane
+ *                                  decapsulation descriptor.
+ * @descbuf: pointer to buffer for descriptor construction
+ * @ps: if 36/40bit addressing is desired, this parameter must be true
+ * @swap: must be true when core endianness doesn't match SEC endianness
+ * @sn_size: selects Sequence Number Size: 7/12/15 bits
+ * @hfn: starting Hyper Frame Number to be used together with the SN from the
+ *       PDCP frames.
+ * @bearer: radio bearer ID
+ * @direction: the direction of the PDCP frame (UL/DL)
+ * @hfn_threshold: HFN value that once reached triggers a warning from SEC that
+ *                 keys should be renegotiated at the earliest convenience.
+ * @cipherdata: pointer to block cipher transform definitions
+ *              Valid algorithm values are those from cipher_type_pdcp enum.
+ * @era_2_sw_hfn_override: if software HFN override mechanism is desired for
+ *                         this descriptor. Note: Can only be used for
+ *                         SEC ERA 2.
+ *
+ * Return: size of descriptor written in words or negative number on error.
+ *         Once the function returns, the value of this parameter can be used
+ *         for reclaiming the space that wasn't used for the descriptor.
+ *
+ * Note: descbuf must be large enough to contain a full 256 byte long
+ * descriptor; after the function returns, by subtracting the actual number of
+ * bytes used, the user can reuse the remaining buffer space for other purposes.
+ */
+static inline int cnstr_shdsc_pdcp_u_plane_decap(uint32_t *descbuf,
+		bool ps,
+		bool swap,
+		enum pdcp_sn_size sn_size,
+		uint32_t hfn,
+		unsigned short bearer,
+		unsigned short direction,
+		uint32_t hfn_threshold,
+		struct alginfo *cipherdata,
+		unsigned char era_2_sw_hfn_override)
+{
+	struct program prg;
+	struct program *p = &prg;
+	int err;
+	LABEL(pdb_end);
+
+	if (rta_sec_era != RTA_SEC_ERA_2 && era_2_sw_hfn_override) {
+		pr_err("Cannot select SW HFN override for other era than 2");
+		return -EINVAL;
+	}
+
+	PROGRAM_CNTXT_INIT(p, descbuf, 0);
+	if (swap)
+		PROGRAM_SET_BSWAP(p);
+	if (ps)
+		PROGRAM_SET_36BIT_ADDR(p);
+
+	SHR_HDR(p, SHR_ALWAYS, 0, 0);
+	if (cnstr_pdcp_u_plane_pdb(p, sn_size, hfn, bearer, direction,
+				   hfn_threshold)) {
+		pr_err("Error creating PDCP UPlane PDB\n");
+		return -EINVAL;
+	}
+	SET_LABEL(p, pdb_end);
+
+	err = insert_hfn_ov_op(p, sn_size, PDCP_PDB_TYPE_FULL_PDB,
+			       era_2_sw_hfn_override);
+	if (err)
+		return err;
+
+	switch (sn_size) {
+	case PDCP_SN_SIZE_7:
+	case PDCP_SN_SIZE_12:
+		switch (cipherdata->algtype) {
+		case PDCP_CIPHER_TYPE_ZUC:
+			if (rta_sec_era < RTA_SEC_ERA_5) {
+				pr_err("Invalid era for selected algorithm\n");
+				return -ENOTSUP;
+			}
+		case PDCP_CIPHER_TYPE_AES:
+		case PDCP_CIPHER_TYPE_SNOW:
+			/* Insert Cipher Key */
+			KEY(p, KEY1, cipherdata->key_enc_flags,
+			    cipherdata->key, cipherdata->keylen,
+			    INLINE_KEY(cipherdata));
+			PROTOCOL(p, OP_TYPE_DECAP_PROTOCOL,
+				 OP_PCLID_LTE_PDCP_USER,
+				 (uint16_t)cipherdata->algtype);
+			break;
+		case PDCP_CIPHER_TYPE_NULL:
+			insert_copy_frame_op(p,
+					     cipherdata,
+					     OP_TYPE_DECAP_PROTOCOL);
+			break;
+		default:
+			pr_err("%s: Invalid encrypt algorithm selected: %d\n",
+			       "cnstr_pcl_shdsc_pdcp_u_plane_decap",
+			       cipherdata->algtype);
+			return -EINVAL;
+		}
+		break;
+
+	case PDCP_SN_SIZE_15:
+		switch (cipherdata->algtype) {
+		case PDCP_CIPHER_TYPE_NULL:
+			insert_copy_frame_op(p,
+					     cipherdata,
+					     OP_TYPE_DECAP_PROTOCOL);
+			break;
+
+		default:
+			err = pdcp_insert_uplane_15bit_op(p, cipherdata,
+				OP_TYPE_DECAP_PROTOCOL);
+			if (err)
+				return err;
+			break;
+		}
+		break;
+
+	case PDCP_SN_SIZE_5:
+	default:
+		pr_err("Invalid SN size selected\n");
+		return -ENOTSUP;
+	}
+
+	PATCH_HDR(p, 0, pdb_end);
+	return PROGRAM_FINALIZE(p);
+}
+
+/**
+ * cnstr_shdsc_pdcp_short_mac - Function for creating a PDCP Short MAC
+ *                              descriptor.
+ * @descbuf: pointer to buffer for descriptor construction
+ * @ps: if 36/40bit addressing is desired, this parameter must be true
+ * @swap: must be true when core endianness doesn't match SEC endianness
+ * @authdata: pointer to authentication transform definitions
+ *            Valid algorithm values are those from auth_type_pdcp enum.
+ *
+ * Return: size of descriptor written in words or negative number on error.
+ *         Once the function returns, the value of this parameter can be used
+ *         for reclaiming the space that wasn't used for the descriptor.
+ *
+ * Note: descbuf must be large enough to contain a full 256 byte long
+ * descriptor; after the function returns, by subtracting the actual number of
+ * bytes used, the user can reuse the remaining buffer space for other purposes.
+ */
+static inline int cnstr_shdsc_pdcp_short_mac(uint32_t *descbuf,
+		bool ps,
+		bool swap,
+		struct alginfo *authdata)
+{
+	struct program prg;
+	struct program *p = &prg;
+	uint32_t iv[3] = {0, 0, 0};
+	LABEL(local_offset);
+	REFERENCE(move_cmd_read_descbuf);
+	REFERENCE(move_cmd_write_descbuf);
+
+	PROGRAM_CNTXT_INIT(p, descbuf, 0);
+	if (swap)
+		PROGRAM_SET_BSWAP(p);
+	if (ps)
+		PROGRAM_SET_36BIT_ADDR(p);
+
+	SHR_HDR(p, SHR_ALWAYS, 1, 0);
+
+	if (rta_sec_era > RTA_SEC_ERA_2) {
+		MATHB(p, SEQINSZ, SUB, ZERO, VSEQINSZ, 4, 0);
+		MATHB(p, SEQINSZ, SUB, ZERO, MATH1, 4, 0);
+	} else {
+		MATHB(p, SEQINSZ, ADD, ONE, MATH1, 4, 0);
+		MATHB(p, MATH1, SUB, ONE, MATH1, 4, 0);
+		MATHB(p, ZERO, ADD, MATH1, VSEQINSZ, 4, 0);
+		MOVE(p, MATH1, 0, MATH0, 0, 8, IMMED);
+
+		/*
+		 * Since MOVELEN is available only starting with
+		 * SEC ERA 3, use poor man's MOVELEN: create a MOVE
+		 * command dynamically by writing the length from M1 by
+		 * OR-ing the command in the M1 register and MOVE the
+		 * result into the descriptor buffer. Care must be taken
+		 * wrt. the location of the command because of SEC
+		 * pipelining. The actual MOVEs are written at the end
+		 * of the descriptor due to calculations needed on the
+		 * offset in the descriptor for the MOVE command.
+		 */
+		move_cmd_read_descbuf = MOVE(p, DESCBUF, 0, MATH0, 0, 6,
+					     IMMED);
+		move_cmd_write_descbuf = MOVE(p, MATH0, 0, DESCBUF, 0, 8,
+					      WAITCOMP | IMMED);
+	}
+	MATHB(p, ZERO, ADD, MATH1, VSEQOUTSZ, 4, 0);
+
+	switch (authdata->algtype) {
+	case PDCP_AUTH_TYPE_NULL:
+		SEQFIFOSTORE(p, MSG, 0, 0, VLF);
+		if (rta_sec_era > RTA_SEC_ERA_2) {
+			MOVE(p, AB1, 0, OFIFO, 0, MATH1, 0);
+		} else {
+			SET_LABEL(p, local_offset);
+
+			/* Shut off automatic Info FIFO entries */
+			LOAD(p, 0, DCTRL, LDOFF_DISABLE_AUTO_NFIFO, 0, IMMED);
+
+			/* Placeholder for MOVE command with length from M1
+			 * register
+			 */
+			MOVE(p, IFIFOAB1, 0, OFIFO, 0, 0, IMMED);
+
+			/* Enable automatic Info FIFO entries */
+			LOAD(p, 0, DCTRL, LDOFF_ENABLE_AUTO_NFIFO, 0, IMMED);
+		}
+
+		LOAD(p, (uintptr_t)iv, MATH0, 0, 8, IMMED | COPY);
+		SEQFIFOLOAD(p, MSG1, 0, VLF | LAST1 | LAST2 | FLUSH1);
+		SEQSTORE(p, MATH0, 0, 4, 0);
+
+		break;
+
+	case PDCP_AUTH_TYPE_SNOW:
+		iv[0] = 0xFFFFFFFF;
+		iv[1] = swap ? swab32(0x04000000) : 0x04000000;
+		iv[2] = swap ? swab32(0xF8000000) : 0xF8000000;
+
+		KEY(p, KEY2, authdata->key_enc_flags, authdata->key,
+		    authdata->keylen, INLINE_KEY(authdata));
+		LOAD(p, (uintptr_t)&iv, CONTEXT2, 0, 12, IMMED | COPY);
+		ALG_OPERATION(p, OP_ALG_ALGSEL_SNOW_F9,
+			      OP_ALG_AAI_F9,
+			      OP_ALG_AS_INITFINAL,
+			      ICV_CHECK_DISABLE,
+			      DIR_ENC);
+		SEQFIFOSTORE(p, MSG, 0, 0, VLF);
+
+		if (rta_sec_era > RTA_SEC_ERA_2) {
+			MOVE(p, AB1, 0, OFIFO, 0, MATH1, 0);
+		} else {
+			SET_LABEL(p, local_offset);
+
+
+			/* Shut off automatic Info FIFO entries */
+			LOAD(p, 0, DCTRL, LDOFF_DISABLE_AUTO_NFIFO, 0, IMMED);
+
+			/* Placeholder for MOVE command with length from M1
+			 * register */
+			MOVE(p, IFIFOAB1, 0, OFIFO, 0, 0, IMMED);
+
+			/* Enable automatic Info FIFO entries */
+			LOAD(p, 0, DCTRL, LDOFF_ENABLE_AUTO_NFIFO, 0, IMMED);
+		}
+		SEQFIFOLOAD(p, MSGINSNOOP, 0, VLF | LAST1 | LAST2 | FLUSH1);
+		SEQSTORE(p, CONTEXT2, 0, 4, 0);
+
+		break;
+
+	case PDCP_AUTH_TYPE_AES:
+		iv[0] = 0xFFFFFFFF;
+		iv[1] = swap ? swab32(0xFC000000) : 0xFC000000;
+		iv[2] = 0x00000000; /* unused */
+
+		KEY(p, KEY1, authdata->key_enc_flags, authdata->key,
+		    authdata->keylen, INLINE_KEY(authdata));
+		LOAD(p, (uintptr_t)&iv, MATH0, 0, 8, IMMED | COPY);
+		MOVE(p, MATH0, 0, IFIFOAB1, 0, 8, IMMED);
+		ALG_OPERATION(p, OP_ALG_ALGSEL_AES,
+			      OP_ALG_AAI_CMAC,
+			      OP_ALG_AS_INITFINAL,
+			      ICV_CHECK_DISABLE,
+			      DIR_ENC);
+		SEQFIFOSTORE(p, MSG, 0, 0, VLF);
+
+		if (rta_sec_era > RTA_SEC_ERA_2) {
+			MOVE(p, AB2, 0, OFIFO, 0, MATH1, 0);
+		} else {
+			SET_LABEL(p, local_offset);
+
+			/* Shut off automatic Info FIFO entries */
+			LOAD(p, 0, DCTRL, LDOFF_DISABLE_AUTO_NFIFO, 0, IMMED);
+
+			/* Placeholder for MOVE command with length from M1
+			 * register */
+			MOVE(p, IFIFOAB2, 0, OFIFO, 0, 0, IMMED);
+
+			/* Enable automatic Info FIFO entries */
+			LOAD(p, 0, DCTRL, LDOFF_ENABLE_AUTO_NFIFO, 0, IMMED);
+		}
+		SEQFIFOLOAD(p, MSGINSNOOP, 0, VLF | LAST1 | LAST2 | FLUSH1);
+		SEQSTORE(p, CONTEXT1, 0, 4, 0);
+
+		break;
+
+	case PDCP_AUTH_TYPE_ZUC:
+		if (rta_sec_era < RTA_SEC_ERA_5) {
+			pr_err("Invalid era for selected algorithm\n");
+			return -ENOTSUP;
+		}
+		iv[0] = 0xFFFFFFFF;
+		iv[1] = swap ? swab32(0xFC000000) : 0xFC000000;
+		iv[2] = 0x00000000; /* unused */
+
+		KEY(p, KEY2, authdata->key_enc_flags, authdata->key,
+		    authdata->keylen, INLINE_KEY(authdata));
+		LOAD(p, (uintptr_t)&iv, CONTEXT2, 0, 12, IMMED | COPY);
+		ALG_OPERATION(p, OP_ALG_ALGSEL_ZUCA,
+			      OP_ALG_AAI_F9,
+			      OP_ALG_AS_INITFINAL,
+			      ICV_CHECK_DISABLE,
+			      DIR_ENC);
+		SEQFIFOSTORE(p, MSG, 0, 0, VLF);
+		MOVE(p, AB1, 0, OFIFO, 0, MATH1, 0);
+		SEQFIFOLOAD(p, MSGINSNOOP, 0, VLF | LAST1 | LAST2 | FLUSH1);
+		SEQSTORE(p, CONTEXT2, 0, 4, 0);
+
+		break;
+
+	default:
+		pr_err("%s: Invalid integrity algorithm selected: %d\n",
+		       "cnstr_shdsc_pdcp_short_mac", authdata->algtype);
+		return -EINVAL;
+	}
+
+
+	if (rta_sec_era < RTA_SEC_ERA_3) {
+		PATCH_MOVE(p, move_cmd_read_descbuf, local_offset);
+		PATCH_MOVE(p, move_cmd_write_descbuf, local_offset);
+	}
+
+	return PROGRAM_FINALIZE(p);
+}
+
+#endif /* __DESC_PDCP_H__ */
-- 
2.17.1

^ permalink raw reply	[flat|nested] 41+ messages in thread

* [dpdk-dev] [PATCH 3/3] crypto/dpaa2_sec: support pdcp offload
  2018-08-28 13:01 [dpdk-dev] [PATCH 0/3] security: support for pdcp akhil.goyal
  2018-08-28 13:01 ` [dpdk-dev] [PATCH 1/3] security: support pdcp protocol akhil.goyal
  2018-08-28 13:01 ` [dpdk-dev] [PATCH 2/3] crypto/dpaa2_sec: add sample pdcp descriptor apis akhil.goyal
@ 2018-08-28 13:01 ` akhil.goyal
  2018-08-30  6:46 ` [dpdk-dev] [PATCH 0/3] security: support for pdcp Akhil Goyal
  2018-10-05 13:33 ` [dpdk-dev] [PATCH v2 " akhil.goyal
  4 siblings, 0 replies; 41+ messages in thread
From: akhil.goyal @ 2018-08-28 13:01 UTC (permalink / raw)
  To: dev; +Cc: Akhil Goyal

From: Akhil Goyal <akhil.goyal@nxp.com>

Signed-off-by: Hemant Agrawal <hemant.agrawal@nxp.com>
Signed-off-by: Akhil Goyal <akhil.goyal@nxp.com>
---
 drivers/crypto/dpaa2_sec/dpaa2_sec_dpseci.c | 294 ++++++++++++++++++++
 drivers/crypto/dpaa2_sec/dpaa2_sec_priv.h   | 172 ++++++++++++
 2 files changed, 466 insertions(+)

diff --git a/drivers/crypto/dpaa2_sec/dpaa2_sec_dpseci.c b/drivers/crypto/dpaa2_sec/dpaa2_sec_dpseci.c
index 2a3c61c66..ef4e1ab37 100644
--- a/drivers/crypto/dpaa2_sec/dpaa2_sec_dpseci.c
+++ b/drivers/crypto/dpaa2_sec/dpaa2_sec_dpseci.c
@@ -35,6 +35,7 @@ typedef uint64_t	dma_addr_t;
 
 /* RTA header files */
 #include <hw/desc/ipsec.h>
+#include <hw/desc/pdcp.h>
 #include <hw/desc/algo.h>
 
 /* Minimum job descriptor consists of a oneword job descriptor HEADER and
@@ -61,6 +62,70 @@ static uint8_t cryptodev_driver_id;
 
 int dpaa2_logtype_sec;
 
+static inline int
+build_proto_compound_fd(dpaa2_sec_session *sess,
+	       struct rte_crypto_op *op,
+	       struct qbman_fd *fd, uint16_t bpid)
+{
+	struct rte_crypto_sym_op *sym_op = op->sym;
+	struct ctxt_priv *priv = sess->ctxt;
+	struct qbman_fle *fle, *ip_fle, *op_fle;
+	struct sec_flow_context *flc;
+	struct rte_mbuf *src_mbuf = sym_op->m_src;
+	struct rte_mbuf *dst_mbuf = sym_op->m_dst;
+	int retval;
+
+	if (!dst_mbuf)
+		dst_mbuf = src_mbuf;
+
+	/* Save the shared descriptor */
+	flc = &priv->flc_desc[0].flc;
+
+	/* we are using the first FLE entry to store Mbuf */
+	retval = rte_mempool_get(priv->fle_pool, (void **)(&fle));
+	if (retval) {
+		DPAA2_SEC_ERR("Memory alloc failed");
+		return -1;
+	}
+	memset(fle, 0, FLE_POOL_BUF_SIZE);
+	DPAA2_SET_FLE_ADDR(fle, (size_t)op);
+	DPAA2_FLE_SAVE_CTXT(fle, (ptrdiff_t)priv);
+
+	op_fle = fle + 1;
+	ip_fle = fle + 2;
+
+	if (likely(bpid < MAX_BPID)) {
+		DPAA2_SET_FD_BPID(fd, bpid);
+		DPAA2_SET_FLE_BPID(op_fle, bpid);
+		DPAA2_SET_FLE_BPID(ip_fle, bpid);
+	} else {
+		DPAA2_SET_FD_IVP(fd);
+		DPAA2_SET_FLE_IVP(op_fle);
+		DPAA2_SET_FLE_IVP(ip_fle);
+	}
+
+	/* Configure FD as a FRAME LIST */
+	DPAA2_SET_FD_ADDR(fd, DPAA2_VADDR_TO_IOVA(op_fle));
+	DPAA2_SET_FD_COMPOUND_FMT(fd);
+	DPAA2_SET_FD_FLC(fd, (ptrdiff_t)flc);
+
+	/* Configure Output FLE with dst mbuf data  */
+	DPAA2_SET_FLE_ADDR(op_fle, DPAA2_MBUF_VADDR_TO_IOVA(dst_mbuf));
+	DPAA2_SET_FLE_OFFSET(op_fle, dst_mbuf->data_off);
+	DPAA2_SET_FLE_LEN(op_fle, dst_mbuf->buf_len);
+
+	/* Configure Input FLE with src mbuf data */
+	DPAA2_SET_FLE_ADDR(ip_fle, DPAA2_MBUF_VADDR_TO_IOVA(src_mbuf));
+	DPAA2_SET_FLE_OFFSET(ip_fle, src_mbuf->data_off);
+	DPAA2_SET_FLE_LEN(ip_fle, src_mbuf->pkt_len);
+
+	DPAA2_SET_FD_LEN(fd, ip_fle->length);
+	DPAA2_SET_FLE_FIN(ip_fle);
+
+	return 0;
+
+}
+
 static inline int
 build_proto_fd(dpaa2_sec_session *sess,
 	       struct rte_crypto_op *op,
@@ -1124,6 +1189,9 @@ build_sec_fd(struct rte_crypto_op *op,
 		case DPAA2_SEC_IPSEC:
 			ret = build_proto_fd(sess, op, fd, bpid);
 			break;
+		case DPAA2_SEC_PDCP:
+			ret = build_proto_compound_fd(sess, op, fd, bpid);
+			break;
 		case DPAA2_SEC_HASH_CIPHER:
 		default:
 			DPAA2_SEC_ERR("error: Unsupported session");
@@ -2375,6 +2443,228 @@ dpaa2_sec_set_ipsec_session(struct rte_cryptodev *dev,
 	return -1;
 }
 
+static int
+dpaa2_sec_set_pdcp_session(struct rte_cryptodev *dev,
+			   struct rte_security_session_conf *conf,
+			   void *sess)
+{
+	struct rte_security_pdcp_xform *pdcp_xform = &conf->pdcp;
+	struct rte_crypto_sym_xform *xform = conf->crypto_xform;
+	struct rte_crypto_auth_xform *auth_xform = NULL;
+	struct rte_crypto_cipher_xform *cipher_xform;
+	dpaa2_sec_session *session = (dpaa2_sec_session *)sess;
+	struct ctxt_priv *priv;
+	struct dpaa2_sec_dev_private *dev_priv = dev->data->dev_private;
+	struct alginfo authdata, cipherdata;
+	int bufsize = -1;
+	struct sec_flow_context *flc;
+
+	PMD_INIT_FUNC_TRACE();
+
+	memset(session, 0, sizeof(dpaa2_sec_session));
+
+	priv = (struct ctxt_priv *)rte_zmalloc(NULL,
+				sizeof(struct ctxt_priv) +
+				sizeof(struct sec_flc_desc),
+				RTE_CACHE_LINE_SIZE);
+
+	if (priv == NULL) {
+		DPAA2_SEC_ERR("No memory for priv CTXT");
+		return -ENOMEM;
+	}
+
+	priv->fle_pool = dev_priv->fle_pool;
+	flc = &priv->flc_desc[0].flc;
+
+	/* find xfrm types */
+	if (xform->type == RTE_CRYPTO_SYM_XFORM_CIPHER && xform->next == NULL) {
+		cipher_xform = &xform->cipher;
+	} else if (xform->type == RTE_CRYPTO_SYM_XFORM_CIPHER &&
+		   xform->next->type == RTE_CRYPTO_SYM_XFORM_AUTH) {
+		session->ext_params.aead_ctxt.auth_cipher_text = true;
+		cipher_xform = &xform->cipher;
+		auth_xform = &xform->next->auth;
+	} else if (xform->type == RTE_CRYPTO_SYM_XFORM_AUTH &&
+		   xform->next->type == RTE_CRYPTO_SYM_XFORM_CIPHER) {
+		session->ext_params.aead_ctxt.auth_cipher_text = false;
+		cipher_xform = &xform->next->cipher;
+		auth_xform = &xform->auth;
+	} else {
+		DPAA2_SEC_ERR("Invalid crypto type");
+		return -EINVAL;
+	}
+
+	session->ctxt_type = DPAA2_SEC_PDCP;
+	if (cipher_xform) {
+		session->cipher_key.data = rte_zmalloc(NULL,
+					       cipher_xform->key.length,
+					       RTE_CACHE_LINE_SIZE);
+		if (session->cipher_key.data == NULL &&
+				cipher_xform->key.length > 0) {
+			DPAA2_SEC_ERR("No Memory for cipher key");
+			rte_free(priv);
+			return -ENOMEM;
+		}
+		session->cipher_key.length = cipher_xform->key.length;
+		memcpy(session->cipher_key.data, cipher_xform->key.data,
+			cipher_xform->key.length);
+		session->dir = (cipher_xform->op == RTE_CRYPTO_CIPHER_OP_ENCRYPT) ?
+					DIR_ENC : DIR_DEC;
+		session->cipher_alg = cipher_xform->algo;
+	} else {
+		session->cipher_key.data = NULL;
+		session->cipher_key.length = 0;
+		session->cipher_alg = RTE_CRYPTO_CIPHER_NULL;
+		session->dir = DIR_ENC;
+	}
+
+	cipherdata.key = (size_t)session->cipher_key.data;
+	cipherdata.keylen = session->cipher_key.length;
+	cipherdata.key_enc_flags = 0;
+	cipherdata.key_type = RTA_DATA_IMM;
+
+	switch (session->cipher_alg) {
+	case RTE_CRYPTO_CIPHER_SNOW3G_UEA2:
+		cipherdata.algtype = PDCP_CIPHER_TYPE_SNOW;
+		break;
+	case RTE_CRYPTO_CIPHER_ZUC_EEA3:
+		cipherdata.algtype = PDCP_CIPHER_TYPE_ZUC;
+		break;
+	case RTE_CRYPTO_CIPHER_AES_CTR:
+		cipherdata.algtype = PDCP_CIPHER_TYPE_AES;
+		break;
+	case RTE_CRYPTO_CIPHER_NULL:
+		cipherdata.algtype = PDCP_CIPHER_TYPE_NULL;
+		break;
+	default:
+		DPAA2_SEC_ERR("Crypto: Undefined Cipher specified %u",
+			      session->cipher_alg);
+		goto out;
+	}
+
+	/* Auth is only applicable for control mode operation. */
+	if (pdcp_xform->domain == RTE_SECURITY_PDCP_MODE_CONTROL) {
+		if (pdcp_xform->sn_size != RTE_SECURITY_PDCP_SN_SIZE_5) {
+			DPAA2_SEC_ERR(
+				"PDCP Seq Num size should be 5 bits for cmode");
+			goto out;
+		}
+		if (auth_xform) {
+			session->auth_key.data = rte_zmalloc(NULL,
+							auth_xform->key.length,
+							RTE_CACHE_LINE_SIZE);
+			if (session->auth_key.data == NULL &&
+					auth_xform->key.length > 0) {
+				DPAA2_SEC_ERR("No Memory for auth key");
+				rte_free(session->cipher_key.data);
+				rte_free(priv);
+				return -ENOMEM;
+			}
+			session->auth_key.length = auth_xform->key.length;
+			memcpy(session->auth_key.data, auth_xform->key.data,
+					auth_xform->key.length);
+			session->auth_alg = auth_xform->algo;
+		} else {
+			session->auth_key.data = NULL;
+			session->auth_key.length = 0;
+			session->auth_alg = RTE_CRYPTO_AUTH_NULL;
+		}
+		authdata.key = (size_t)session->auth_key.data;
+		authdata.keylen = session->auth_key.length;
+		authdata.key_enc_flags = 0;
+		authdata.key_type = RTA_DATA_IMM;
+
+		switch (session->auth_alg) {
+		case RTE_CRYPTO_AUTH_SNOW3G_UIA2:
+			authdata.algtype = PDCP_AUTH_TYPE_SNOW;
+			break;
+		case RTE_CRYPTO_AUTH_ZUC_EIA3:
+			authdata.algtype = PDCP_AUTH_TYPE_ZUC;
+			break;
+		case RTE_CRYPTO_AUTH_AES_CMAC:
+			authdata.algtype = PDCP_AUTH_TYPE_AES;
+			break;
+		case RTE_CRYPTO_AUTH_NULL:
+			authdata.algtype = PDCP_AUTH_TYPE_NULL;
+			break;
+		default:
+			DPAA2_SEC_ERR("Crypto: Unsupported auth alg %u",
+				      session->auth_alg);
+			goto out;
+		}
+
+		if (session->dir == DIR_ENC)
+			bufsize = cnstr_shdsc_pdcp_c_plane_encap(
+					priv->flc_desc[0].desc, 1, 0,
+					pdcp_xform->hfn,
+					pdcp_xform->bearer,
+					pdcp_xform->pkt_dir,
+					pdcp_xform->hfn_threshold,
+					&cipherdata, &authdata,
+					0);
+		else if (session->dir == DIR_DEC)
+			bufsize = cnstr_shdsc_pdcp_c_plane_decap(
+					priv->flc_desc[0].desc, 1, 0,
+					pdcp_xform->hfn,
+					pdcp_xform->bearer,
+					pdcp_xform->pkt_dir,
+					pdcp_xform->hfn_threshold,
+					&cipherdata, &authdata,
+					0);
+	} else {
+		if (session->dir == DIR_ENC)
+			bufsize = cnstr_shdsc_pdcp_u_plane_encap(
+					priv->flc_desc[0].desc, 1, 0,
+					pdcp_xform->sn_size,
+					pdcp_xform->hfn,
+					pdcp_xform->bearer,
+					pdcp_xform->pkt_dir,
+					pdcp_xform->hfn_threshold,
+					&cipherdata, 0);
+		else if (session->dir == DIR_DEC)
+			bufsize = cnstr_shdsc_pdcp_u_plane_decap(
+					priv->flc_desc[0].desc, 1, 0,
+					pdcp_xform->sn_size,
+					pdcp_xform->hfn,
+					pdcp_xform->bearer,
+					pdcp_xform->pkt_dir,
+					pdcp_xform->hfn_threshold,
+					&cipherdata, 0);
+	}
+
+	if (bufsize < 0) {
+		DPAA2_SEC_ERR("Crypto: Invalid buffer length");
+		goto out;
+	}
+
+	/* Enable the stashing control bit */
+	DPAA2_SET_FLC_RSC(flc);
+	flc->word2_rflc_31_0 = lower_32_bits(
+			(size_t)&(((struct dpaa2_sec_qp *)
+			dev->data->queue_pairs[0])->rx_vq) | 0x14);
+	flc->word3_rflc_63_32 = upper_32_bits(
+			(size_t)&(((struct dpaa2_sec_qp *)
+			dev->data->queue_pairs[0])->rx_vq));
+
+	flc->word1_sdl = (uint8_t)bufsize;
+
+	/* Set EWS bit i.e. enable write-safe */
+	DPAA2_SET_FLC_EWS(flc);
+	/* Set BS = 1 i.e reuse input buffers as output buffers */
+	DPAA2_SET_FLC_REUSE_BS(flc);
+	/* Set FF = 10; reuse input buffers if they provide sufficient space */
+	DPAA2_SET_FLC_REUSE_FF(flc);
+
+	session->ctxt = priv;
+
+	return 0;
+out:
+	rte_free(session->auth_key.data);
+	rte_free(session->cipher_key.data);
+	rte_free(priv);
+	return -1;
+}
+
 static int
 dpaa2_sec_security_session_create(void *dev,
 				  struct rte_security_session_conf *conf,
@@ -2397,6 +2687,10 @@ dpaa2_sec_security_session_create(void *dev,
 		break;
 	case RTE_SECURITY_PROTOCOL_MACSEC:
 		return -ENOTSUP;
+	case RTE_SECURITY_PROTOCOL_PDCP:
+		ret = dpaa2_sec_set_pdcp_session(cdev, conf,
+				sess_private_data);
+		break;
 	default:
 		return -EINVAL;
 	}
diff --git a/drivers/crypto/dpaa2_sec/dpaa2_sec_priv.h b/drivers/crypto/dpaa2_sec/dpaa2_sec_priv.h
index d015be1e9..907374346 100644
--- a/drivers/crypto/dpaa2_sec/dpaa2_sec_priv.h
+++ b/drivers/crypto/dpaa2_sec/dpaa2_sec_priv.h
@@ -390,6 +390,162 @@ static const struct rte_cryptodev_capabilities dpaa2_sec_capabilities[] = {
 	RTE_CRYPTODEV_END_OF_CAPABILITIES_LIST()
 };
 
+static const struct rte_cryptodev_capabilities dpaa2_pdcp_capabilities[] = {
+	{	/* SNOW 3G (UIA2) */
+		.op = RTE_CRYPTO_OP_TYPE_SYMMETRIC,
+		{.sym = {
+			.xform_type = RTE_CRYPTO_SYM_XFORM_AUTH,
+			{.auth = {
+				.algo = RTE_CRYPTO_AUTH_SNOW3G_UIA2,
+				.block_size = 16,
+				.key_size = {
+					.min = 16,
+					.max = 16,
+					.increment = 0
+				},
+				.digest_size = {
+					.min = 4,
+					.max = 4,
+					.increment = 0
+				},
+				.iv_size = {
+					.min = 16,
+					.max = 16,
+					.increment = 0
+				}
+			}, }
+		}, }
+	},
+	{	/* SNOW 3G (UEA2) */
+		.op = RTE_CRYPTO_OP_TYPE_SYMMETRIC,
+		{.sym = {
+			.xform_type = RTE_CRYPTO_SYM_XFORM_CIPHER,
+			{.cipher = {
+				.algo = RTE_CRYPTO_CIPHER_SNOW3G_UEA2,
+				.block_size = 16,
+				.key_size = {
+					.min = 16,
+					.max = 16,
+					.increment = 0
+				},
+				.iv_size = {
+					.min = 16,
+					.max = 16,
+					.increment = 0
+				}
+			}, }
+		}, }
+	},
+	{	/* AES CTR */
+		.op = RTE_CRYPTO_OP_TYPE_SYMMETRIC,
+		{.sym = {
+			.xform_type = RTE_CRYPTO_SYM_XFORM_CIPHER,
+			{.cipher = {
+				.algo = RTE_CRYPTO_CIPHER_AES_CTR,
+				.block_size = 16,
+				.key_size = {
+					.min = 16,
+					.max = 32,
+					.increment = 8
+				},
+				.iv_size = {
+					.min = 16,
+					.max = 16,
+					.increment = 0
+				}
+			}, }
+		}, }
+	},
+	{	/* NULL (AUTH) */
+		.op = RTE_CRYPTO_OP_TYPE_SYMMETRIC,
+		{.sym = {
+			.xform_type = RTE_CRYPTO_SYM_XFORM_AUTH,
+			{.auth = {
+				.algo = RTE_CRYPTO_AUTH_NULL,
+				.block_size = 1,
+				.key_size = {
+					.min = 0,
+					.max = 0,
+					.increment = 0
+				},
+				.digest_size = {
+					.min = 0,
+					.max = 0,
+					.increment = 0
+				},
+				.iv_size = { 0 }
+			}, },
+		}, },
+	},
+	{	/* NULL (CIPHER) */
+		.op = RTE_CRYPTO_OP_TYPE_SYMMETRIC,
+		{.sym = {
+			.xform_type = RTE_CRYPTO_SYM_XFORM_CIPHER,
+			{.cipher = {
+				.algo = RTE_CRYPTO_CIPHER_NULL,
+				.block_size = 1,
+				.key_size = {
+					.min = 0,
+					.max = 0,
+					.increment = 0
+				},
+				.iv_size = {
+					.min = 0,
+					.max = 0,
+					.increment = 0
+				}
+			}, },
+		}, }
+	},
+	{	/* ZUC (EEA3) */
+		.op = RTE_CRYPTO_OP_TYPE_SYMMETRIC,
+		{.sym = {
+			.xform_type = RTE_CRYPTO_SYM_XFORM_CIPHER,
+			{.cipher = {
+				.algo = RTE_CRYPTO_CIPHER_ZUC_EEA3,
+				.block_size = 16,
+				.key_size = {
+					.min = 16,
+					.max = 16,
+					.increment = 0
+				},
+				.iv_size = {
+					.min = 16,
+					.max = 16,
+					.increment = 0
+				}
+			}, }
+		}, }
+	},
+	{	/* ZUC (EIA3) */
+		.op = RTE_CRYPTO_OP_TYPE_SYMMETRIC,
+		{.sym = {
+			.xform_type = RTE_CRYPTO_SYM_XFORM_AUTH,
+			{.auth = {
+				.algo = RTE_CRYPTO_AUTH_ZUC_EIA3,
+				.block_size = 16,
+				.key_size = {
+					.min = 16,
+					.max = 16,
+					.increment = 0
+				},
+				.digest_size = {
+					.min = 4,
+					.max = 4,
+					.increment = 0
+				},
+				.iv_size = {
+					.min = 16,
+					.max = 16,
+					.increment = 0
+				}
+			}, }
+		}, }
+	},
+
+	RTE_CRYPTODEV_END_OF_CAPABILITIES_LIST()
+};
+
 static const struct rte_security_capability dpaa2_sec_security_cap[] = {
 	{ /* IPsec Lookaside Protocol offload ESP Transport Egress */
 		.action = RTE_SECURITY_ACTION_TYPE_LOOKASIDE_PROTOCOL,
@@ -413,6 +569,22 @@ static const struct rte_security_capability dpaa2_sec_security_cap[] = {
 		},
 		.crypto_capabilities = dpaa2_sec_capabilities
 	},
+	{ /* PDCP Lookaside Protocol offload Data */
+		.action = RTE_SECURITY_ACTION_TYPE_LOOKASIDE_PROTOCOL,
+		.protocol = RTE_SECURITY_PROTOCOL_PDCP,
+		.pdcp = {
+			.domain = RTE_SECURITY_PDCP_MODE_DATA,
+		},
+		.crypto_capabilities = dpaa2_pdcp_capabilities
+	},
+	{ /* PDCP Lookaside Protocol offload Control */
+		.action = RTE_SECURITY_ACTION_TYPE_LOOKASIDE_PROTOCOL,
+		.protocol = RTE_SECURITY_PROTOCOL_PDCP,
+		.pdcp = {
+			.domain = RTE_SECURITY_PDCP_MODE_CONTROL,
+		},
+		.crypto_capabilities = dpaa2_pdcp_capabilities
+	},
 	{
 		.action = RTE_SECURITY_ACTION_TYPE_NONE
 	}
-- 
2.17.1

^ permalink raw reply	[flat|nested] 41+ messages in thread

* Re: [dpdk-dev] [PATCH 0/3] security: support for pdcp
  2018-08-28 13:01 [dpdk-dev] [PATCH 0/3] security: support for pdcp akhil.goyal
                   ` (2 preceding siblings ...)
  2018-08-28 13:01 ` [dpdk-dev] [PATCH 3/3] crypto/dpaa2_sec: support pdcp offload akhil.goyal
@ 2018-08-30  6:46 ` Akhil Goyal
  2018-10-05 13:33 ` [dpdk-dev] [PATCH v2 " akhil.goyal
  4 siblings, 0 replies; 41+ messages in thread
From: Akhil Goyal @ 2018-08-30  6:46 UTC (permalink / raw)
  To: Nicolau, Radu, Pablo de Lara, Declan Doherty, Anoob Joseph; +Cc: dev

Hi Declan, Pablo, Radu, Anoob,

On 8/28/2018 6:31 PM, akhil.goyal@nxp.com wrote:

> From: Akhil Goyal <akhil.goyal@nxp.com>
>
> Security library currently only has support for IPSec protocol.
> This patchset defines structures for pdcp protocol in rte_security
> and provide a sample driver implementation for lookaside protocol
> offload to support PDCP.
>
> Akhil Goyal (3):
>    security: support pdcp protocol
>    crypto/dpaa2_sec: add sample pdcp descriptor apis
>    crypto/dpaa2_sec: support pdcp offload
>
>   doc/guides/prog_guide/rte_security.rst      |   90 +-
>   drivers/crypto/dpaa2_sec/dpaa2_sec_dpseci.c |  294 +++
>   drivers/crypto/dpaa2_sec/dpaa2_sec_priv.h   |  172 ++
>   drivers/crypto/dpaa2_sec/hw/desc.h          |    2 +-
>   drivers/crypto/dpaa2_sec/hw/desc/pdcp.h     | 2642 +++++++++++++++++++
>   lib/librte_security/rte_security.c          |    4 +
>   lib/librte_security/rte_security.h          |   62 +
>   7 files changed, 3258 insertions(+), 8 deletions(-)
>   create mode 100644 drivers/crypto/dpaa2_sec/hw/desc/pdcp.h
>
Could you please help in review of this Patchset - mainly the rte_security changes.

I forgot to add you for the cc list while sending.

Thanks,

Akhil

^ permalink raw reply	[flat|nested] 41+ messages in thread

* Re: [dpdk-dev] [PATCH 1/3] security: support pdcp protocol
  2018-08-28 13:01 ` [dpdk-dev] [PATCH 1/3] security: support pdcp protocol akhil.goyal
@ 2018-09-06  4:15   ` Joseph, Anoob
  2018-10-05 12:05     ` Akhil Goyal
  0 siblings, 1 reply; 41+ messages in thread
From: Joseph, Anoob @ 2018-09-06  4:15 UTC (permalink / raw)
  To: akhil.goyal
  Cc: dev, Declan Doherty, Pablo de Lara, Radu Nicolau, Jerin Jacob,
	Narayana Prasad, Verma, Shally, Vidya Sagar Velumuri

Hi Akhil,

Please see inline.

Thanks,
Anoob

On 28-08-2018 18:31, akhil.goyal@nxp.com wrote:
> External Email
>
> From: Akhil Goyal <akhil.goyal@nxp.com>
>
> Signed-off-by: Hemant Agrawal <hemant.agrawal@nxp.com>
> Signed-off-by: Akhil Goyal <akhil.goyal@nxp.com>
> ---
>   doc/guides/prog_guide/rte_security.rst | 90 ++++++++++++++++++++++++--
>   lib/librte_security/rte_security.c     |  4 ++
>   lib/librte_security/rte_security.h     | 62 ++++++++++++++++++
>   3 files changed, 149 insertions(+), 7 deletions(-)
>
> diff --git a/doc/guides/prog_guide/rte_security.rst b/doc/guides/prog_guide/rte_security.rst
> index 0812abe77..412fff016 100644
> --- a/doc/guides/prog_guide/rte_security.rst
> +++ b/doc/guides/prog_guide/rte_security.rst
> @@ -10,8 +10,8 @@ The security library provides a framework for management and provisioning
>   of security protocol operations offloaded to hardware based devices. The
>   library defines generic APIs to create and free security sessions which can
>   support full protocol offload as well as inline crypto operation with
> -NIC or crypto devices. The framework currently only supports the IPSec protocol
> -and associated operations, other protocols will be added in future.
> +NIC or crypto devices. The framework currently only supports the IPSec and PDCP
> +protocol and associated operations, other protocols will be added in future.
>
>   Design Principles
>   -----------------
> @@ -253,6 +253,46 @@ for any protocol header addition.
>           +--------|--------+
>                    V
>
> +PDCP Flow Diagram
> +~~~~~~~~~~~~~~~~~
> +
> +.. code-block:: c
> +
> +        Transmitting PDCP Entity          Receiving PDCP Entity
> +                  |                                   ^
> +                  |                       +-----------|-----------+
> +                  V                       | In order delivery and |
> +        +---------|----------+            | Duplicate detection   |
> +        | Sequence Numbering |            |  (Data Plane only)    |
> +        +---------|----------+            +-----------|-----------+
> +                  |                                   |
> +        +---------|----------+            +-----------|----------+
> +        | Header Compression*|            | Header Decompression*|
> +        | (Data-Plane only)  |            |   (Data Plane only)  |
> +        +---------|----------+            +-----------|----------+
> +                  |                                   |
> +        +---------|-----------+           +-----------|----------+
> +        | Integrity Protection|           |Integrity Verification|
> +        | (Control Plane only)|           | (Control Plane only) |
> +        +---------|-----------+           +-----------|----------+
> +        +---------|-----------+            +----------|----------+
> +        |     Ciphering       |            |     Deciphering     |
> +        +---------|-----------+            +----------|----------+
> +        +---------|-----------+            +----------|----------+
> +        |   Add PDCP header   |            | Remove PDCP Header  |
> +        +---------|-----------+            +----------|----------+
> +                  |                                   |
> +                  +----------------->>----------------+
> +
[Anoob] Which PDCP specification revision is this based on? In the 5G 
specification, even data-plane may undergo integrity protection.
> +
> +.. note::
> +
> +    * Header Compression and decompression are not supported currently.
> +
> +Just like IPSec, in case of PDCP also header addition/deletion, cipher/
> +de-cipher, integrity protection/verification is done based on the action
> +type chosen.
> +
>   Device Features and Capabilities
>   ---------------------------------
>
> @@ -271,7 +311,7 @@ structure in the *DPDK API Reference*.
>
>   Each driver (crypto or ethernet) defines its own private array of capabilities
>   for the operations it supports. Below is an example of the capabilities for a
> -PMD which supports the IPSec protocol.
> +PMD which supports the IPSec and PDCP protocol.
>
>   .. code-block:: c
>
> @@ -298,6 +338,22 @@ PMD which supports the IPSec protocol.
>                   },
>                   .crypto_capabilities = pmd_capabilities
>           },
> +        { /* PDCP Lookaside Protocol offload Data Plane */
> +                .action = RTE_SECURITY_ACTION_TYPE_LOOKASIDE_PROTOCOL,
> +                .protocol = RTE_SECURITY_PROTOCOL_PDCP,
> +                .pdcp = {
> +                        .domain = RTE_SECURITY_PDCP_MODE_DATA,
> +                },
> +                .crypto_capabilities = pmd_capabilities
> +        },
> +        { /* PDCP Lookaside Protocol offload Control */
> +                .action = RTE_SECURITY_ACTION_TYPE_LOOKASIDE_PROTOCOL,
> +                .protocol = RTE_SECURITY_PROTOCOL_PDCP,
> +                .pdcp = {
> +                        .domain = RTE_SECURITY_PDCP_MODE_CONTROL,
> +                },
> +                .crypto_capabilities = pmd_capabilities
> +        },
>           {
>                   .action = RTE_SECURITY_ACTION_TYPE_NONE
>           }
> @@ -429,6 +485,7 @@ Security Session configuration structure is defined as ``rte_security_session_co
>           union {
>                   struct rte_security_ipsec_xform ipsec;
>                   struct rte_security_macsec_xform macsec;
> +                struct rte_security_pdcp_xform pdcp;
>           };
>           /**< Configuration parameters for security session */
>           struct rte_crypto_sym_xform *crypto_xform;
> @@ -463,15 +520,17 @@ The ``rte_security_session_protocol`` is defined as
>   .. code-block:: c
>
>       enum rte_security_session_protocol {
> -        RTE_SECURITY_PROTOCOL_IPSEC,
> +        RTE_SECURITY_PROTOCOL_IPSEC = 1,
>           /**< IPsec Protocol */
>           RTE_SECURITY_PROTOCOL_MACSEC,
>           /**< MACSec Protocol */
> +        RTE_SECURITY_PROTOCOL_PDCP,
> +        /**< PDCP Protocol */
>       };
>
> -Currently the library defines configuration parameters for IPSec only. For other
> -protocols like MACSec, structures and enums are defined as place holders which
> -will be updated in the future.
> +Currently the library defines configuration parameters for IPSec and PDCP only.
> +For other protocols like MACSec, structures and enums are defined as place holders
> +which will be updated in the future.
>
>   IPsec related configuration parameters are defined in ``rte_security_ipsec_xform``
>
> @@ -494,6 +553,23 @@ IPsec related configuration parameters are defined in ``rte_security_ipsec_xform
>           /**< Tunnel parameters, NULL for transport mode */
>       };
>
> +PDCP related configuration parameters are defined in ``rte_security_pdcp_xform``
> +
> +.. code-block:: c
> +
> +    struct rte_security_pdcp_xform {
> +        int8_t bearer; /**< PDCP bearer ID */
> +        enum rte_security_pdcp_domain domain;
> +        /** < PDCP mode of operation: Control or data */
> +        enum rte_security_pdcp_direction pkt_dir;
> +        /**< PDCP Frame Direction 0:UL 1:DL */
> +        enum rte_security_pdcp_sn_size sn_size;
> +        /**< Sequence number size, 5/7/12/15 */
> +        int8_t hfn_ovd; /**< Overwrite HFN per operation */
> +        uint32_t hfn;  /**< Hyper Frame Number */
> +        uint32_t hfn_threshold;        /**< HFN Threashold for key renegotiation */
> +    };
> +
[Anoob] PDCP packet ordering should be both a capability and a setting.
HFN will be incremented overtime and starts at 0. So why is it part of 
the xform?

Also the hfn_ovd is per operation. So why is it part of xform? Is it a 
boolean value? If so, where does the HFN for each operation come from?
>
>   Security API
>   ~~~~~~~~~~~~
> diff --git a/lib/librte_security/rte_security.c b/lib/librte_security/rte_security.c
> index 1954960a5..c6355de95 100644
> --- a/lib/librte_security/rte_security.c
> +++ b/lib/librte_security/rte_security.c
> @@ -131,6 +131,10 @@ rte_security_capability_get(struct rte_security_ctx *instance,
>                                          capability->ipsec.direction ==
>                                                          idx->ipsec.direction)
>                                          return capability;
> +                       } else if (idx->protocol == RTE_SECURITY_PROTOCOL_PDCP) {
> +                               if (capability->pdcp.domain ==
> +                                                       idx->pdcp.domain)
> +                                       return capability;
>                          }
>                  }
>          }
> diff --git a/lib/librte_security/rte_security.h b/lib/librte_security/rte_security.h
> index b0d1b97ee..e625bc656 100644
> --- a/lib/librte_security/rte_security.h
> +++ b/lib/librte_security/rte_security.h
> @@ -206,6 +206,52 @@ struct rte_security_macsec_xform {
>          int dummy;
>   };
>
> +/**
> + * PDCP Mode of session
> + */
> +enum rte_security_pdcp_domain {
> +       RTE_SECURITY_PDCP_MODE_CONTROL, /**< PDCP control plane */
> +       RTE_SECURITY_PDCP_MODE_DATA,    /**< PDCP data plane */
> +};
> +
> +/** PDCP Frame direction */
> +enum rte_security_pdcp_direction {
> +       RTE_SECURITY_PDCP_UPLINK,       /**< Uplink */
> +       RTE_SECURITY_PDCP_DOWNLINK,     /**< Downlink */
> +};
> +
> +/**
> + * PDCP Sequence Number Size selectors
> + * @PDCP_SN_SIZE_5: 5bit sequence number
> + * @PDCP_SN_SIZE_7: 7bit sequence number
> + * @PDCP_SN_SIZE_12: 12bit sequence number
> + * @PDCP_SN_SIZE_15: 15bit sequence number
> + */
> +enum rte_security_pdcp_sn_size {
> +       RTE_SECURITY_PDCP_SN_SIZE_5 = 5,
> +       RTE_SECURITY_PDCP_SN_SIZE_7 = 7,
> +       RTE_SECURITY_PDCP_SN_SIZE_12 = 12,
> +       RTE_SECURITY_PDCP_SN_SIZE_15 = 15
> +};
[Anoob] SN size 18 is also possible
> +
> +/**
> + * PDCP security association configuration data.
> + *
> + * This structure contains data required to create a PDCP security session.
> + */
> +struct rte_security_pdcp_xform {
> +       int8_t bearer;  /**< PDCP bearer ID */
> +       enum rte_security_pdcp_domain domain;
> +               /** < PDCP mode of operation: Control or data */
> +       enum rte_security_pdcp_direction pkt_dir;
> +               /**< PDCP Frame Direction 0:UL 1:DL */
> +       enum rte_security_pdcp_sn_size sn_size;
> +               /**< Sequence number size, 5/7/12/15 */
> +       int8_t hfn_ovd; /**< Overwrite HFN per operation */
> +       uint32_t hfn;   /**< Hyper Frame Number */
> +       uint32_t hfn_threshold; /**< HFN Threashold for key renegotiation */
> +};
> +
>   /**
>    * Security session action type.
>    */
> @@ -232,6 +278,8 @@ enum rte_security_session_protocol {
>          /**< IPsec Protocol */
>          RTE_SECURITY_PROTOCOL_MACSEC,
>          /**< MACSec Protocol */
> +       RTE_SECURITY_PROTOCOL_PDCP,
> +       /**< PDCP Protocol */
>   };
>
>   /**
> @@ -246,6 +294,7 @@ struct rte_security_session_conf {
>          union {
>                  struct rte_security_ipsec_xform ipsec;
>                  struct rte_security_macsec_xform macsec;
> +               struct rte_security_pdcp_xform pdcp;
>          };
>          /**< Configuration parameters for security session */
>          struct rte_crypto_sym_xform *crypto_xform;
> @@ -413,6 +462,10 @@ struct rte_security_ipsec_stats {
>
>   };
>
> +struct rte_security_pdcp_stats {
> +       uint64_t reserved;
> +};
> +
>   struct rte_security_stats {
>          enum rte_security_session_protocol protocol;
>          /**< Security protocol to be configured */
> @@ -421,6 +474,7 @@ struct rte_security_stats {
>          union {
>                  struct rte_security_macsec_stats macsec;
>                  struct rte_security_ipsec_stats ipsec;
> +               struct rte_security_pdcp_stats pdcp;
>          };
>   };
>
> @@ -465,6 +519,11 @@ struct rte_security_capability {
>                          int dummy;
>                  } macsec;
>                  /**< MACsec capability */
> +               struct {
> +                       enum rte_security_pdcp_domain domain;
> +                       /** < PDCP mode of operation: Control or data */
> +               } pdcp;
> +               /**< PDCP capability */
>          };
>
>          const struct rte_cryptodev_capabilities *crypto_capabilities;
> @@ -506,6 +565,9 @@ struct rte_security_capability_idx {
>                          enum rte_security_ipsec_sa_mode mode;
>                          enum rte_security_ipsec_sa_direction direction;
>                  } ipsec;
> +               struct {
> +                       enum rte_security_pdcp_domain domain;
> +               } pdcp;
>          };
>   };
>
> --
> 2.17.1
>

^ permalink raw reply	[flat|nested] 41+ messages in thread

* Re: [dpdk-dev] [PATCH 1/3] security: support pdcp protocol
  2018-09-06  4:15   ` Joseph, Anoob
@ 2018-10-05 12:05     ` Akhil Goyal
  2018-10-07  9:02       ` Joseph, Anoob
  0 siblings, 1 reply; 41+ messages in thread
From: Akhil Goyal @ 2018-10-05 12:05 UTC (permalink / raw)
  To: Joseph, Anoob
  Cc: dev, Declan Doherty, Pablo de Lara, Radu Nicolau, Jerin Jacob,
	Narayana Prasad, Verma, Shally, Vidya Sagar Velumuri


On 9/6/2018 9:45 AM, Joseph, Anoob wrote:

> Hi Akhil,

Hi Anoob,

Thanks for the comments.

> Please see inline.
> Thanks,
> Anoob
> On 28-08-2018 18:31, akhil.goyal@nxp.com wrote:
>> External Email
>> From: Akhil Goyal <akhil.goyal@nxp.com>
>> Signed-off-by: Hemant Agrawal <hemant.agrawal@nxp.com>
>> Signed-off-by: Akhil Goyal <akhil.goyal@nxp.com>
>> ---
>>    doc/guides/prog_guide/rte_security.rst | 90 ++++++++++++++++++++++++--
>>    lib/librte_security/rte_security.c     |  4 ++
>>    lib/librte_security/rte_security.h     | 62 ++++++++++++++++++
>>    3 files changed, 149 insertions(+), 7 deletions(-)
>> diff --git a/doc/guides/prog_guide/rte_security.rst b/doc/guides/prog_guide/rte_security.rst
>> index 0812abe77..412fff016 100644
>> --- a/doc/guides/prog_guide/rte_security.rst
>> +++ b/doc/guides/prog_guide/rte_security.rst
>> @@ -10,8 +10,8 @@ The security library provides a framework for management and provisioning
>>    of security protocol operations offloaded to hardware based devices. The
>>    library defines generic APIs to create and free security sessions which can
>>    support full protocol offload as well as inline crypto operation with
>> -NIC or crypto devices. The framework currently only supports the IPSec protocol
>> -and associated operations, other protocols will be added in future.
>> +NIC or crypto devices. The framework currently only supports the IPSec and PDCP
>> +protocol and associated operations, other protocols will be added in future.
>>    Design Principles
>>    -----------------
>> @@ -253,6 +253,46 @@ for any protocol header addition.
>>            +--------|--------+
>>                     V
>> +PDCP Flow Diagram
>> +~~~~~~~~~~~~~~~~~
>> +
>> +.. code-block:: c
>> +
>> +        Transmitting PDCP Entity          Receiving PDCP Entity
>> +                  |                                   ^
>> +                  |                       +-----------|-----------+
>> +                  V                       | In order delivery and |
>> +        +---------|----------+            | Duplicate detection   |
>> +        | Sequence Numbering |            |  (Data Plane only)    |
>> +        +---------|----------+            +-----------|-----------+
>> +                  |                                   |
>> +        +---------|----------+            +-----------|----------+
>> +        | Header Compression*|            | Header Decompression*|
>> +        | (Data-Plane only)  |            |   (Data Plane only)  |
>> +        +---------|----------+            +-----------|----------+
>> +                  |                                   |
>> +        +---------|-----------+           +-----------|----------+
>> +        | Integrity Protection|           |Integrity Verification|
>> +        | (Control Plane only)|           | (Control Plane only) |
>> +        +---------|-----------+           +-----------|----------+
>> +        +---------|-----------+            +----------|----------+
>> +        |     Ciphering       |            |     Deciphering     |
>> +        +---------|-----------+            +----------|----------+
>> +        +---------|-----------+            +----------|----------+
>> +        |   Add PDCP header   |            | Remove PDCP Header  |
>> +        +---------|-----------+            +----------|----------+
>> +                  |                                   |
>> +                  +----------------->>----------------+
>> +
> [Anoob] Which PDCP specification revision is this based on? In the 5G
> specification, even data-plane may undergo integrity protection.

This patchset is based on LTE-PDCP - 3GPP TS 36.323 v15.1.0 (2018-09).
5G changes are not added in this patchset. It will be added in future.

>> +.. note::
>> +
>> +    * Header Compression and decompression are not supported currently.
>> +
>> +Just like IPSec, in case of PDCP also header addition/deletion, cipher/
>> +de-cipher, integrity protection/verification is done based on the action
>> +type chosen.
>> +
>>    Device Features and Capabilities
>>    ---------------------------------
>> @@ -271,7 +311,7 @@ structure in the *DPDK API Reference*.
>>    Each driver (crypto or ethernet) defines its own private array of capabilities
>>    for the operations it supports. Below is an example of the capabilities for a
>> -PMD which supports the IPSec protocol.
>> +PMD which supports the IPSec and PDCP protocol.
>>    .. code-block:: c
>> @@ -298,6 +338,22 @@ PMD which supports the IPSec protocol.
>>                    },
>>                    .crypto_capabilities = pmd_capabilities
>>            },
>> +        { /* PDCP Lookaside Protocol offload Data Plane */
>> +                .action = RTE_SECURITY_ACTION_TYPE_LOOKASIDE_PROTOCOL,
>> +                .protocol = RTE_SECURITY_PROTOCOL_PDCP,
>> +                .pdcp = {
>> +                        .domain = RTE_SECURITY_PDCP_MODE_DATA,
>> +                },
>> +                .crypto_capabilities = pmd_capabilities
>> +        },
>> +        { /* PDCP Lookaside Protocol offload Control */
>> +                .action = RTE_SECURITY_ACTION_TYPE_LOOKASIDE_PROTOCOL,
>> +                .protocol = RTE_SECURITY_PROTOCOL_PDCP,
>> +                .pdcp = {
>> +                        .domain = RTE_SECURITY_PDCP_MODE_CONTROL,
>> +                },
>> +                .crypto_capabilities = pmd_capabilities
>> +        },
>>            {
>>                    .action = RTE_SECURITY_ACTION_TYPE_NONE
>>            }
>> @@ -429,6 +485,7 @@ Security Session configuration structure is defined as ``rte_security_session_co
>>            union {
>>                    struct rte_security_ipsec_xform ipsec;
>>                    struct rte_security_macsec_xform macsec;
>> +                struct rte_security_pdcp_xform pdcp;
>>            };
>>            /**< Configuration parameters for security session */
>>            struct rte_crypto_sym_xform *crypto_xform;
>> @@ -463,15 +520,17 @@ The ``rte_security_session_protocol`` is defined as
>>    .. code-block:: c
>>        enum rte_security_session_protocol {
>> -        RTE_SECURITY_PROTOCOL_IPSEC,
>> +        RTE_SECURITY_PROTOCOL_IPSEC = 1,
>>            /**< IPsec Protocol */
>>            RTE_SECURITY_PROTOCOL_MACSEC,
>>            /**< MACSec Protocol */
>> +        RTE_SECURITY_PROTOCOL_PDCP,
>> +        /**< PDCP Protocol */
>>        };
>> -Currently the library defines configuration parameters for IPSec only. For other
>> -protocols like MACSec, structures and enums are defined as place holders which
>> -will be updated in the future.
>> +Currently the library defines configuration parameters for IPSec and PDCP only.
>> +For other protocols like MACSec, structures and enums are defined as place holders
>> +which will be updated in the future.
>>    IPsec related configuration parameters are defined in ``rte_security_ipsec_xform``
>> @@ -494,6 +553,23 @@ IPsec related configuration parameters are defined in ``rte_security_ipsec_xform
>>            /**< Tunnel parameters, NULL for transport mode */
>>        };
>> +PDCP related configuration parameters are defined in ``rte_security_pdcp_xform``
>> +
>> +.. code-block:: c
>> +
>> +    struct rte_security_pdcp_xform {
>> +        int8_t bearer; /**< PDCP bearer ID */
>> +        enum rte_security_pdcp_domain domain;
>> +        /** < PDCP mode of operation: Control or data */
>> +        enum rte_security_pdcp_direction pkt_dir;
>> +        /**< PDCP Frame Direction 0:UL 1:DL */
>> +        enum rte_security_pdcp_sn_size sn_size;
>> +        /**< Sequence number size, 5/7/12/15 */
>> +        int8_t hfn_ovd; /**< Overwrite HFN per operation */
>> +        uint32_t hfn;  /**< Hyper Frame Number */
>> +        uint32_t hfn_threshold;        /**< HFN Threashold for key renegotiation */
>> +    };
>> +
> [Anoob] PDCP packet ordering should be both a capability and a setting.
> HFN will be incremented overtime and starts at 0. So why is it part of
> the xform?

The Security accelerators may assume packet in order. Latest PDCP TS 
suggest to do de-Ciphering before re-Ordering the Rx PDCP PDUs. In this 
situation, the accelerator may use wrong HFN value. The PDCP application 
can provide the appropriate HFN value along with PDU to the security 
accelerator.

> Also the hfn_ovd is per operation. So why is it part of xform? Is it a
> boolean value? If so, where does the HFN for each operation come from?

The HFN Override is a boolean. If this is set, the Accelerator shall use 
the HFN value provided by the PDCP Application to construct the IV for 
deciphering instead of deriving it from the state variables. I will 
remove this from the patch as of now, we need to define an appropriate 
way to pass the per operation HFN for each packet.

>>    Security API
>>    ~~~~~~~~~~~~
>> diff --git a/lib/librte_security/rte_security.c b/lib/librte_security/rte_security.c
>> index 1954960a5..c6355de95 100644
>> --- a/lib/librte_security/rte_security.c
>> +++ b/lib/librte_security/rte_security.c
>> @@ -131,6 +131,10 @@ rte_security_capability_get(struct rte_security_ctx *instance,
>>                                           capability->ipsec.direction ==
>>                                                           idx->ipsec.direction)
>>                                           return capability;
>> +                       } else if (idx->protocol == RTE_SECURITY_PROTOCOL_PDCP) {
>> +                               if (capability->pdcp.domain ==
>> +                                                       idx->pdcp.domain)
>> +                                       return capability;
>>                           }
>>                   }
>>           }
>> diff --git a/lib/librte_security/rte_security.h b/lib/librte_security/rte_security.h
>> index b0d1b97ee..e625bc656 100644
>> --- a/lib/librte_security/rte_security.h
>> +++ b/lib/librte_security/rte_security.h
>> @@ -206,6 +206,52 @@ struct rte_security_macsec_xform {
>>           int dummy;
>>    };
>> +/**
>> + * PDCP Mode of session
>> + */
>> +enum rte_security_pdcp_domain {
>> +       RTE_SECURITY_PDCP_MODE_CONTROL, /**< PDCP control plane */
>> +       RTE_SECURITY_PDCP_MODE_DATA,    /**< PDCP data plane */
>> +};
>> +
>> +/** PDCP Frame direction */
>> +enum rte_security_pdcp_direction {
>> +       RTE_SECURITY_PDCP_UPLINK,       /**< Uplink */
>> +       RTE_SECURITY_PDCP_DOWNLINK,     /**< Downlink */
>> +};
>> +
>> +/**
>> + * PDCP Sequence Number Size selectors
>> + * @PDCP_SN_SIZE_5: 5bit sequence number
>> + * @PDCP_SN_SIZE_7: 7bit sequence number
>> + * @PDCP_SN_SIZE_12: 12bit sequence number
>> + * @PDCP_SN_SIZE_15: 15bit sequence number
>> + */
>> +enum rte_security_pdcp_sn_size {
>> +       RTE_SECURITY_PDCP_SN_SIZE_5 = 5,
>> +       RTE_SECURITY_PDCP_SN_SIZE_7 = 7,
>> +       RTE_SECURITY_PDCP_SN_SIZE_12 = 12,
>> +       RTE_SECURITY_PDCP_SN_SIZE_15 = 15
>> +};
> [Anoob] SN size 18 is also possible
Will add this.


-Akhil

^ permalink raw reply	[flat|nested] 41+ messages in thread

* [dpdk-dev] [PATCH v2 0/3] security: support for pdcp
  2018-08-28 13:01 [dpdk-dev] [PATCH 0/3] security: support for pdcp akhil.goyal
                   ` (3 preceding siblings ...)
  2018-08-30  6:46 ` [dpdk-dev] [PATCH 0/3] security: support for pdcp Akhil Goyal
@ 2018-10-05 13:33 ` akhil.goyal
  2018-10-05 13:33   ` [dpdk-dev] [PATCH v2 1/3] security: support pdcp protocol akhil.goyal
                     ` (3 more replies)
  4 siblings, 4 replies; 41+ messages in thread
From: akhil.goyal @ 2018-10-05 13:33 UTC (permalink / raw)
  To: dev
  Cc: pablo.de.lara.guarch, radu.nicolau, jerin.jacob,
	narayanaprasad.athreya, Shally.Verma, Anoob.Joseph,
	Vidya.Velumuri, hemant.agrawal, Akhil Goyal

From: Akhil Goyal <akhil.goyal@nxp.com>

Security library currently only has support for IPSec protocol.
This patchset defines structures for pdcp protocol in rte_security
and provide a sample driver implementation for lookaside protocol
offload to support PDCP.

changes in v2:
- removed hfn override. Will be added later when it is supported
- added seq number size = 18bits
- coding style issues corrected in pdcp.h
- updated documentation for specifying the 3GPP specification reference
- removed some duplicate code in dpaa2_sec_dpseci.c


Akhil Goyal (3):
  security: support pdcp protocol
  crypto/dpaa2_sec: add sample pdcp descriptor apis
  crypto/dpaa2_sec: support pdcp offload

 doc/guides/prog_guide/rte_security.rst      |   96 +-
 drivers/crypto/dpaa2_sec/dpaa2_sec_dpseci.c |  233 ++
 drivers/crypto/dpaa2_sec/dpaa2_sec_priv.h   |  172 ++
 drivers/crypto/dpaa2_sec/hw/desc.h          |    2 +-
 drivers/crypto/dpaa2_sec/hw/desc/pdcp.h     | 2662 +++++++++++++++++++
 lib/librte_security/rte_security.c          |    4 +
 lib/librte_security/rte_security.h          |   67 +
 7 files changed, 3228 insertions(+), 8 deletions(-)
 create mode 100644 drivers/crypto/dpaa2_sec/hw/desc/pdcp.h

-- 
2.17.1

^ permalink raw reply	[flat|nested] 41+ messages in thread

* [dpdk-dev] [PATCH v2 1/3] security: support pdcp protocol
  2018-10-05 13:33 ` [dpdk-dev] [PATCH v2 " akhil.goyal
@ 2018-10-05 13:33   ` akhil.goyal
  2018-10-05 13:33   ` [dpdk-dev] [PATCH v2 2/3] crypto/dpaa2_sec: add sample pdcp descriptor apis akhil.goyal
                     ` (2 subsequent siblings)
  3 siblings, 0 replies; 41+ messages in thread
From: akhil.goyal @ 2018-10-05 13:33 UTC (permalink / raw)
  To: dev
  Cc: pablo.de.lara.guarch, radu.nicolau, jerin.jacob,
	narayanaprasad.athreya, Shally.Verma, Anoob.Joseph,
	Vidya.Velumuri, hemant.agrawal, Akhil Goyal

From: Akhil Goyal <akhil.goyal@nxp.com>

Packet Data Convergence Protocol (PDCP) is added in rte_security
for 3GPP TS 36.323 for LTE.

The patchset provide the structure definitions for configuring the
PDCP sessions and relevant documentation is added.

Signed-off-by: Hemant Agrawal <hemant.agrawal@nxp.com>
Signed-off-by: Akhil Goyal <akhil.goyal@nxp.com>
---
 doc/guides/prog_guide/rte_security.rst | 96 ++++++++++++++++++++++++--
 lib/librte_security/rte_security.c     |  4 ++
 lib/librte_security/rte_security.h     | 67 ++++++++++++++++++
 3 files changed, 160 insertions(+), 7 deletions(-)

diff --git a/doc/guides/prog_guide/rte_security.rst b/doc/guides/prog_guide/rte_security.rst
index 0812abe77..83d9d99e0 100644
--- a/doc/guides/prog_guide/rte_security.rst
+++ b/doc/guides/prog_guide/rte_security.rst
@@ -10,8 +10,8 @@ The security library provides a framework for management and provisioning
 of security protocol operations offloaded to hardware based devices. The
 library defines generic APIs to create and free security sessions which can
 support full protocol offload as well as inline crypto operation with
-NIC or crypto devices. The framework currently only supports the IPSec protocol
-and associated operations, other protocols will be added in future.
+NIC or crypto devices. The framework currently only supports the IPSec and PDCP
+protocol and associated operations, other protocols will be added in future.
 
 Design Principles
 -----------------
@@ -253,6 +253,49 @@ for any protocol header addition.
         +--------|--------+
                  V
 
+PDCP Flow Diagram
+~~~~~~~~~~~~~~~~~
+
+Based on 3GPP TS 36.323 Evolved Universal Terrestrial Radio Access (E-UTRA);
+Packet Data Convergence Protocol (PDCP) specification
+
+.. code-block:: c
+
+        Transmitting PDCP Entity          Receiving PDCP Entity
+                  |                                   ^
+                  |                       +-----------|-----------+
+                  V                       | In order delivery and |
+        +---------|----------+            | Duplicate detection   |
+        | Sequence Numbering |            |  (Data Plane only)    |
+        +---------|----------+            +-----------|-----------+
+                  |                                   |
+        +---------|----------+            +-----------|----------+
+        | Header Compression*|            | Header Decompression*|
+        | (Data-Plane only)  |            |   (Data Plane only)  |
+        +---------|----------+            +-----------|----------+
+                  |                                   |
+        +---------|-----------+           +-----------|----------+
+        | Integrity Protection|           |Integrity Verification|
+        | (Control Plane only)|           | (Control Plane only) |
+        +---------|-----------+           +-----------|----------+
+        +---------|-----------+            +----------|----------+
+        |     Ciphering       |            |     Deciphering     |
+        +---------|-----------+            +----------|----------+
+        +---------|-----------+            +----------|----------+
+        |   Add PDCP header   |            | Remove PDCP Header  |
+        +---------|-----------+            +----------|----------+
+                  |                                   |
+                  +----------------->>----------------+
+
+
+.. note::
+
+    * Header Compression and decompression are not supported currently.
+
+Just like IPSec, in case of PDCP also header addition/deletion, cipher/
+de-cipher, integrity protection/verification is done based on the action
+type chosen.
+
 Device Features and Capabilities
 ---------------------------------
 
@@ -271,7 +314,7 @@ structure in the *DPDK API Reference*.
 
 Each driver (crypto or ethernet) defines its own private array of capabilities
 for the operations it supports. Below is an example of the capabilities for a
-PMD which supports the IPSec protocol.
+PMD which supports the IPSec and PDCP protocol.
 
 .. code-block:: c
 
@@ -298,6 +341,22 @@ PMD which supports the IPSec protocol.
                 },
                 .crypto_capabilities = pmd_capabilities
         },
+        { /* PDCP Lookaside Protocol offload Data Plane */
+                .action = RTE_SECURITY_ACTION_TYPE_LOOKASIDE_PROTOCOL,
+                .protocol = RTE_SECURITY_PROTOCOL_PDCP,
+                .pdcp = {
+                        .domain = RTE_SECURITY_PDCP_MODE_DATA,
+                },
+                .crypto_capabilities = pmd_capabilities
+        },
+        { /* PDCP Lookaside Protocol offload Control */
+                .action = RTE_SECURITY_ACTION_TYPE_LOOKASIDE_PROTOCOL,
+                .protocol = RTE_SECURITY_PROTOCOL_PDCP,
+                .pdcp = {
+                        .domain = RTE_SECURITY_PDCP_MODE_CONTROL,
+                },
+                .crypto_capabilities = pmd_capabilities
+        },
         {
                 .action = RTE_SECURITY_ACTION_TYPE_NONE
         }
@@ -429,6 +488,7 @@ Security Session configuration structure is defined as ``rte_security_session_co
         union {
                 struct rte_security_ipsec_xform ipsec;
                 struct rte_security_macsec_xform macsec;
+                struct rte_security_pdcp_xform pdcp;
         };
         /**< Configuration parameters for security session */
         struct rte_crypto_sym_xform *crypto_xform;
@@ -463,15 +523,17 @@ The ``rte_security_session_protocol`` is defined as
 .. code-block:: c
 
     enum rte_security_session_protocol {
-        RTE_SECURITY_PROTOCOL_IPSEC,
+        RTE_SECURITY_PROTOCOL_IPSEC = 1,
         /**< IPsec Protocol */
         RTE_SECURITY_PROTOCOL_MACSEC,
         /**< MACSec Protocol */
+        RTE_SECURITY_PROTOCOL_PDCP,
+        /**< PDCP Protocol */
     };
 
-Currently the library defines configuration parameters for IPSec only. For other
-protocols like MACSec, structures and enums are defined as place holders which
-will be updated in the future.
+Currently the library defines configuration parameters for IPSec and PDCP only.
+For other protocols like MACSec, structures and enums are defined as place holders
+which will be updated in the future.
 
 IPsec related configuration parameters are defined in ``rte_security_ipsec_xform``
 
@@ -494,6 +556,26 @@ IPsec related configuration parameters are defined in ``rte_security_ipsec_xform
         /**< Tunnel parameters, NULL for transport mode */
     };
 
+PDCP related configuration parameters are defined in ``rte_security_pdcp_xform``
+
+.. code-block:: c
+
+    struct rte_security_pdcp_xform {
+        int8_t bearer;	/**< PDCP bearer ID */
+        /** < PDCP mode of operation: Control or data */
+        enum rte_security_pdcp_domain domain;
+        /**< PDCP Frame Direction 0:UL 1:DL */
+        enum rte_security_pdcp_direction pkt_dir;
+        /**< Sequence number size, 5/7/12/15/18 */
+        enum rte_security_pdcp_sn_size sn_size;
+        /**< Starting Hyper Frame Number to be used together with the SN
+         * from the PDCP frames
+         */
+        uint32_t hfn;
+        /**< HFN Threashold for key renegotiation */
+        uint32_t hfn_threshold;
+    };
+
 
 Security API
 ~~~~~~~~~~~~
diff --git a/lib/librte_security/rte_security.c b/lib/librte_security/rte_security.c
index 1954960a5..c6355de95 100644
--- a/lib/librte_security/rte_security.c
+++ b/lib/librte_security/rte_security.c
@@ -131,6 +131,10 @@ rte_security_capability_get(struct rte_security_ctx *instance,
 					capability->ipsec.direction ==
 							idx->ipsec.direction)
 					return capability;
+			} else if (idx->protocol == RTE_SECURITY_PROTOCOL_PDCP) {
+				if (capability->pdcp.domain ==
+							idx->pdcp.domain)
+					return capability;
 			}
 		}
 	}
diff --git a/lib/librte_security/rte_security.h b/lib/librte_security/rte_security.h
index b0d1b97ee..b3565c612 100644
--- a/lib/librte_security/rte_security.h
+++ b/lib/librte_security/rte_security.h
@@ -206,6 +206,57 @@ struct rte_security_macsec_xform {
 	int dummy;
 };
 
+/**
+ * PDCP Mode of session
+ */
+enum rte_security_pdcp_domain {
+	RTE_SECURITY_PDCP_MODE_CONTROL,	/**< PDCP control plane */
+	RTE_SECURITY_PDCP_MODE_DATA,	/**< PDCP data plane */
+};
+
+/** PDCP Frame direction */
+enum rte_security_pdcp_direction {
+	RTE_SECURITY_PDCP_UPLINK,	/**< Uplink */
+	RTE_SECURITY_PDCP_DOWNLINK,	/**< Downlink */
+};
+
+/**
+ * PDCP Sequence Number Size selectors
+ * @PDCP_SN_SIZE_5: 5bit sequence number
+ * @PDCP_SN_SIZE_7: 7bit sequence number
+ * @PDCP_SN_SIZE_12: 12bit sequence number
+ * @PDCP_SN_SIZE_15: 15bit sequence number
+ * @PDCP_SN_SIZE_18: 18bit sequence number
+ */
+enum rte_security_pdcp_sn_size {
+	RTE_SECURITY_PDCP_SN_SIZE_5 = 5,
+	RTE_SECURITY_PDCP_SN_SIZE_7 = 7,
+	RTE_SECURITY_PDCP_SN_SIZE_12 = 12,
+	RTE_SECURITY_PDCP_SN_SIZE_15 = 15,
+	RTE_SECURITY_PDCP_SN_SIZE_18 = 18
+};
+
+/**
+ * PDCP security association configuration data.
+ *
+ * This structure contains data required to create a PDCP security session.
+ */
+struct rte_security_pdcp_xform {
+	int8_t bearer;	/**< PDCP bearer ID */
+	/** < PDCP mode of operation: Control or data */
+	enum rte_security_pdcp_domain domain;
+	/**< PDCP Frame Direction 0:UL 1:DL */
+	enum rte_security_pdcp_direction pkt_dir;
+	/**< Sequence number size, 5/7/12/15/18 */
+	enum rte_security_pdcp_sn_size sn_size;
+	/**< Starting Hyper Frame Number to be used together with the SN
+	 * from the PDCP frames
+	 */
+	uint32_t hfn;
+	/**< HFN Threshold for key renegotiation */
+	uint32_t hfn_threshold;
+};
+
 /**
  * Security session action type.
  */
@@ -232,6 +283,8 @@ enum rte_security_session_protocol {
 	/**< IPsec Protocol */
 	RTE_SECURITY_PROTOCOL_MACSEC,
 	/**< MACSec Protocol */
+	RTE_SECURITY_PROTOCOL_PDCP,
+	/**< PDCP Protocol */
 };
 
 /**
@@ -246,6 +299,7 @@ struct rte_security_session_conf {
 	union {
 		struct rte_security_ipsec_xform ipsec;
 		struct rte_security_macsec_xform macsec;
+		struct rte_security_pdcp_xform pdcp;
 	};
 	/**< Configuration parameters for security session */
 	struct rte_crypto_sym_xform *crypto_xform;
@@ -413,6 +467,10 @@ struct rte_security_ipsec_stats {
 
 };
 
+struct rte_security_pdcp_stats {
+	uint64_t reserved;
+};
+
 struct rte_security_stats {
 	enum rte_security_session_protocol protocol;
 	/**< Security protocol to be configured */
@@ -421,6 +479,7 @@ struct rte_security_stats {
 	union {
 		struct rte_security_macsec_stats macsec;
 		struct rte_security_ipsec_stats ipsec;
+		struct rte_security_pdcp_stats pdcp;
 	};
 };
 
@@ -465,6 +524,11 @@ struct rte_security_capability {
 			int dummy;
 		} macsec;
 		/**< MACsec capability */
+		struct {
+			enum rte_security_pdcp_domain domain;
+			/** < PDCP mode of operation: Control or data */
+		} pdcp;
+		/**< PDCP capability */
 	};
 
 	const struct rte_cryptodev_capabilities *crypto_capabilities;
@@ -506,6 +570,9 @@ struct rte_security_capability_idx {
 			enum rte_security_ipsec_sa_mode mode;
 			enum rte_security_ipsec_sa_direction direction;
 		} ipsec;
+		struct {
+			enum rte_security_pdcp_domain domain;
+		} pdcp;
 	};
 };
 
-- 
2.17.1

^ permalink raw reply	[flat|nested] 41+ messages in thread

* [dpdk-dev] [PATCH v2 2/3] crypto/dpaa2_sec: add sample pdcp descriptor apis
  2018-10-05 13:33 ` [dpdk-dev] [PATCH v2 " akhil.goyal
  2018-10-05 13:33   ` [dpdk-dev] [PATCH v2 1/3] security: support pdcp protocol akhil.goyal
@ 2018-10-05 13:33   ` akhil.goyal
  2018-10-05 13:33   ` [dpdk-dev] [PATCH v2 3/3] crypto/dpaa2_sec: support pdcp offload akhil.goyal
  2018-10-05 13:53   ` [dpdk-dev] [PATCH v3 0/3] security: support for pdcp akhil.goyal
  3 siblings, 0 replies; 41+ messages in thread
From: akhil.goyal @ 2018-10-05 13:33 UTC (permalink / raw)
  To: dev
  Cc: pablo.de.lara.guarch, radu.nicolau, jerin.jacob,
	narayanaprasad.athreya, Shally.Verma, Anoob.Joseph,
	Vidya.Velumuri, hemant.agrawal, Akhil Goyal

From: Akhil Goyal <akhil.goyal@nxp.com>

DPAA2 SEC platform can support look aside protocol
offload for PDCP protocol.

The relevant APIs for configuring the hardware for PDCP
is added for various modes and crypto algorithms.

Signed-off-by: Hemant Agrawal <hemant.agrawal@nxp.com>
Signed-off-by: Horia Geanta Neag <horia.geanta@nxp.com>
Signed-off-by: Alex Porosanu <alexandru.porosanu@nxp.com>
Signed-off-by: Akhil Goyal <akhil.goyal@nxp.com>
---
 drivers/crypto/dpaa2_sec/hw/desc.h      |    2 +-
 drivers/crypto/dpaa2_sec/hw/desc/pdcp.h | 2662 +++++++++++++++++++++++
 2 files changed, 2663 insertions(+), 1 deletion(-)
 create mode 100644 drivers/crypto/dpaa2_sec/hw/desc/pdcp.h

diff --git a/drivers/crypto/dpaa2_sec/hw/desc.h b/drivers/crypto/dpaa2_sec/hw/desc.h
index ca94ea3ff..5d99dd8af 100644
--- a/drivers/crypto/dpaa2_sec/hw/desc.h
+++ b/drivers/crypto/dpaa2_sec/hw/desc.h
@@ -868,7 +868,7 @@
 #define OP_PCL_LTE_MIXED_AUTH_SHIFT	0
 #define OP_PCL_LTE_MIXED_AUTH_MASK	(3 << OP_PCL_LTE_MIXED_AUTH_SHIFT)
 #define OP_PCL_LTE_MIXED_ENC_SHIFT	8
-#define OP_PCL_LTE_MIXED_ENC_MASK	(3 < OP_PCL_LTE_MIXED_ENC_SHIFT)
+#define OP_PCL_LTE_MIXED_ENC_MASK	(3 << OP_PCL_LTE_MIXED_ENC_SHIFT)
 #define OP_PCL_LTE_MIXED_AUTH_NULL	(OP_PCL_LTE_NULL << \
 					 OP_PCL_LTE_MIXED_AUTH_SHIFT)
 #define OP_PCL_LTE_MIXED_AUTH_SNOW	(OP_PCL_LTE_SNOW << \
diff --git a/drivers/crypto/dpaa2_sec/hw/desc/pdcp.h b/drivers/crypto/dpaa2_sec/hw/desc/pdcp.h
new file mode 100644
index 000000000..d47f4df1b
--- /dev/null
+++ b/drivers/crypto/dpaa2_sec/hw/desc/pdcp.h
@@ -0,0 +1,2662 @@
+/*
+ * Copyright 2008-2013 Freescale Semiconductor, Inc.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause or GPL-2.0+
+ */
+
+#ifndef __DESC_PDCP_H__
+#define __DESC_PDCP_H__
+
+#include "hw/rta.h"
+#include "common.h"
+
+/**
+ * DOC: PDCP Shared Descriptor Constructors
+ *
+ * Shared descriptors for PDCP protocol.
+ */
+
+/**
+ * PDCP_NULL_MAX_FRAME_LEN - The maximum frame frame length that is supported by
+ *                           PDCP NULL protocol.
+ */
+#define PDCP_NULL_MAX_FRAME_LEN		0x00002FFF
+
+/**
+ * PDCP_MAC_I_LEN - The length of the MAC-I for PDCP protocol operation
+ */
+#define PDCP_MAC_I_LEN			0x00000004
+
+/**
+ * PDCP_MAX_FRAME_LEN_STATUS - The status returned in FD status/command field in
+ *                             case the input frame is larger than
+ *                             PDCP_NULL_MAX_FRAME_LEN.
+ */
+#define PDCP_MAX_FRAME_LEN_STATUS	0xF1
+
+/**
+ * PDCP_C_PLANE_SN_MASK - This mask is used in the PDCP descriptors for
+ *                        extracting the sequence number (SN) from the PDCP
+ *                        Control Plane header. For PDCP Control Plane, the SN
+ *                        is constant (5 bits) as opposed to PDCP Data Plane
+ *                        (7/12/15 bits).
+ */
+#define PDCP_C_PLANE_SN_MASK		0x0000001F
+
+/**
+ * PDCP_U_PLANE_15BIT_SN_MASK - This mask is used in the PDCP descriptors for
+ *                              extracting the sequence number (SN) from the
+ *                              PDCP User Plane header. For PDCP Control Plane,
+ *                              the SN is constant (5 bits) as opposed to PDCP
+ *                              Data Plane (7/12/15 bits).
+ */
+#define PDCP_U_PLANE_15BIT_SN_MASK	0x00007FFF
+
+/**
+ * PDCP_BEARER_MASK - This mask is used masking out the bearer for PDCP
+ *                    processing with SNOW f9 in LTE.
+ *
+ * The value on which this mask is applied is formatted as below:
+ *     Count-C (32 bit) | Bearer (5 bit) | Direction (1 bit) | 0 (26 bits)
+ *
+ * Applying this mask is done for creating the upper 64 bits of the IV needed
+ * for SNOW f9.
+ *
+ * The lower 32 bits of the mask are used for masking the direction for AES
+ * CMAC IV.
+ */
+#define PDCP_BEARER_MASK		0xFFFFFFFF04000000ull
+
+/**
+ * PDCP_DIR_MASK - This mask is used masking out the direction for PDCP
+ *                 processing with SNOW f9 in LTE.
+ *
+ * The value on which this mask is applied is formatted as below:
+ *     Bearer (5 bit) | Direction (1 bit) | 0 (26 bits)
+ *
+ * Applying this mask is done for creating the lower 32 bits of the IV needed
+ * for SNOW f9.
+ *
+ * The upper 32 bits of the mask are used for masking the direction for AES
+ * CMAC IV.
+ */
+#define PDCP_DIR_MASK			0xF800000000000000ull
+
+/**
+ * PDCP_NULL_INT_MAC_I_VAL - The value of the PDCP PDU MAC-I in case NULL
+ *                           integrity is used.
+ */
+
+#define PDCP_NULL_INT_MAC_I_VAL		0x00000000
+
+/**
+ * PDCP_NULL_INT_ICV_CHECK_FAILED_STATUS - The status used to report ICV check
+ *                                         failed in case of NULL integrity
+ *                                         Control Plane processing.
+ */
+#define PDCP_NULL_INT_ICV_CHECK_FAILED_STATUS	0x0A
+/**
+ * PDCP_DPOVRD_HFN_OV_EN - Value to be used in the FD status/cmd field to
+ *                         indicate the HFN override mechanism is active for the
+ *                         frame.
+ */
+#define PDCP_DPOVRD_HFN_OV_EN		0x80000000
+
+/**
+ * PDCP_P4080REV2_HFN_OV_BUFLEN - The length in bytes of the supplementary space
+ *                                that must be provided by the user at the
+ *                                beginning of the input frame buffer for
+ *                                P4080 REV 2.
+ *
+ * The format of the frame buffer is the following:
+ *
+ *  |<---PDCP_P4080REV2_HFN_OV_BUFLEN-->|
+ * //===================================||============||==============\\
+ * || PDCP_DPOVRD_HFN_OV_EN | HFN value || PDCP Header|| PDCP Payload ||
+ * \\===================================||============||==============//
+ *
+ * If HFN override mechanism is not desired, then the MSB of the first 4 bytes
+ * must be set to 0b.
+ */
+#define PDCP_P4080REV2_HFN_OV_BUFLEN	4
+
+/**
+ * enum cipher_type_pdcp - Type selectors for cipher types in PDCP protocol OP
+ *                         instructions.
+ * @PDCP_CIPHER_TYPE_NULL: NULL
+ * @PDCP_CIPHER_TYPE_SNOW: SNOW F8
+ * @PDCP_CIPHER_TYPE_AES: AES
+ * @PDCP_CIPHER_TYPE_ZUC: ZUCE
+ * @PDCP_CIPHER_TYPE_INVALID: invalid option
+ */
+enum cipher_type_pdcp {
+	PDCP_CIPHER_TYPE_NULL,
+	PDCP_CIPHER_TYPE_SNOW,
+	PDCP_CIPHER_TYPE_AES,
+	PDCP_CIPHER_TYPE_ZUC,
+	PDCP_CIPHER_TYPE_INVALID
+};
+
+/**
+ * enum auth_type_pdcp - Type selectors for integrity types in PDCP protocol OP
+ *                       instructions.
+ * @PDCP_AUTH_TYPE_NULL: NULL
+ * @PDCP_AUTH_TYPE_SNOW: SNOW F9
+ * @PDCP_AUTH_TYPE_AES: AES CMAC
+ * @PDCP_AUTH_TYPE_ZUC: ZUCA
+ * @PDCP_AUTH_TYPE_INVALID: invalid option
+ */
+enum auth_type_pdcp {
+	PDCP_AUTH_TYPE_NULL,
+	PDCP_AUTH_TYPE_SNOW,
+	PDCP_AUTH_TYPE_AES,
+	PDCP_AUTH_TYPE_ZUC,
+	PDCP_AUTH_TYPE_INVALID
+};
+
+/**
+ * enum pdcp_dir - Type selectors for direction for PDCP protocol
+ * @PDCP_DIR_UPLINK: uplink direction
+ * @PDCP_DIR_DOWNLINK: downlink direction
+ * @PDCP_DIR_INVALID: invalid option
+ */
+enum pdcp_dir {
+	PDCP_DIR_UPLINK = 0,
+	PDCP_DIR_DOWNLINK = 1,
+	PDCP_DIR_INVALID
+};
+
+/**
+ * enum pdcp_plane - PDCP domain selectors
+ * @PDCP_CONTROL_PLANE: Control Plane
+ * @PDCP_DATA_PLANE: Data Plane
+ * @PDCP_SHORT_MAC: Short MAC
+ */
+enum pdcp_plane {
+	PDCP_CONTROL_PLANE,
+	PDCP_DATA_PLANE,
+	PDCP_SHORT_MAC
+};
+
+/**
+ * enum pdcp_sn_size - Sequence Number Size selectors for PDCP protocol
+ * @PDCP_SN_SIZE_5: 5bit sequence number
+ * @PDCP_SN_SIZE_7: 7bit sequence number
+ * @PDCP_SN_SIZE_12: 12bit sequence number
+ * @PDCP_SN_SIZE_15: 15bit sequence number
+ * @PDCP_SN_SIZE_18: 18bit sequence number
+ */
+enum pdcp_sn_size {
+	PDCP_SN_SIZE_5 = 5,
+	PDCP_SN_SIZE_7 = 7,
+	PDCP_SN_SIZE_12 = 12,
+	PDCP_SN_SIZE_15 = 15
+};
+
+/*
+ * PDCP Control Plane Protocol Data Blocks
+ */
+#define PDCP_C_PLANE_PDB_HFN_SHIFT		5
+#define PDCP_C_PLANE_PDB_BEARER_SHIFT		27
+#define PDCP_C_PLANE_PDB_DIR_SHIFT		26
+#define PDCP_C_PLANE_PDB_HFN_THR_SHIFT		5
+
+#define PDCP_U_PLANE_PDB_OPT_SHORT_SN		0x2
+#define PDCP_U_PLANE_PDB_OPT_15B_SN		0x4
+#define PDCP_U_PLANE_PDB_SHORT_SN_HFN_SHIFT	7
+#define PDCP_U_PLANE_PDB_LONG_SN_HFN_SHIFT	12
+#define PDCP_U_PLANE_PDB_15BIT_SN_HFN_SHIFT	15
+#define PDCP_U_PLANE_PDB_BEARER_SHIFT		27
+#define PDCP_U_PLANE_PDB_DIR_SHIFT		26
+#define PDCP_U_PLANE_PDB_SHORT_SN_HFN_THR_SHIFT	7
+#define PDCP_U_PLANE_PDB_LONG_SN_HFN_THR_SHIFT	12
+#define PDCP_U_PLANE_PDB_15BIT_SN_HFN_THR_SHIFT	15
+
+struct pdcp_pdb {
+	union {
+		uint32_t opt;
+		uint32_t rsvd;
+	} opt_res;
+	uint32_t hfn_res;	/* HyperFrame number,(27, 25 or 21 bits),
+				 * left aligned & right-padded with zeros. */
+	uint32_t bearer_dir_res;/* Bearer(5 bits), packet direction (1 bit),
+				 * left aligned & right-padded with zeros. */
+	uint32_t hfn_thr_res;	/* HyperFrame number threshold (27, 25 or 21
+				 * bits), left aligned & right-padded with
+				 * zeros. */
+};
+
+/*
+ * PDCP internal PDB types
+ */
+enum pdb_type_e {
+	PDCP_PDB_TYPE_NO_PDB,
+	PDCP_PDB_TYPE_FULL_PDB,
+	PDCP_PDB_TYPE_REDUCED_PDB,
+	PDCP_PDB_TYPE_INVALID
+};
+
+/*
+ * Function for appending the portion of a PDCP Control Plane shared descriptor
+ * which performs NULL encryption and integrity (i.e. copies the input frame
+ * to the output frame, appending 32 bits of zeros at the end (MAC-I for
+ * NULL integrity).
+ */
+static inline int
+pdcp_insert_cplane_null_op(struct program *p,
+			   struct alginfo *cipherdata __maybe_unused,
+			   struct alginfo *authdata __maybe_unused,
+			   unsigned dir,
+			   unsigned char era_2_sw_hfn_ovrd __maybe_unused)
+{
+	LABEL(local_offset);
+	REFERENCE(move_cmd_read_descbuf);
+	REFERENCE(move_cmd_write_descbuf);
+
+	if (rta_sec_era > RTA_SEC_ERA_2) {
+		MATHB(p, SEQINSZ, ADD, ZERO, VSEQINSZ, 4, 0);
+		if (dir == OP_TYPE_ENCAP_PROTOCOL)
+			MATHB(p, SEQINSZ, ADD, PDCP_MAC_I_LEN, VSEQOUTSZ, 4,
+			      IMMED2);
+		else
+			MATHB(p, SEQINSZ, SUB, PDCP_MAC_I_LEN, VSEQOUTSZ, 4,
+			      IMMED2);
+	} else {
+		MATHB(p, SEQINSZ, ADD, ONE, VSEQINSZ, 4, 0);
+		MATHB(p, VSEQINSZ, SUB, ONE, VSEQINSZ, 4, 0);
+
+		if (dir == OP_TYPE_ENCAP_PROTOCOL) {
+			MATHB(p, SEQINSZ, ADD, PDCP_MAC_I_LEN, VSEQOUTSZ, 4,
+			      IMMED2);
+			MATHB(p, VSEQINSZ, SUB, ONE, MATH0, 4, 0);
+		} else {
+			MATHB(p, VSEQINSZ, SUB, PDCP_MAC_I_LEN, VSEQINSZ, 4,
+			      IMMED2);
+			MATHB(p, SEQINSZ, SUB, PDCP_MAC_I_LEN, VSEQOUTSZ, 4,
+			      IMMED2);
+			MATHB(p, VSEQOUTSZ, SUB, ONE, MATH0, 4, 0);
+		}
+
+		MATHB(p, MATH0, ADD, ONE, MATH0, 4, 0);
+
+		/*
+		 * Since MOVELEN is available only starting with
+		 * SEC ERA 3, use poor man's MOVELEN: create a MOVE
+		 * command dynamically by writing the length from M1 by
+		 * OR-ing the command in the M1 register and MOVE the
+		 * result into the descriptor buffer. Care must be taken
+		 * wrt. the location of the command because of SEC
+		 * pipelining. The actual MOVEs are written at the end
+		 * of the descriptor due to calculations needed on the
+		 * offset in the descriptor for the MOVE command.
+		 */
+		move_cmd_read_descbuf = MOVE(p, DESCBUF, 0, MATH0, 0, 6,
+					     IMMED);
+		move_cmd_write_descbuf = MOVE(p, MATH0, 0, DESCBUF, 0, 8,
+					      WAITCOMP | IMMED);
+	}
+	MATHB(p, VSEQINSZ, SUB, PDCP_NULL_MAX_FRAME_LEN, NONE, 4,
+	      IMMED2);
+	JUMP(p, PDCP_MAX_FRAME_LEN_STATUS, HALT_STATUS, ALL_FALSE, MATH_N);
+
+	if (rta_sec_era > RTA_SEC_ERA_2) {
+		if (dir == OP_TYPE_ENCAP_PROTOCOL)
+			MATHB(p, VSEQINSZ, ADD, ZERO, MATH0, 4, 0);
+		else
+			MATHB(p, VSEQOUTSZ, ADD, ZERO, MATH0, 4, 0);
+	}
+	SEQFIFOSTORE(p, MSG, 0, 0, VLF);
+	SEQFIFOLOAD(p, MSG1, 0, VLF | LAST1 | FLUSH1);
+
+	if (rta_sec_era > RTA_SEC_ERA_2) {
+		MOVE(p, AB1, 0, OFIFO, 0, MATH0, 0);
+	} else {
+		SET_LABEL(p, local_offset);
+
+		/* Shut off automatic Info FIFO entries */
+		LOAD(p, 0, DCTRL, LDOFF_DISABLE_AUTO_NFIFO, 0, IMMED);
+		/* Placeholder for MOVE command with length from M1 register */
+		MOVE(p, IFIFOAB1, 0, OFIFO, 0, 0, IMMED);
+		/* Enable automatic Info FIFO entries */
+		LOAD(p, 0, DCTRL, LDOFF_ENABLE_AUTO_NFIFO, 0, IMMED);
+	}
+
+	if (dir == OP_TYPE_ENCAP_PROTOCOL) {
+		MATHB(p, MATH1, XOR, MATH1, MATH0, 8, 0);
+		MOVE(p, MATH0, 0, OFIFO, 0, 4, IMMED);
+	}
+
+	if (rta_sec_era < RTA_SEC_ERA_3) {
+		PATCH_MOVE(p, move_cmd_read_descbuf, local_offset);
+		PATCH_MOVE(p, move_cmd_write_descbuf, local_offset);
+	}
+
+	return 0;
+}
+
+static inline int
+insert_copy_frame_op(struct program *p,
+		     struct alginfo *cipherdata __maybe_unused,
+		     unsigned dir __maybe_unused)
+{
+	LABEL(local_offset);
+	REFERENCE(move_cmd_read_descbuf);
+	REFERENCE(move_cmd_write_descbuf);
+
+	if (rta_sec_era > RTA_SEC_ERA_2) {
+		MATHB(p, SEQINSZ, ADD, ZERO, VSEQINSZ,  4, 0);
+		MATHB(p, SEQINSZ, ADD, ZERO, VSEQOUTSZ,  4, 0);
+	} else {
+		MATHB(p, SEQINSZ, ADD, ONE, VSEQINSZ,  4, 0);
+		MATHB(p, VSEQINSZ, SUB, ONE, VSEQINSZ,  4, 0);
+		MATHB(p, SEQINSZ, ADD, ONE, VSEQOUTSZ,  4, 0);
+		MATHB(p, VSEQOUTSZ, SUB, ONE, VSEQOUTSZ,  4, 0);
+		MATHB(p, VSEQINSZ, SUB, ONE, MATH0,  4, 0);
+		MATHB(p, MATH0, ADD, ONE, MATH0,  4, 0);
+
+		/*
+		 * Since MOVELEN is available only starting with
+		 * SEC ERA 3, use poor man's MOVELEN: create a MOVE
+		 * command dynamically by writing the length from M1 by
+		 * OR-ing the command in the M1 register and MOVE the
+		 * result into the descriptor buffer. Care must be taken
+		 * wrt. the location of the command because of SEC
+		 * pipelining. The actual MOVEs are written at the end
+		 * of the descriptor due to calculations needed on the
+		 * offset in the descriptor for the MOVE command.
+		 */
+		move_cmd_read_descbuf = MOVE(p, DESCBUF, 0, MATH0, 0, 6,
+					     IMMED);
+		move_cmd_write_descbuf = MOVE(p, MATH0, 0, DESCBUF, 0, 8,
+					      WAITCOMP | IMMED);
+	}
+	MATHB(p, SEQINSZ, SUB, PDCP_NULL_MAX_FRAME_LEN, NONE,  4,
+	      IFB | IMMED2);
+	JUMP(p, PDCP_MAX_FRAME_LEN_STATUS, HALT_STATUS, ALL_FALSE, MATH_N);
+
+	if (rta_sec_era > RTA_SEC_ERA_2)
+		MATHB(p, VSEQINSZ, ADD, ZERO, MATH0,  4, 0);
+
+	SEQFIFOLOAD(p, MSG1, 0, VLF | LAST1 | FLUSH1);
+	if (rta_sec_era > RTA_SEC_ERA_2) {
+		MOVE(p, AB1, 0, OFIFO, 0, MATH0, 0);
+	} else {
+		SET_LABEL(p, local_offset);
+
+		/* Shut off automatic Info FIFO entries */
+		LOAD(p, 0, DCTRL, LDOFF_DISABLE_AUTO_NFIFO, 0, IMMED);
+
+		/* Placeholder for MOVE command with length from M0 register */
+		MOVE(p, IFIFOAB1, 0, OFIFO, 0, 0, IMMED);
+
+		/* Enable automatic Info FIFO entries */
+		LOAD(p, 0, DCTRL, LDOFF_ENABLE_AUTO_NFIFO, 0, IMMED);
+	}
+
+	SEQFIFOSTORE(p, MSG, 0, 0, VLF);
+
+	if (rta_sec_era < RTA_SEC_ERA_3) {
+		PATCH_MOVE(p, move_cmd_read_descbuf, local_offset);
+		PATCH_MOVE(p, move_cmd_write_descbuf, local_offset);
+	}
+	return 0;
+}
+
+static inline int
+pdcp_insert_cplane_int_only_op(struct program *p,
+			       struct alginfo *cipherdata __maybe_unused,
+			       struct alginfo *authdata, unsigned dir,
+			       unsigned char era_2_sw_hfn_ovrd)
+{
+	LABEL(local_offset);
+	REFERENCE(move_cmd_read_descbuf);
+	REFERENCE(move_cmd_write_descbuf);
+
+	switch (authdata->algtype) {
+	case PDCP_AUTH_TYPE_SNOW:
+		/* Insert Auth Key */
+		KEY(p, KEY2, authdata->key_enc_flags, authdata->key,
+		    authdata->keylen, INLINE_KEY(authdata));
+		SEQLOAD(p, MATH0, 7, 1, 0);
+		JUMP(p, 1, LOCAL_JUMP, ALL_TRUE, CALM);
+
+		if (rta_sec_era > RTA_SEC_ERA_2 ||
+		    (rta_sec_era == RTA_SEC_ERA_2 &&
+				   era_2_sw_hfn_ovrd == 0)) {
+			SEQINPTR(p, 0, 1, RTO);
+		} else {
+			SEQINPTR(p, 0, 5, RTO);
+			SEQFIFOLOAD(p, SKIP, 4, 0);
+		}
+
+		MATHB(p, MATH0, AND, PDCP_C_PLANE_SN_MASK, MATH1,  8,
+		      IFB | IMMED2);
+		MATHB(p, MATH1, SHLD, MATH1, MATH1,  8, 0);
+		MOVE(p, DESCBUF, 8, MATH2, 0, 8, WAITCOMP | IMMED);
+		MATHB(p, MATH2, AND, PDCP_BEARER_MASK, MATH2, 8,
+		      IMMED2);
+		MOVE(p, DESCBUF, 0x0C, MATH3, 0, 4, WAITCOMP | IMMED);
+		MATHB(p, MATH3, AND, PDCP_DIR_MASK, MATH3, 8,
+		      IMMED2);
+		MATHB(p, MATH1, OR, MATH2, MATH2, 8, 0);
+		MOVE(p, MATH2, 0, CONTEXT2, 0, 0x0C, WAITCOMP | IMMED);
+
+		if (dir == OP_TYPE_DECAP_PROTOCOL) {
+			MATHB(p, SEQINSZ, SUB, PDCP_MAC_I_LEN, MATH1, 4,
+			      IMMED2);
+		} else {
+			if (rta_sec_era > RTA_SEC_ERA_2) {
+				MATHB(p, SEQINSZ, SUB, ZERO, MATH1, 4,
+				      0);
+			} else {
+				MATHB(p, SEQINSZ, ADD, ONE, MATH1, 4,
+				      0);
+				MATHB(p, MATH1, SUB, ONE, MATH1, 4,
+				      0);
+			}
+		}
+
+		if (rta_sec_era > RTA_SEC_ERA_2) {
+			MATHB(p, MATH1, SUB, ZERO, VSEQINSZ, 4, 0);
+			MATHB(p, MATH1, SUB, ZERO, VSEQOUTSZ, 4, 0);
+		} else {
+			MATHB(p, ZERO, ADD, MATH1, VSEQINSZ, 4, 0);
+			MATHB(p, ZERO, ADD, MATH1, VSEQOUTSZ, 4, 0);
+
+			/*
+			 * Since MOVELEN is available only starting with
+			 * SEC ERA 3, use poor man's MOVELEN: create a MOVE
+			 * command dynamically by writing the length from M1 by
+			 * OR-ing the command in the M1 register and MOVE the
+			 * result into the descriptor buffer. Care must be taken
+			 * wrt. the location of the command because of SEC
+			 * pipelining. The actual MOVEs are written at the end
+			 * of the descriptor due to calculations needed on the
+			 * offset in the descriptor for the MOVE command.
+			 */
+			move_cmd_read_descbuf = MOVE(p, DESCBUF, 0, MATH1, 0, 6,
+						     IMMED);
+			move_cmd_write_descbuf = MOVE(p, MATH1, 0, DESCBUF, 0,
+						      8, WAITCOMP | IMMED);
+		}
+
+		SEQFIFOSTORE(p, MSG, 0, 0, VLF);
+		ALG_OPERATION(p, OP_ALG_ALGSEL_SNOW_F9, OP_ALG_AAI_F9,
+			      OP_ALG_AS_INITFINAL,
+			      dir == OP_TYPE_ENCAP_PROTOCOL ?
+				     ICV_CHECK_DISABLE : ICV_CHECK_ENABLE,
+			      DIR_ENC);
+
+		if (rta_sec_era > RTA_SEC_ERA_2) {
+			SEQFIFOLOAD(p, MSGINSNOOP, 0,
+				    VLF | LAST1 | LAST2 | FLUSH1);
+			MOVE(p, AB1, 0, OFIFO, 0, MATH1, 0);
+		} else {
+			SEQFIFOLOAD(p, MSGINSNOOP, 0,
+				    VLF | LAST1 | LAST2 | FLUSH1);
+			SET_LABEL(p, local_offset);
+
+			/* Shut off automatic Info FIFO entries */
+			LOAD(p, 0, DCTRL, LDOFF_DISABLE_AUTO_NFIFO, 0, IMMED);
+			/*
+			 * Placeholder for MOVE command with length from M1
+			 * register
+			 */
+			MOVE(p, IFIFOAB1, 0, OFIFO, 0, 0, IMMED);
+			/* Enable automatic Info FIFO entries */
+			LOAD(p, 0, DCTRL, LDOFF_ENABLE_AUTO_NFIFO, 0, IMMED);
+		}
+
+		if (dir == OP_TYPE_DECAP_PROTOCOL)
+			SEQFIFOLOAD(p, ICV2, 4, LAST2);
+		else
+			SEQSTORE(p, CONTEXT2, 0, 4, 0);
+
+		break;
+
+	case PDCP_AUTH_TYPE_AES:
+		/* Insert Auth Key */
+		KEY(p, KEY1, authdata->key_enc_flags, authdata->key,
+		    authdata->keylen, INLINE_KEY(authdata));
+		SEQLOAD(p, MATH0, 7, 1, 0);
+		JUMP(p, 1, LOCAL_JUMP, ALL_TRUE, CALM);
+		if (rta_sec_era > RTA_SEC_ERA_2 ||
+		    (rta_sec_era == RTA_SEC_ERA_2 &&
+		     era_2_sw_hfn_ovrd == 0)) {
+			SEQINPTR(p, 0, 1, RTO);
+		} else {
+			SEQINPTR(p, 0, 5, RTO);
+			SEQFIFOLOAD(p, SKIP, 4, 0);
+		}
+
+		MATHB(p, MATH0, AND, PDCP_C_PLANE_SN_MASK, MATH1, 8,
+		      IFB | IMMED2);
+		MATHB(p, MATH1, SHLD, MATH1, MATH1, 8, 0);
+		MOVE(p, DESCBUF, 8, MATH2, 0, 8, WAITCOMP | IMMED);
+		MATHB(p, MATH1, OR, MATH2, MATH2, 8, 0);
+		MOVE(p, MATH2, 0, IFIFOAB1, 0, 8, IMMED);
+		if (dir == OP_TYPE_DECAP_PROTOCOL) {
+			MATHB(p, SEQINSZ, SUB, PDCP_MAC_I_LEN, MATH1, 4,
+			      IMMED2);
+		} else {
+			if (rta_sec_era > RTA_SEC_ERA_2) {
+				MATHB(p, SEQINSZ, SUB, ZERO, MATH1, 4,
+				      0);
+			} else {
+				MATHB(p, SEQINSZ, ADD, ONE, MATH1, 4,
+				      0);
+				MATHB(p, MATH1, SUB, ONE, MATH1, 4,
+				      0);
+			}
+		}
+
+		if (rta_sec_era > RTA_SEC_ERA_2) {
+			MATHB(p, MATH1, SUB, ZERO, VSEQINSZ, 4, 0);
+			MATHB(p, MATH1, SUB, ZERO, VSEQOUTSZ, 4, 0);
+		} else {
+			MATHB(p, ZERO, ADD, MATH1, VSEQINSZ, 4, 0);
+			MATHB(p, ZERO, ADD, MATH1, VSEQOUTSZ, 4, 0);
+
+			/*
+			 * Since MOVELEN is available only starting with
+			 * SEC ERA 3, use poor man's MOVELEN: create a MOVE
+			 * command dynamically by writing the length from M1 by
+			 * OR-ing the command in the M1 register and MOVE the
+			 * result into the descriptor buffer. Care must be taken
+			 * wrt. the location of the command because of SEC
+			 * pipelining. The actual MOVEs are written at the end
+			 * of the descriptor due to calculations needed on the
+			 * offset in the descriptor for the MOVE command.
+			 */
+			move_cmd_read_descbuf = MOVE(p, DESCBUF, 0, MATH1, 0, 6,
+						     IMMED);
+			move_cmd_write_descbuf = MOVE(p, MATH1, 0, DESCBUF, 0,
+						      8, WAITCOMP | IMMED);
+		}
+		SEQFIFOSTORE(p, MSG, 0, 0, VLF);
+		ALG_OPERATION(p, OP_ALG_ALGSEL_AES,
+			      OP_ALG_AAI_CMAC,
+			      OP_ALG_AS_INITFINAL,
+			      dir == OP_TYPE_ENCAP_PROTOCOL ?
+				     ICV_CHECK_DISABLE : ICV_CHECK_ENABLE,
+			      DIR_ENC);
+
+		if (rta_sec_era > RTA_SEC_ERA_2) {
+			MOVE(p, AB2, 0, OFIFO, 0, MATH1, 0);
+			SEQFIFOLOAD(p, MSGINSNOOP, 0,
+				    VLF | LAST1 | LAST2 | FLUSH1);
+		} else {
+			SEQFIFOLOAD(p, MSGINSNOOP, 0,
+				    VLF | LAST1 | LAST2 | FLUSH1);
+			SET_LABEL(p, local_offset);
+
+			/* Shut off automatic Info FIFO entries */
+			LOAD(p, 0, DCTRL, LDOFF_DISABLE_AUTO_NFIFO, 0, IMMED);
+
+			/*
+			 * Placeholder for MOVE command with length from
+			 * M1 register
+			 * */
+			MOVE(p, IFIFOAB2, 0, OFIFO, 0, 0, IMMED);
+
+			/* Enable automatic Info FIFO entries */
+			LOAD(p, 0, DCTRL, LDOFF_ENABLE_AUTO_NFIFO, 0, IMMED);
+		}
+
+		if (dir == OP_TYPE_DECAP_PROTOCOL)
+			SEQFIFOLOAD(p, ICV1, 4, LAST1 | FLUSH1);
+		else
+			SEQSTORE(p, CONTEXT1, 0, 4, 0);
+
+		break;
+
+	case PDCP_AUTH_TYPE_ZUC:
+		if (rta_sec_era < RTA_SEC_ERA_5) {
+			pr_err("Invalid era for selected algorithm\n");
+			return -ENOTSUP;
+		}
+		/* Insert Auth Key */
+		KEY(p, KEY2, authdata->key_enc_flags, authdata->key,
+		    authdata->keylen, INLINE_KEY(authdata));
+		SEQLOAD(p, MATH0, 7, 1, 0);
+		JUMP(p, 1, LOCAL_JUMP, ALL_TRUE, CALM);
+		SEQINPTR(p, 0, 1, RTO);
+		MATHB(p, MATH0, AND, PDCP_C_PLANE_SN_MASK, MATH1, 8,
+		      IFB | IMMED2);
+		MATHB(p, MATH1, SHLD, MATH1, MATH1, 8, 0);
+		MOVE(p, DESCBUF, 8, MATH2, 0, 8, WAITCOMP | IMMED);
+		MATHB(p, MATH1, OR, MATH2, MATH2, 8, 0);
+		MOVE(p, MATH2, 0, CONTEXT2, 0, 8, IMMED);
+
+		if (dir == OP_TYPE_DECAP_PROTOCOL)
+			MATHB(p, SEQINSZ, SUB, PDCP_MAC_I_LEN, MATH1, 4,
+			      IMMED2);
+		else
+			MATHB(p, SEQINSZ, SUB, ZERO, MATH1, 4, 0);
+
+		MATHB(p, MATH1, SUB, ZERO, VSEQINSZ, 4, 0);
+		MATHB(p, MATH1, SUB, ZERO, VSEQOUTSZ, 4, 0);
+		SEQFIFOSTORE(p, MSG, 0, 0, VLF);
+		ALG_OPERATION(p, OP_ALG_ALGSEL_ZUCA,
+			      OP_ALG_AAI_F9,
+			      OP_ALG_AS_INITFINAL,
+			      dir == OP_TYPE_ENCAP_PROTOCOL ?
+				     ICV_CHECK_DISABLE : ICV_CHECK_ENABLE,
+			      DIR_ENC);
+		SEQFIFOLOAD(p, MSGINSNOOP, 0, VLF | LAST1 | LAST2 | FLUSH1);
+		MOVE(p, AB1, 0, OFIFO, 0, MATH1, 0);
+
+		if (dir == OP_TYPE_DECAP_PROTOCOL)
+			SEQFIFOLOAD(p, ICV2, 4, LAST2);
+		else
+			SEQSTORE(p, CONTEXT2, 0, 4, 0);
+
+		break;
+
+	default:
+		pr_err("%s: Invalid integrity algorithm selected: %d\n",
+		       "pdcp_insert_cplane_int_only_op", authdata->algtype);
+		return -EINVAL;
+	}
+
+	if (rta_sec_era < RTA_SEC_ERA_3) {
+		PATCH_MOVE(p, move_cmd_read_descbuf, local_offset);
+		PATCH_MOVE(p, move_cmd_write_descbuf, local_offset);
+	}
+
+	return 0;
+}
+
+static inline int
+pdcp_insert_cplane_enc_only_op(struct program *p,
+			       struct alginfo *cipherdata,
+			       struct alginfo *authdata __maybe_unused,
+			       unsigned dir,
+			       unsigned char era_2_sw_hfn_ovrd __maybe_unused)
+{
+	/* Insert Cipher Key */
+	KEY(p, KEY1, cipherdata->key_enc_flags, cipherdata->key,
+	    cipherdata->keylen, INLINE_KEY(cipherdata));
+
+	if (rta_sec_era >= RTA_SEC_ERA_8) {
+		PROTOCOL(p, dir, OP_PCLID_LTE_PDCP_CTRL_MIXED,
+				(uint16_t)cipherdata->algtype << 8);
+		return 0;
+	}
+
+	SEQLOAD(p, MATH0, 7, 1, 0);
+	JUMP(p, 1, LOCAL_JUMP, ALL_TRUE, CALM);
+	MATHB(p, MATH0, AND, PDCP_C_PLANE_SN_MASK, MATH1, 8, IFB | IMMED2);
+	SEQSTORE(p, MATH0, 7, 1, 0);
+	MATHB(p, MATH1, SHLD, MATH1, MATH1, 8, 0);
+	MOVE(p, DESCBUF, 8, MATH2, 0, 8, WAITCOMP | IMMED);
+	MATHB(p, MATH1, OR, MATH2, MATH2, 8, 0);
+
+	switch (cipherdata->algtype) {
+	case PDCP_CIPHER_TYPE_SNOW:
+		MOVE(p, MATH2, 0, CONTEXT1, 0, 8, WAITCOMP | IMMED);
+
+		if (rta_sec_era > RTA_SEC_ERA_2) {
+			MATHB(p, SEQINSZ, SUB, ZERO, VSEQINSZ, 4, 0);
+		} else {
+			MATHB(p, SEQINSZ, SUB, ONE, MATH1, 4, 0);
+			MATHB(p, MATH1, ADD, ONE, VSEQINSZ, 4, 0);
+		}
+
+		if (dir == OP_TYPE_ENCAP_PROTOCOL)
+			MATHB(p, SEQINSZ, ADD, PDCP_MAC_I_LEN, VSEQOUTSZ, 4,
+			      IMMED2);
+		else
+			MATHB(p, SEQINSZ, SUB, PDCP_MAC_I_LEN, VSEQOUTSZ, 4,
+			      IMMED2);
+		SEQFIFOSTORE(p, MSG, 0, 0, VLF | CONT);
+		ALG_OPERATION(p, OP_ALG_ALGSEL_SNOW_F8,
+			      OP_ALG_AAI_F8,
+			      OP_ALG_AS_INITFINAL, ICV_CHECK_DISABLE,
+			      dir == OP_TYPE_ENCAP_PROTOCOL ?
+					DIR_ENC : DIR_DEC);
+		break;
+
+	case PDCP_CIPHER_TYPE_AES:
+		MOVE(p, MATH2, 0, CONTEXT1, 0x10, 0x10, WAITCOMP | IMMED);
+
+		if (rta_sec_era > RTA_SEC_ERA_2) {
+			MATHB(p, SEQINSZ, SUB, ZERO, VSEQINSZ, 4, 0);
+		} else {
+			MATHB(p, SEQINSZ, SUB, ONE, MATH1, 4, 0);
+			MATHB(p, MATH1, ADD, ONE, VSEQINSZ, 4, 0);
+		}
+
+		if (dir == OP_TYPE_ENCAP_PROTOCOL)
+			MATHB(p, SEQINSZ, ADD, PDCP_MAC_I_LEN, VSEQOUTSZ, 4,
+			      IMMED2);
+		else
+			MATHB(p, SEQINSZ, SUB, PDCP_MAC_I_LEN, VSEQOUTSZ, 4,
+			      IMMED2);
+
+		SEQFIFOSTORE(p, MSG, 0, 0, VLF | CONT);
+		ALG_OPERATION(p, OP_ALG_ALGSEL_AES,
+			      OP_ALG_AAI_CTR,
+			      OP_ALG_AS_INITFINAL,
+			      ICV_CHECK_DISABLE,
+			      dir == OP_TYPE_ENCAP_PROTOCOL ?
+					DIR_ENC : DIR_DEC);
+		break;
+
+	case PDCP_CIPHER_TYPE_ZUC:
+		if (rta_sec_era < RTA_SEC_ERA_5) {
+			pr_err("Invalid era for selected algorithm\n");
+			return -ENOTSUP;
+		}
+
+		MOVE(p, MATH2, 0, CONTEXT1, 0, 0x08, IMMED);
+		MOVE(p, MATH2, 0, CONTEXT1, 0x08, 0x08, WAITCOMP | IMMED);
+		MATHB(p, SEQINSZ, SUB, ZERO, VSEQINSZ, 4, 0);
+		if (dir == OP_TYPE_ENCAP_PROTOCOL)
+			MATHB(p, SEQINSZ, ADD, PDCP_MAC_I_LEN, VSEQOUTSZ, 4,
+			      IMMED2);
+		else
+			MATHB(p, SEQINSZ, SUB, PDCP_MAC_I_LEN, VSEQOUTSZ, 4,
+			      IMMED2);
+
+		SEQFIFOSTORE(p, MSG, 0, 0, VLF | CONT);
+		ALG_OPERATION(p, OP_ALG_ALGSEL_ZUCE,
+			      OP_ALG_AAI_F8,
+			      OP_ALG_AS_INITFINAL,
+			      ICV_CHECK_DISABLE,
+			      dir == OP_TYPE_ENCAP_PROTOCOL ?
+					DIR_ENC : DIR_DEC);
+		break;
+
+	default:
+		pr_err("%s: Invalid encrypt algorithm selected: %d\n",
+		       "pdcp_insert_cplane_enc_only_op", cipherdata->algtype);
+		return -EINVAL;
+	}
+
+	if (dir == OP_TYPE_ENCAP_PROTOCOL) {
+		SEQFIFOLOAD(p, MSG1, 0, VLF);
+		FIFOLOAD(p, MSG1, PDCP_NULL_INT_MAC_I_VAL, 4,
+			 LAST1 | FLUSH1 | IMMED);
+	} else {
+		SEQFIFOLOAD(p, MSG1, 0, VLF | LAST1 | FLUSH1);
+		MOVE(p, OFIFO, 0, MATH1, 4, PDCP_MAC_I_LEN, WAITCOMP | IMMED);
+		MATHB(p, MATH1, XOR, PDCP_NULL_INT_MAC_I_VAL, NONE, 4, IMMED2);
+		JUMP(p, PDCP_NULL_INT_ICV_CHECK_FAILED_STATUS,
+		     HALT_STATUS, ALL_FALSE, MATH_Z);
+	}
+
+	return 0;
+}
+
+static inline int
+pdcp_insert_cplane_acc_op(struct program *p,
+			  struct alginfo *cipherdata,
+			  struct alginfo *authdata,
+			  unsigned dir,
+			  unsigned char era_2_hfn_ovrd __maybe_unused)
+{
+	/* Insert Auth Key */
+	KEY(p, KEY2, authdata->key_enc_flags, authdata->key, authdata->keylen,
+	    INLINE_KEY(authdata));
+
+	/* Insert Cipher Key */
+	KEY(p, KEY1, cipherdata->key_enc_flags, cipherdata->key,
+	    cipherdata->keylen, INLINE_KEY(cipherdata));
+	PROTOCOL(p, dir, OP_PCLID_LTE_PDCP_CTRL, (uint16_t)cipherdata->algtype);
+
+	return 0;
+}
+
+static inline int
+pdcp_insert_cplane_snow_aes_op(struct program *p,
+			       struct alginfo *cipherdata,
+			       struct alginfo *authdata,
+			       unsigned dir,
+			       unsigned char era_2_sw_hfn_ovrd)
+{
+	LABEL(back_to_sd_offset);
+	LABEL(end_desc);
+	LABEL(local_offset);
+	LABEL(jump_to_beginning);
+	LABEL(fifo_load_mac_i_offset);
+	REFERENCE(seqin_ptr_read);
+	REFERENCE(seqin_ptr_write);
+	REFERENCE(seq_out_read);
+	REFERENCE(jump_back_to_sd_cmd);
+	REFERENCE(move_mac_i_to_desc_buf);
+
+	if (rta_sec_era >= RTA_SEC_ERA_8) {
+		KEY(p, KEY1, cipherdata->key_enc_flags, cipherdata->key,
+				cipherdata->keylen, INLINE_KEY(cipherdata));
+		KEY(p, KEY2, authdata->key_enc_flags, authdata->key,
+				authdata->keylen, INLINE_KEY(authdata));
+
+		PROTOCOL(p, dir, OP_PCLID_LTE_PDCP_CTRL_MIXED,
+			 ((uint16_t)cipherdata->algtype << 8) |
+			 (uint16_t)authdata->algtype);
+
+		return 0;
+	}
+
+	SEQLOAD(p, MATH0, 7, 1, 0);
+	JUMP(p, 1, LOCAL_JUMP, ALL_TRUE, CALM);
+	MATHB(p, MATH0, AND, PDCP_C_PLANE_SN_MASK, MATH1, 8, IFB | IMMED2);
+	MATHB(p, MATH1, SHLD, MATH1, MATH1, 8, 0);
+	MOVE(p, DESCBUF, 4, MATH2, 0, 0x08, WAITCOMP | IMMED);
+	MATHB(p, MATH1, OR, MATH2, MATH2, 8, 0);
+	SEQSTORE(p, MATH0, 7, 1, 0);
+	if (dir == OP_TYPE_ENCAP_PROTOCOL) {
+		if (rta_sec_era > RTA_SEC_ERA_2 ||
+		    (rta_sec_era == RTA_SEC_ERA_2 &&
+				   era_2_sw_hfn_ovrd == 0)) {
+			SEQINPTR(p, 0, 1, RTO);
+		} else {
+			SEQINPTR(p, 0, 5, RTO);
+			SEQFIFOLOAD(p, SKIP, 4, 0);
+		}
+		KEY(p, KEY1, authdata->key_enc_flags, authdata->key,
+		    authdata->keylen, INLINE_KEY(authdata));
+		MOVE(p, MATH2, 0, IFIFOAB1, 0, 0x08, IMMED);
+
+		if (rta_sec_era > RTA_SEC_ERA_2) {
+			MATHB(p, SEQINSZ, SUB, ZERO, VSEQINSZ, 4, 0);
+			MATHB(p, SEQINSZ, SUB, ZERO, MATH1, 4, 0);
+			MATHB(p, VSEQINSZ, ADD, PDCP_MAC_I_LEN - 1, VSEQOUTSZ,
+			      4, IMMED2);
+		} else {
+			MATHB(p, SEQINSZ, SUB, MATH3, VSEQINSZ, 4, 0);
+			MATHB(p, VSEQINSZ, ADD, PDCP_MAC_I_LEN - 1, VSEQOUTSZ,
+			      4, IMMED2);
+			/*
+			 * Note: Although the calculations below might seem a
+			 * little off, the logic is the following:
+			 *
+			 * - SEQ IN PTR RTO below needs the full length of the
+			 *   frame; in case of P4080_REV_2_HFN_OV_WORKAROUND,
+			 *   this means the length of the frame to be processed
+			 *   + 4 bytes (the HFN override flag and value).
+			 *   The length of the frame to be processed minus 1
+			 *   byte is in the VSIL register (because
+			 *   VSIL = SIL + 3, due to 1 byte, the header being
+			 *   already written by the SEQ STORE above). So for
+			 *   calculating the length to use in RTO, I add one
+			 *   to the VSIL value in order to obtain the total
+			 *   frame length. This helps in case of P4080 which
+			 *   can have the value 0 as an operand in a MATH
+			 *   command only as SRC1 When the HFN override
+			 *   workaround is not enabled, the length of the
+			 *   frame is given by the SIL register; the
+			 *   calculation is similar to the one in the SEC 4.2
+			 *   and SEC 5.3 cases.
+			 */
+			if (era_2_sw_hfn_ovrd)
+				MATHB(p, VSEQOUTSZ, ADD, ONE, MATH1, 4,
+				      0);
+			else
+				MATHB(p, SEQINSZ, ADD, MATH3, MATH1, 4,
+				      0);
+		}
+		/*
+		 * Placeholder for filling the length in
+		 * SEQIN PTR RTO below
+		 */
+		seqin_ptr_read = MOVE(p, DESCBUF, 0, MATH1, 0, 6, IMMED);
+		seqin_ptr_write = MOVE(p, MATH1, 0, DESCBUF, 0, 8,
+				       WAITCOMP | IMMED);
+		ALG_OPERATION(p, OP_ALG_ALGSEL_AES,
+			      OP_ALG_AAI_CMAC,
+			      OP_ALG_AS_INITFINAL,
+			      ICV_CHECK_DISABLE,
+			      DIR_DEC);
+		SEQFIFOLOAD(p, MSG1, 0, VLF | LAST1 | FLUSH1);
+		MOVE(p, CONTEXT1, 0, MATH3, 0, 4, WAITCOMP | IMMED);
+		if (rta_sec_era <= RTA_SEC_ERA_3)
+			LOAD(p, CLRW_CLR_C1KEY |
+			     CLRW_CLR_C1CTX |
+			     CLRW_CLR_C1ICV |
+			     CLRW_CLR_C1DATAS |
+			     CLRW_CLR_C1MODE,
+			     CLRW, 0, 4, IMMED);
+		else
+			LOAD(p, CLRW_RESET_CLS1_CHA |
+			     CLRW_CLR_C1KEY |
+			     CLRW_CLR_C1CTX |
+			     CLRW_CLR_C1ICV |
+			     CLRW_CLR_C1DATAS |
+			     CLRW_CLR_C1MODE,
+			     CLRW, 0, 4, IMMED);
+
+		if (rta_sec_era <= RTA_SEC_ERA_3)
+			LOAD(p, CCTRL_RESET_CHA_ALL, CCTRL, 0, 4, IMMED);
+
+		KEY(p, KEY1, cipherdata->key_enc_flags, cipherdata->key,
+		    cipherdata->keylen, INLINE_KEY(cipherdata));
+		SET_LABEL(p, local_offset);
+		MOVE(p, MATH2, 0, CONTEXT1, 0, 8, IMMED);
+		SEQINPTR(p, 0, 0, RTO);
+
+		if (rta_sec_era == RTA_SEC_ERA_2 && era_2_sw_hfn_ovrd) {
+			SEQFIFOLOAD(p, SKIP, 5, 0);
+			MATHB(p, SEQINSZ, ADD, ONE, SEQINSZ, 4, 0);
+		}
+
+		MATHB(p, SEQINSZ, SUB, ONE, VSEQINSZ, 4, 0);
+		ALG_OPERATION(p, OP_ALG_ALGSEL_SNOW_F8,
+			      OP_ALG_AAI_F8,
+			      OP_ALG_AS_INITFINAL,
+			      ICV_CHECK_DISABLE,
+			      DIR_ENC);
+		SEQFIFOSTORE(p, MSG, 0, 0, VLF);
+
+		if (rta_sec_era > RTA_SEC_ERA_2 ||
+		    (rta_sec_era == RTA_SEC_ERA_2 &&
+				   era_2_sw_hfn_ovrd == 0))
+			SEQFIFOLOAD(p, SKIP, 1, 0);
+
+		SEQFIFOLOAD(p, MSG1, 0, VLF);
+		MOVE(p, MATH3, 0, IFIFOAB1, 0, 4, LAST1 | FLUSH1 | IMMED);
+		PATCH_MOVE(p, seqin_ptr_read, local_offset);
+		PATCH_MOVE(p, seqin_ptr_write, local_offset);
+	} else {
+		MOVE(p, MATH2, 0, CONTEXT1, 0, 8, IMMED);
+
+		if (rta_sec_era >= RTA_SEC_ERA_5)
+			MOVE(p, CONTEXT1, 0, CONTEXT2, 0, 8, IMMED);
+
+		if (rta_sec_era > RTA_SEC_ERA_2)
+			MATHB(p, SEQINSZ, SUB, ZERO, VSEQINSZ, 4, 0);
+		else
+			MATHB(p, SEQINSZ, SUB, MATH3, VSEQINSZ, 4, 0);
+
+		MATHB(p, SEQINSZ, SUB, PDCP_MAC_I_LEN, VSEQOUTSZ, 4, IMMED2);
+/*
+ * TODO: To be changed when proper support is added in RTA (can't load a
+ * command that is also written by RTA (or patch it for that matter).
+ * Change when proper RTA support is added.
+ */
+		if (p->ps)
+			WORD(p, 0x168B0004);
+		else
+			WORD(p, 0x16880404);
+
+		jump_back_to_sd_cmd = JUMP(p, 0, LOCAL_JUMP, ALL_TRUE, 0);
+		/*
+		 * Placeholder for command reading  the SEQ OUT command in
+		 * JD. Done for rereading the decrypted data and performing
+		 * the integrity check
+		 */
+/*
+ * TODO: RTA currently doesn't support patching of length of a MOVE command
+ * Thus, it is inserted as a raw word, as per PS setting.
+ */
+		if (p->ps)
+			seq_out_read = MOVE(p, DESCBUF, 0, MATH1, 0, 20,
+					    WAITCOMP | IMMED);
+		else
+			seq_out_read = MOVE(p, DESCBUF, 0, MATH1, 0, 16,
+					    WAITCOMP | IMMED);
+
+		MATHB(p, MATH1, XOR, CMD_SEQ_IN_PTR ^ CMD_SEQ_OUT_PTR, MATH1, 4,
+		      IMMED2);
+		/* Placeholder for overwriting the SEQ IN  with SEQ OUT */
+/*
+ * TODO: RTA currently doesn't support patching of length of a MOVE command
+ * Thus, it is inserted as a raw word, as per PS setting.
+ */
+		if (p->ps)
+			MOVE(p, MATH1, 0, DESCBUF, 0, 24, IMMED);
+		else
+			MOVE(p, MATH1, 0, DESCBUF, 0, 20, IMMED);
+
+		KEY(p, KEY1, cipherdata->key_enc_flags, cipherdata->key,
+		    cipherdata->keylen, INLINE_KEY(cipherdata));
+
+		if (rta_sec_era >= RTA_SEC_ERA_4)
+			MOVE(p, CONTEXT1, 0, CONTEXT2, 0, 8, IMMED);
+		else
+			MOVE(p, CONTEXT1, 0, MATH3, 0, 8, IMMED);
+
+		ALG_OPERATION(p, OP_ALG_ALGSEL_SNOW_F8,
+			      OP_ALG_AAI_F8,
+			      OP_ALG_AS_INITFINAL,
+			      ICV_CHECK_DISABLE,
+			      DIR_DEC);
+		SEQFIFOSTORE(p, MSG, 0, 0, VLF | CONT);
+		SEQFIFOLOAD(p, MSG1, 0, VLF | LAST1 | FLUSH1);
+
+		if (rta_sec_era <= RTA_SEC_ERA_3)
+			move_mac_i_to_desc_buf = MOVE(p, OFIFO, 0, DESCBUF, 0,
+						      4, WAITCOMP | IMMED);
+		else
+			MOVE(p, OFIFO, 0, MATH3, 0, 4, IMMED);
+
+		if (rta_sec_era <= RTA_SEC_ERA_3)
+			LOAD(p, CCTRL_RESET_CHA_ALL, CCTRL, 0, 4, IMMED);
+		else
+			LOAD(p, CLRW_RESET_CLS1_CHA |
+			     CLRW_CLR_C1KEY |
+			     CLRW_CLR_C1CTX |
+			     CLRW_CLR_C1ICV |
+			     CLRW_CLR_C1DATAS |
+			     CLRW_CLR_C1MODE,
+			     CLRW, 0, 4, IMMED);
+
+		KEY(p, KEY1, authdata->key_enc_flags, authdata->key,
+		    authdata->keylen, INLINE_KEY(authdata));
+		/*
+		 * Placeholder for jump in SD for executing the new SEQ IN PTR
+		 * command (which is actually the old SEQ OUT PTR command
+		 * copied over from JD.
+		 */
+		SET_LABEL(p, jump_to_beginning);
+		JUMP(p, 1 - jump_to_beginning, LOCAL_JUMP, ALL_TRUE, 0);
+		SET_LABEL(p, back_to_sd_offset);
+		ALG_OPERATION(p, OP_ALG_ALGSEL_AES,
+			      OP_ALG_AAI_CMAC,
+			      OP_ALG_AS_INITFINAL,
+			      ICV_CHECK_ENABLE,
+			      DIR_DEC);
+
+		/* Read the # of bytes written in the output buffer + 1 (HDR) */
+		MATHB(p, VSEQOUTSZ, ADD, ONE, VSEQINSZ, 4, 0);
+
+		if (rta_sec_era <= RTA_SEC_ERA_3)
+			MOVE(p, MATH3, 0, IFIFOAB1, 0, 8, IMMED);
+		else
+			MOVE(p, CONTEXT2, 0, IFIFOAB1, 0, 8, IMMED);
+
+		if (rta_sec_era == RTA_SEC_ERA_2 && era_2_sw_hfn_ovrd)
+			SEQFIFOLOAD(p, SKIP, 4, 0);
+
+		SEQFIFOLOAD(p, MSG1, 0, VLF | LAST1 | FLUSH1);
+
+		if (rta_sec_era >= RTA_SEC_ERA_4) {
+			LOAD(p, NFIFOENTRY_STYPE_ALTSOURCE |
+			     NFIFOENTRY_DEST_CLASS1 |
+			     NFIFOENTRY_DTYPE_ICV |
+			     NFIFOENTRY_LC1 |
+			     NFIFOENTRY_FC1 | 4, NFIFO_SZL, 0, 4, IMMED);
+			MOVE(p, MATH3, 0, ALTSOURCE, 0, 4, IMMED);
+		} else {
+			SET_LABEL(p, fifo_load_mac_i_offset);
+			FIFOLOAD(p, ICV1, fifo_load_mac_i_offset, 4,
+				 LAST1 | FLUSH1 | IMMED);
+		}
+
+		SET_LABEL(p, end_desc);
+
+		if (!p->ps) {
+			PATCH_MOVE(p, seq_out_read, end_desc + 1);
+			PATCH_JUMP(p, jump_back_to_sd_cmd,
+				   back_to_sd_offset + jump_back_to_sd_cmd - 5);
+
+			if (rta_sec_era <= RTA_SEC_ERA_3)
+				PATCH_MOVE(p, move_mac_i_to_desc_buf,
+					   fifo_load_mac_i_offset + 1);
+		} else {
+			PATCH_MOVE(p, seq_out_read, end_desc + 2);
+			PATCH_JUMP(p, jump_back_to_sd_cmd,
+				   back_to_sd_offset + jump_back_to_sd_cmd - 5);
+
+			if (rta_sec_era <= RTA_SEC_ERA_3)
+				PATCH_MOVE(p, move_mac_i_to_desc_buf,
+					   fifo_load_mac_i_offset + 1);
+		}
+	}
+
+	return 0;
+}
+
+static inline int
+pdcp_insert_cplane_aes_snow_op(struct program *p,
+			       struct alginfo *cipherdata,
+			       struct alginfo *authdata,
+			       unsigned dir,
+			       unsigned char era_2_sw_hfn_ovrd __maybe_unused)
+{
+	KEY(p, KEY1, cipherdata->key_enc_flags, cipherdata->key,
+	    cipherdata->keylen, INLINE_KEY(cipherdata));
+	KEY(p, KEY2, authdata->key_enc_flags, authdata->key, authdata->keylen,
+	    INLINE_KEY(authdata));
+
+	if (rta_sec_era >= RTA_SEC_ERA_8) {
+		PROTOCOL(p, dir, OP_PCLID_LTE_PDCP_CTRL_MIXED,
+			 ((uint16_t)cipherdata->algtype << 8) |
+			 (uint16_t)authdata->algtype);
+
+		return 0;
+	}
+
+	if (dir == OP_TYPE_ENCAP_PROTOCOL)
+		MATHB(p, SEQINSZ, SUB, ONE, VSEQINSZ, 4, 0);
+
+	SEQLOAD(p, MATH0, 7, 1, 0);
+	JUMP(p, 1, LOCAL_JUMP, ALL_TRUE, CALM);
+	MOVE(p, MATH0, 7, IFIFOAB2, 0, 1, IMMED);
+	MATHB(p, MATH0, AND, PDCP_C_PLANE_SN_MASK, MATH1, 8, IFB | IMMED2);
+	SEQSTORE(p, MATH0, 7, 1, 0);
+	MATHB(p, MATH1, SHLD, MATH1, MATH1, 8, 0);
+	MOVE(p, DESCBUF, 4, MATH2, 0, 8, WAITCOMP | IMMED);
+	MATHB(p, MATH1, OR, MATH2, MATH1, 8, 0);
+	MOVE(p, MATH1, 0, CONTEXT1, 16, 8, IMMED);
+	MOVE(p, MATH1, 0, CONTEXT2, 0, 4, IMMED);
+	MATHB(p, MATH1, AND, lower_32_bits(PDCP_BEARER_MASK), MATH2, 4, IMMED2);
+	MATHB(p, MATH1, AND, upper_32_bits(PDCP_DIR_MASK), MATH3, 4, IMMED2);
+	MATHB(p, MATH3, SHLD, MATH3, MATH3, 8, 0);
+	MOVE(p, MATH2, 4, OFIFO, 0, 12, IMMED);
+	MOVE(p, OFIFO, 0, CONTEXT2, 4, 12, IMMED);
+	if (dir == OP_TYPE_ENCAP_PROTOCOL) {
+		MATHB(p, SEQINSZ, ADD, PDCP_MAC_I_LEN, VSEQOUTSZ, 4, IMMED2);
+	} else {
+		MATHB(p, SEQINSZ, SUB, PDCP_MAC_I_LEN, MATH1, 4, IMMED2);
+
+		MATHB(p, ZERO, ADD, MATH1, VSEQOUTSZ, 4, 0);
+		MATHB(p, ZERO, ADD, MATH1, VSEQINSZ, 4, 0);
+	}
+
+	if (dir == OP_TYPE_ENCAP_PROTOCOL)
+		SEQFIFOSTORE(p, MSG, 0, 0, VLF);
+	else
+		SEQFIFOSTORE(p, MSG, 0, 0, VLF | CONT);
+
+	ALG_OPERATION(p, OP_ALG_ALGSEL_SNOW_F9,
+		      OP_ALG_AAI_F9,
+		      OP_ALG_AS_INITFINAL,
+		      dir == OP_TYPE_ENCAP_PROTOCOL ?
+			     ICV_CHECK_DISABLE : ICV_CHECK_ENABLE,
+		      DIR_DEC);
+	ALG_OPERATION(p, OP_ALG_ALGSEL_AES,
+		      OP_ALG_AAI_CTR,
+		      OP_ALG_AS_INITFINAL,
+		      ICV_CHECK_DISABLE,
+		      dir == OP_TYPE_ENCAP_PROTOCOL ? DIR_ENC : DIR_DEC);
+
+	if (dir == OP_TYPE_ENCAP_PROTOCOL) {
+		SEQFIFOLOAD(p, MSGINSNOOP, 0, VLF | LAST2);
+		MOVE(p, CONTEXT2, 0, IFIFOAB1, 0, 4, LAST1 | FLUSH1 | IMMED);
+	} else {
+		SEQFIFOLOAD(p, MSGOUTSNOOP, 0, VLF | LAST2);
+		SEQFIFOLOAD(p, MSG1, 4, LAST1 | FLUSH1);
+		JUMP(p, 1, LOCAL_JUMP, ALL_TRUE, CLASS1 | NOP | NIFP);
+
+		if (rta_sec_era >= RTA_SEC_ERA_6)
+			LOAD(p, 0, DCTRL, 0, LDLEN_RST_CHA_OFIFO_PTR, IMMED);
+
+		MOVE(p, OFIFO, 0, MATH0, 0, 4, WAITCOMP | IMMED);
+
+		NFIFOADD(p, IFIFO, ICV2, 4, LAST2);
+
+		if (rta_sec_era <= RTA_SEC_ERA_2) {
+			/* Shut off automatic Info FIFO entries */
+			LOAD(p, 0, DCTRL, LDOFF_DISABLE_AUTO_NFIFO, 0, IMMED);
+			MOVE(p, MATH0, 0, IFIFOAB2, 0, 4, WAITCOMP | IMMED);
+		} else {
+			MOVE(p, MATH0, 0, IFIFO, 0, 4, WAITCOMP | IMMED);
+		}
+	}
+
+	return 0;
+}
+
+static inline int
+pdcp_insert_cplane_snow_zuc_op(struct program *p,
+			       struct alginfo *cipherdata,
+			       struct alginfo *authdata,
+			       unsigned dir,
+			       unsigned char era_2_sw_hfn_ovrd __maybe_unused)
+{
+	LABEL(keyjump);
+	REFERENCE(pkeyjump);
+
+	if (rta_sec_era < RTA_SEC_ERA_5) {
+		pr_err("Invalid era for selected algorithm\n");
+		return -ENOTSUP;
+	}
+
+	pkeyjump = JUMP(p, keyjump, LOCAL_JUMP, ALL_TRUE, SHRD | SELF | BOTH);
+	KEY(p, KEY1, cipherdata->key_enc_flags, cipherdata->key,
+	    cipherdata->keylen, INLINE_KEY(cipherdata));
+	KEY(p, KEY2, authdata->key_enc_flags, authdata->key, authdata->keylen,
+	    INLINE_KEY(authdata));
+
+	SET_LABEL(p, keyjump);
+
+	if (rta_sec_era >= RTA_SEC_ERA_8) {
+		PROTOCOL(p, dir, OP_PCLID_LTE_PDCP_CTRL_MIXED,
+			 ((uint16_t)cipherdata->algtype << 8) |
+			 (uint16_t)authdata->algtype);
+		return 0;
+	}
+
+	SEQLOAD(p, MATH0, 7, 1, 0);
+	JUMP(p, 1, LOCAL_JUMP, ALL_TRUE, CALM);
+	MOVE(p, MATH0, 7, IFIFOAB2, 0, 1, IMMED);
+	MATHB(p, MATH0, AND, PDCP_C_PLANE_SN_MASK, MATH1, 8, IFB | IMMED2);
+	MATHB(p, MATH1, SHLD, MATH1, MATH1, 8, 0);
+	MOVE(p, DESCBUF, 4, MATH2, 0, 8, WAITCOMP | IMMED);
+	MATHB(p, MATH1, OR, MATH2, MATH2, 8, 0);
+	MOVE(p, MATH2, 0, CONTEXT1, 0, 8, IMMED);
+	MOVE(p, MATH2, 0, CONTEXT2, 0, 8, WAITCOMP | IMMED);
+
+	if (dir == OP_TYPE_ENCAP_PROTOCOL)
+		MATHB(p, SEQINSZ, ADD, PDCP_MAC_I_LEN, VSEQOUTSZ, 4, IMMED2);
+	else
+		MATHB(p, SEQINSZ, SUB, PDCP_MAC_I_LEN, VSEQOUTSZ, 4, IMMED2);
+
+	MATHB(p, SEQINSZ, SUB, ZERO, VSEQINSZ, 4, 0);
+	SEQSTORE(p, MATH0, 7, 1, 0);
+
+	if (dir == OP_TYPE_ENCAP_PROTOCOL) {
+		SEQFIFOSTORE(p, MSG, 0, 0, VLF);
+		SEQFIFOLOAD(p, MSGINSNOOP, 0, VLF | LAST2);
+	} else {
+		SEQFIFOSTORE(p, MSG, 0, 0, VLF | CONT);
+		SEQFIFOLOAD(p, MSGOUTSNOOP, 0, VLF | LAST1 | FLUSH1);
+	}
+
+	ALG_OPERATION(p, OP_ALG_ALGSEL_ZUCA,
+		      OP_ALG_AAI_F9,
+		      OP_ALG_AS_INITFINAL,
+		      dir == OP_TYPE_ENCAP_PROTOCOL ?
+			     ICV_CHECK_DISABLE : ICV_CHECK_ENABLE,
+		      DIR_ENC);
+
+	ALG_OPERATION(p, OP_ALG_ALGSEL_SNOW_F8,
+		      OP_ALG_AAI_F8,
+		      OP_ALG_AS_INITFINAL,
+		      ICV_CHECK_DISABLE,
+		      dir == OP_TYPE_ENCAP_PROTOCOL ? DIR_ENC : DIR_DEC);
+	if (dir == OP_TYPE_ENCAP_PROTOCOL) {
+		MOVE(p, CONTEXT2, 0, IFIFOAB1, 0, 4, LAST1 | FLUSH1 | IMMED);
+	} else {
+		/* Save ICV */
+		MOVE(p, OFIFO, 0, MATH0, 0, 4, IMMED);
+		LOAD(p, NFIFOENTRY_STYPE_ALTSOURCE |
+		     NFIFOENTRY_DEST_CLASS2 |
+		     NFIFOENTRY_DTYPE_ICV |
+		     NFIFOENTRY_LC2 | 4, NFIFO_SZL, 0, 4, IMMED);
+		MOVE(p, MATH0, 0, ALTSOURCE, 0, 4, WAITCOMP | IMMED);
+	}
+
+	/* Reset ZUCA mode and done interrupt */
+	LOAD(p, CLRW_CLR_C2MODE, CLRW, 0, 4, IMMED);
+	LOAD(p, CIRQ_ZADI, ICTRL, 0, 4, IMMED);
+
+	PATCH_JUMP(p, pkeyjump, keyjump);
+	return 0;
+}
+
+static inline int
+pdcp_insert_cplane_aes_zuc_op(struct program *p,
+			      struct alginfo *cipherdata,
+			      struct alginfo *authdata,
+			      unsigned dir,
+			      unsigned char era_2_sw_hfn_ovrd __maybe_unused)
+{
+	LABEL(keyjump);
+	REFERENCE(pkeyjump);
+
+	if (rta_sec_era < RTA_SEC_ERA_5) {
+		pr_err("Invalid era for selected algorithm\n");
+		return -ENOTSUP;
+	}
+
+	pkeyjump = JUMP(p, keyjump, LOCAL_JUMP, ALL_TRUE, SHRD | SELF | BOTH);
+	KEY(p, KEY1, cipherdata->key_enc_flags, cipherdata->key,
+	    cipherdata->keylen, INLINE_KEY(cipherdata));
+	KEY(p, KEY2, authdata->key_enc_flags, authdata->key, authdata->keylen,
+	    INLINE_KEY(authdata));
+
+	if (rta_sec_era >= RTA_SEC_ERA_8) {
+		PROTOCOL(p, dir, OP_PCLID_LTE_PDCP_CTRL_MIXED,
+			 ((uint16_t)cipherdata->algtype << 8) |
+			 (uint16_t)authdata->algtype);
+
+		return 0;
+	}
+
+	SET_LABEL(p, keyjump);
+	SEQLOAD(p, MATH0, 7, 1, 0);
+	JUMP(p, 1, LOCAL_JUMP, ALL_TRUE, CALM);
+	MOVE(p, MATH0, 7, IFIFOAB2, 0, 1, IMMED);
+	MATHB(p, MATH0, AND, PDCP_C_PLANE_SN_MASK, MATH1, 8, IFB | IMMED2);
+
+	MATHB(p, MATH1, SHLD, MATH1, MATH1, 8, 0);
+	MOVE(p, DESCBUF, 4, MATH2, 0, 8, WAITCOMP | IMMED);
+	MATHB(p, MATH1, OR, MATH2, MATH2, 8, 0);
+	MOVE(p, MATH2, 0, CONTEXT1, 16, 8, IMMED);
+	MOVE(p, MATH2, 0, CONTEXT2, 0, 8, WAITCOMP | IMMED);
+
+	if (dir == OP_TYPE_ENCAP_PROTOCOL)
+		MATHB(p, SEQINSZ, ADD, PDCP_MAC_I_LEN, VSEQOUTSZ, 4, IMMED2);
+	else
+		MATHB(p, SEQINSZ, SUB, PDCP_MAC_I_LEN, VSEQOUTSZ, 4, IMMED2);
+
+	MATHB(p, SEQINSZ, SUB, ZERO, VSEQINSZ, 4, 0);
+	SEQSTORE(p, MATH0, 7, 1, 0);
+
+	if (dir == OP_TYPE_ENCAP_PROTOCOL) {
+		SEQFIFOSTORE(p, MSG, 0, 0, VLF);
+		SEQFIFOLOAD(p, MSGINSNOOP, 0, VLF | LAST2);
+	} else {
+		SEQFIFOSTORE(p, MSG, 0, 0, VLF | CONT);
+		SEQFIFOLOAD(p, MSGOUTSNOOP, 0, VLF | LAST1 | FLUSH1);
+	}
+
+	ALG_OPERATION(p, OP_ALG_ALGSEL_ZUCA,
+		      OP_ALG_AAI_F9,
+		      OP_ALG_AS_INITFINAL,
+		      dir == OP_TYPE_ENCAP_PROTOCOL ?
+			     ICV_CHECK_DISABLE : ICV_CHECK_ENABLE,
+		      DIR_ENC);
+
+	ALG_OPERATION(p, OP_ALG_ALGSEL_AES,
+		      OP_ALG_AAI_CTR,
+		      OP_ALG_AS_INITFINAL,
+		      ICV_CHECK_DISABLE,
+		      dir == OP_TYPE_ENCAP_PROTOCOL ? DIR_ENC : DIR_DEC);
+
+	if (dir == OP_TYPE_ENCAP_PROTOCOL) {
+		MOVE(p, CONTEXT2, 0, IFIFOAB1, 0, 4, LAST1 | FLUSH1 | IMMED);
+	} else {
+		/* Save ICV */
+		MOVE(p, OFIFO, 0, MATH0, 0, 4, IMMED);
+
+		LOAD(p, NFIFOENTRY_STYPE_ALTSOURCE |
+		     NFIFOENTRY_DEST_CLASS2 |
+		     NFIFOENTRY_DTYPE_ICV |
+		     NFIFOENTRY_LC2 | 4, NFIFO_SZL, 0, 4, IMMED);
+		MOVE(p, MATH0, 0, ALTSOURCE, 0, 4, WAITCOMP | IMMED);
+	}
+
+	/* Reset ZUCA mode and done interrupt */
+	LOAD(p, CLRW_CLR_C2MODE, CLRW, 0, 4, IMMED);
+	LOAD(p, CIRQ_ZADI, ICTRL, 0, 4, IMMED);
+
+	PATCH_JUMP(p, pkeyjump, keyjump);
+
+	return 0;
+}
+
+static inline int
+pdcp_insert_cplane_zuc_snow_op(struct program *p,
+			       struct alginfo *cipherdata,
+			       struct alginfo *authdata,
+			       unsigned dir,
+			       unsigned char era_2_sw_hfn_ovrd __maybe_unused)
+{
+	LABEL(keyjump);
+	REFERENCE(pkeyjump);
+
+	if (rta_sec_era < RTA_SEC_ERA_5) {
+		pr_err("Invalid era for selected algorithm\n");
+		return -ENOTSUP;
+	}
+
+	pkeyjump = JUMP(p, keyjump, LOCAL_JUMP, ALL_TRUE, SHRD | SELF | BOTH);
+	KEY(p, KEY1, cipherdata->key_enc_flags, cipherdata->key,
+	    cipherdata->keylen, INLINE_KEY(cipherdata));
+	KEY(p, KEY2, authdata->key_enc_flags, authdata->key, authdata->keylen,
+	    INLINE_KEY(authdata));
+
+	if (rta_sec_era >= RTA_SEC_ERA_8) {
+		PROTOCOL(p, dir, OP_PCLID_LTE_PDCP_CTRL_MIXED,
+			 ((uint16_t)cipherdata->algtype << 8) |
+			 (uint16_t)authdata->algtype);
+
+		return 0;
+	}
+
+	SET_LABEL(p, keyjump);
+	SEQLOAD(p, MATH0, 7, 1, 0);
+	JUMP(p, 1, LOCAL_JUMP, ALL_TRUE, CALM);
+	MOVE(p, MATH0, 7, IFIFOAB2, 0, 1, IMMED);
+	MATHB(p, MATH0, AND, PDCP_C_PLANE_SN_MASK, MATH1, 8, IFB | IMMED2);
+	MATHB(p, MATH1, SHLD, MATH1, MATH1, 8, 0);
+	MOVE(p, DESCBUF, 4, MATH2, 0, 8, WAITCOMP | IMMED);
+	MATHB(p, MATH1, OR, MATH2, MATH1, 8, 0);
+	MOVE(p, MATH1, 0, CONTEXT1, 0, 8, IMMED);
+	MOVE(p, MATH1, 0, CONTEXT2, 0, 4, IMMED);
+	MATHB(p, MATH1, AND, lower_32_bits(PDCP_BEARER_MASK), MATH2, 4, IMMED2);
+	MATHB(p, MATH1, AND, upper_32_bits(PDCP_DIR_MASK), MATH3, 4, IMMED2);
+	MATHB(p, MATH3, SHLD, MATH3, MATH3, 8, 0);
+	MOVE(p, MATH2, 4, OFIFO, 0, 12, IMMED);
+	MOVE(p, OFIFO, 0, CONTEXT2, 4, 12, IMMED);
+
+	if (dir == OP_TYPE_ENCAP_PROTOCOL) {
+		MATHB(p, SEQINSZ, ADD, PDCP_MAC_I_LEN, VSEQOUTSZ, 4, IMMED2);
+		MATHB(p, SEQINSZ, SUB, ZERO, VSEQINSZ, 4, 0);
+	} else {
+		MATHB(p, SEQINSZ, SUB, PDCP_MAC_I_LEN, VSEQOUTSZ, 4, IMMED2);
+		MATHB(p, VSEQOUTSZ, SUB, ZERO, VSEQINSZ, 4, 0);
+	}
+
+	SEQSTORE(p, MATH0, 7, 1, 0);
+
+	if (dir == OP_TYPE_ENCAP_PROTOCOL) {
+		SEQFIFOSTORE(p, MSG, 0, 0, VLF);
+		SEQFIFOLOAD(p, MSGINSNOOP, 0, VLF | LAST2);
+	} else {
+		SEQFIFOSTORE(p, MSG, 0, 0, VLF | CONT);
+		SEQFIFOLOAD(p, MSGOUTSNOOP, 0, VLF | LAST2);
+	}
+
+	ALG_OPERATION(p, OP_ALG_ALGSEL_SNOW_F9,
+		      OP_ALG_AAI_F9,
+		      OP_ALG_AS_INITFINAL,
+		      dir == OP_TYPE_ENCAP_PROTOCOL ?
+			     ICV_CHECK_DISABLE : ICV_CHECK_ENABLE,
+		      DIR_DEC);
+
+	ALG_OPERATION(p, OP_ALG_ALGSEL_ZUCE,
+		      OP_ALG_AAI_F8,
+		      OP_ALG_AS_INITFINAL,
+		      ICV_CHECK_DISABLE,
+		      dir == OP_TYPE_ENCAP_PROTOCOL ? DIR_ENC : DIR_DEC);
+
+	if (dir == OP_TYPE_ENCAP_PROTOCOL) {
+		MOVE(p, CONTEXT2, 0, IFIFOAB1, 0, 4, LAST1 | FLUSH1 | IMMED);
+	} else {
+		SEQFIFOLOAD(p, MSG1, 4, LAST1 | FLUSH1);
+		JUMP(p, 1, LOCAL_JUMP, ALL_TRUE, CLASS1 | NOP | NIFP);
+
+		if (rta_sec_era >= RTA_SEC_ERA_6)
+			/*
+			 * For SEC ERA 6, there's a problem with the OFIFO
+			 * pointer, and thus it needs to be reset here before
+			 * moving to M0.
+			 */
+			LOAD(p, 0, DCTRL, 0, LDLEN_RST_CHA_OFIFO_PTR, IMMED);
+
+		/* Put ICV to M0 before sending it to C2 for comparison. */
+		MOVE(p, OFIFO, 0, MATH0, 0, 4, WAITCOMP | IMMED);
+
+		LOAD(p, NFIFOENTRY_STYPE_ALTSOURCE |
+		     NFIFOENTRY_DEST_CLASS2 |
+		     NFIFOENTRY_DTYPE_ICV |
+		     NFIFOENTRY_LC2 | 4, NFIFO_SZL, 0, 4, IMMED);
+		MOVE(p, MATH0, 0, ALTSOURCE, 0, 4, IMMED);
+	}
+
+	PATCH_JUMP(p, pkeyjump, keyjump);
+	return 0;
+}
+
+static inline int
+pdcp_insert_cplane_zuc_aes_op(struct program *p,
+			      struct alginfo *cipherdata,
+			      struct alginfo *authdata,
+			      unsigned dir,
+			      unsigned char era_2_sw_hfn_ovrd __maybe_unused)
+{
+	if (rta_sec_era < RTA_SEC_ERA_5) {
+		pr_err("Invalid era for selected algorithm\n");
+		return -ENOTSUP;
+	}
+
+	if (rta_sec_era >= RTA_SEC_ERA_8) {
+		KEY(p, KEY1, cipherdata->key_enc_flags, cipherdata->key,
+				cipherdata->keylen, INLINE_KEY(cipherdata));
+		KEY(p, KEY2, authdata->key_enc_flags, authdata->key,
+				authdata->keylen, INLINE_KEY(authdata));
+
+		PROTOCOL(p, dir, OP_PCLID_LTE_PDCP_CTRL_MIXED,
+			 ((uint16_t)cipherdata->algtype << 8) |
+			 (uint16_t)authdata->algtype);
+		return 0;
+	}
+
+	SEQLOAD(p, MATH0, 7, 1, 0);
+	JUMP(p, 1, LOCAL_JUMP, ALL_TRUE, CALM);
+	MATHB(p, MATH0, AND, PDCP_C_PLANE_SN_MASK, MATH1, 8, IFB | IMMED2);
+	MATHB(p, MATH1, SHLD, MATH1, MATH1, 8, 0);
+	MOVE(p, DESCBUF, 4, MATH2, 0, 0x08, WAITCOMP | IMMED);
+	MATHB(p, MATH1, OR, MATH2, MATH2, 8, 0);
+	SEQSTORE(p, MATH0, 7, 1, 0);
+	if (dir == OP_TYPE_ENCAP_PROTOCOL) {
+		KEY(p, KEY1, authdata->key_enc_flags, authdata->key,
+		    authdata->keylen, INLINE_KEY(authdata));
+		MOVE(p, MATH2, 0, IFIFOAB1, 0, 0x08, IMMED);
+		MOVE(p, MATH0, 7, IFIFOAB1, 0, 1, IMMED);
+
+		MATHB(p, SEQINSZ, SUB, ZERO, VSEQINSZ, 4, 0);
+		MATHB(p, VSEQINSZ, ADD, PDCP_MAC_I_LEN, VSEQOUTSZ, 4, IMMED2);
+
+		ALG_OPERATION(p, OP_ALG_ALGSEL_AES,
+			      OP_ALG_AAI_CMAC,
+			      OP_ALG_AS_INITFINAL,
+			      ICV_CHECK_DISABLE,
+			      DIR_DEC);
+		SEQFIFOLOAD(p, MSG1, 0, VLF | LAST1 | FLUSH1);
+		MOVE(p, CONTEXT1, 0, MATH3, 0, 4, WAITCOMP | IMMED);
+		LOAD(p, CLRW_RESET_CLS1_CHA |
+		     CLRW_CLR_C1KEY |
+		     CLRW_CLR_C1CTX |
+		     CLRW_CLR_C1ICV |
+		     CLRW_CLR_C1DATAS |
+		     CLRW_CLR_C1MODE,
+		     CLRW, 0, 4, IMMED);
+
+		KEY(p, KEY1, cipherdata->key_enc_flags, cipherdata->key,
+		    cipherdata->keylen, INLINE_KEY(cipherdata));
+
+		MOVE(p, MATH2, 0, CONTEXT1, 0, 8, IMMED);
+		SEQINPTR(p, 0, PDCP_NULL_MAX_FRAME_LEN, RTO);
+
+		ALG_OPERATION(p, OP_ALG_ALGSEL_ZUCE,
+			      OP_ALG_AAI_F8,
+			      OP_ALG_AS_INITFINAL,
+			      ICV_CHECK_DISABLE,
+			      DIR_ENC);
+		SEQFIFOSTORE(p, MSG, 0, 0, VLF);
+
+		SEQFIFOLOAD(p, SKIP, 1, 0);
+
+		SEQFIFOLOAD(p, MSG1, 0, VLF);
+		MOVE(p, MATH3, 0, IFIFOAB1, 0, 4, LAST1 | FLUSH1 | IMMED);
+	} else {
+		MOVE(p, MATH2, 0, CONTEXT1, 0, 8, IMMED);
+
+		MOVE(p, CONTEXT1, 0, CONTEXT2, 0, 8, IMMED);
+
+		MATHB(p, SEQINSZ, SUB, ZERO, VSEQINSZ, 4, 0);
+
+		MATHB(p, SEQINSZ, SUB, PDCP_MAC_I_LEN, VSEQOUTSZ, 4, IMMED2);
+
+		KEY(p, KEY1, cipherdata->key_enc_flags, cipherdata->key,
+		    cipherdata->keylen, INLINE_KEY(cipherdata));
+
+		MOVE(p, CONTEXT1, 0, CONTEXT2, 0, 8, IMMED);
+
+		ALG_OPERATION(p, OP_ALG_ALGSEL_ZUCE,
+			      OP_ALG_AAI_F8,
+			      OP_ALG_AS_INITFINAL,
+			      ICV_CHECK_DISABLE,
+			      DIR_DEC);
+		SEQFIFOSTORE(p, MSG, 0, 0, VLF | CONT);
+		SEQFIFOLOAD(p, MSG1, 0, VLF | LAST1 | FLUSH1);
+
+		MOVE(p, OFIFO, 0, MATH3, 0, 4, IMMED);
+
+		LOAD(p, CLRW_RESET_CLS1_CHA |
+		     CLRW_CLR_C1KEY |
+		     CLRW_CLR_C1CTX |
+		     CLRW_CLR_C1ICV |
+		     CLRW_CLR_C1DATAS |
+		     CLRW_CLR_C1MODE,
+		     CLRW, 0, 4, IMMED);
+
+		KEY(p, KEY1, authdata->key_enc_flags, authdata->key,
+		    authdata->keylen, INLINE_KEY(authdata));
+
+		SEQINPTR(p, 0, 0, SOP);
+
+		ALG_OPERATION(p, OP_ALG_ALGSEL_AES,
+			      OP_ALG_AAI_CMAC,
+			      OP_ALG_AS_INITFINAL,
+			      ICV_CHECK_ENABLE,
+			      DIR_DEC);
+
+		MATHB(p, SEQINSZ, SUB, ZERO, VSEQINSZ, 4, 0);
+
+		MOVE(p, CONTEXT2, 0, IFIFOAB1, 0, 8, IMMED);
+
+		SEQFIFOLOAD(p, MSG1, 0, VLF | LAST1 | FLUSH1);
+
+		LOAD(p, NFIFOENTRY_STYPE_ALTSOURCE |
+		     NFIFOENTRY_DEST_CLASS1 |
+		     NFIFOENTRY_DTYPE_ICV |
+		     NFIFOENTRY_LC1 |
+		     NFIFOENTRY_FC1 | 4, NFIFO_SZL, 0, 4, IMMED);
+		MOVE(p, MATH3, 0, ALTSOURCE, 0, 4, IMMED);
+	}
+
+	return 0;
+}
+
+static inline int
+pdcp_insert_uplane_15bit_op(struct program *p,
+			    struct alginfo *cipherdata,
+			    unsigned dir)
+{
+	int op;
+	/* Insert Cipher Key */
+	KEY(p, KEY1, cipherdata->key_enc_flags, cipherdata->key,
+	    cipherdata->keylen, INLINE_KEY(cipherdata));
+
+	if (rta_sec_era >= RTA_SEC_ERA_8) {
+		PROTOCOL(p, dir, OP_PCLID_LTE_PDCP_USER,
+			 (uint16_t)cipherdata->algtype);
+		return 0;
+	}
+
+	SEQLOAD(p, MATH0, 6, 2, 0);
+	JUMP(p, 1, LOCAL_JUMP, ALL_TRUE, CALM);
+	MATHB(p, MATH0, AND, PDCP_U_PLANE_15BIT_SN_MASK, MATH1, 8,
+	      IFB | IMMED2);
+	SEQSTORE(p, MATH0, 6, 2, 0);
+	MATHB(p, MATH1, SHLD, MATH1, MATH1, 8, 0);
+	MOVE(p, DESCBUF, 8, MATH2, 0, 8, WAITCOMP | IMMED);
+	MATHB(p, MATH1, OR, MATH2, MATH2, 8, 0);
+
+	MATHB(p, SEQINSZ, SUB, MATH3, VSEQINSZ, 4, 0);
+	MATHB(p, SEQINSZ, SUB, MATH3, VSEQOUTSZ, 4, 0);
+
+	SEQFIFOSTORE(p, MSG, 0, 0, VLF);
+
+	op = dir == OP_TYPE_ENCAP_PROTOCOL ? DIR_ENC : DIR_DEC;
+	switch (cipherdata->algtype) {
+	case PDCP_CIPHER_TYPE_SNOW:
+		MOVE(p, MATH2, 0, CONTEXT1, 0, 8, WAITCOMP | IMMED);
+		ALG_OPERATION(p, OP_ALG_ALGSEL_SNOW_F8,
+			      OP_ALG_AAI_F8,
+			      OP_ALG_AS_INITFINAL,
+			      ICV_CHECK_DISABLE,
+			      op);
+		break;
+
+	case PDCP_CIPHER_TYPE_AES:
+		MOVE(p, MATH2, 0, CONTEXT1, 0x10, 0x10, WAITCOMP | IMMED);
+		ALG_OPERATION(p, OP_ALG_ALGSEL_AES,
+			      OP_ALG_AAI_CTR,
+			      OP_ALG_AS_INITFINAL,
+			      ICV_CHECK_DISABLE,
+			      op);
+		break;
+
+	case PDCP_CIPHER_TYPE_ZUC:
+		if (rta_sec_era < RTA_SEC_ERA_5) {
+			pr_err("Invalid era for selected algorithm\n");
+			return -ENOTSUP;
+		}
+		MOVE(p, MATH2, 0, CONTEXT1, 0, 0x08, IMMED);
+		MOVE(p, MATH2, 0, CONTEXT1, 0x08, 0x08, WAITCOMP | IMMED);
+
+		ALG_OPERATION(p, OP_ALG_ALGSEL_ZUCE,
+			      OP_ALG_AAI_F8,
+			      OP_ALG_AS_INITFINAL,
+			      ICV_CHECK_DISABLE,
+			      op);
+		break;
+
+	default:
+		pr_err("%s: Invalid encrypt algorithm selected: %d\n",
+		       "pdcp_insert_uplane_15bit_op", cipherdata->algtype);
+		return -EINVAL;
+	}
+
+	SEQFIFOLOAD(p, MSG1, 0, VLF | LAST1 | FLUSH1);
+
+	return 0;
+}
+
+/*
+ * Function for inserting the snippet of code responsible for creating
+ * the HFN override code via either DPOVRD or via the input frame.
+ */
+static inline int
+insert_hfn_ov_op(struct program *p,
+		 uint32_t shift,
+		 enum pdb_type_e pdb_type,
+		 unsigned char era_2_sw_hfn_ovrd)
+{
+	uint32_t imm = 0x80000000;
+	uint16_t hfn_pdb_offset;
+
+	if (rta_sec_era == RTA_SEC_ERA_2 && !era_2_sw_hfn_ovrd)
+		return 0;
+
+	switch (pdb_type) {
+	case PDCP_PDB_TYPE_NO_PDB:
+		/*
+		 * If there is no PDB, then HFN override mechanism does not
+		 * make any sense, thus in this case the function will
+		 * return the pointer to the current position in the
+		 * descriptor buffer
+		 */
+		return 0;
+
+	case PDCP_PDB_TYPE_REDUCED_PDB:
+		hfn_pdb_offset = 4;
+		break;
+
+	case PDCP_PDB_TYPE_FULL_PDB:
+		hfn_pdb_offset = 8;
+		break;
+
+	default:
+		return -EINVAL;
+	}
+
+	if (rta_sec_era > RTA_SEC_ERA_2) {
+		MATHB(p, DPOVRD, AND, imm, NONE, 8, IFB | IMMED2);
+	} else {
+		SEQLOAD(p, MATH0, 4, 4, 0);
+		JUMP(p, 1, LOCAL_JUMP, ALL_TRUE, CALM);
+		MATHB(p, MATH0, AND, imm, NONE, 8, IFB | IMMED2);
+		SEQSTORE(p, MATH0, 4, 4, 0);
+	}
+
+	JUMP(p, 5, LOCAL_JUMP, ALL_TRUE, MATH_Z);
+
+	if (rta_sec_era > RTA_SEC_ERA_2)
+		MATHB(p, DPOVRD, LSHIFT, shift, MATH0, 4, IMMED2);
+	else
+		MATHB(p, MATH0, LSHIFT, shift, MATH0, 4, IMMED2);
+
+	MATHB(p, MATH0, SHLD, MATH0, MATH0, 8, 0);
+	MOVE(p, MATH0, 0, DESCBUF, hfn_pdb_offset, 4, IMMED);
+
+	return 0;
+}
+
+/*
+ * PDCP Control PDB creation function
+ */
+static inline enum pdb_type_e
+cnstr_pdcp_c_plane_pdb(struct program *p,
+		       uint32_t hfn,
+		       unsigned char bearer,
+		       unsigned char direction,
+		       uint32_t hfn_threshold,
+		       struct alginfo *cipherdata,
+		       struct alginfo *authdata)
+{
+	struct pdcp_pdb pdb;
+	enum pdb_type_e
+		pdb_mask[PDCP_CIPHER_TYPE_INVALID][PDCP_AUTH_TYPE_INVALID] = {
+			{	/* NULL */
+				PDCP_PDB_TYPE_NO_PDB,		/* NULL */
+				PDCP_PDB_TYPE_FULL_PDB,		/* SNOW f9 */
+				PDCP_PDB_TYPE_FULL_PDB,		/* AES CMAC */
+				PDCP_PDB_TYPE_FULL_PDB		/* ZUC-I */
+			},
+			{	/* SNOW f8 */
+				PDCP_PDB_TYPE_FULL_PDB,		/* NULL */
+				PDCP_PDB_TYPE_FULL_PDB,		/* SNOW f9 */
+				PDCP_PDB_TYPE_REDUCED_PDB,	/* AES CMAC */
+				PDCP_PDB_TYPE_REDUCED_PDB	/* ZUC-I */
+			},
+			{	/* AES CTR */
+				PDCP_PDB_TYPE_FULL_PDB,		/* NULL */
+				PDCP_PDB_TYPE_REDUCED_PDB,	/* SNOW f9 */
+				PDCP_PDB_TYPE_FULL_PDB,		/* AES CMAC */
+				PDCP_PDB_TYPE_REDUCED_PDB	/* ZUC-I */
+			},
+			{	/* ZUC-E */
+				PDCP_PDB_TYPE_FULL_PDB,		/* NULL */
+				PDCP_PDB_TYPE_REDUCED_PDB,	/* SNOW f9 */
+				PDCP_PDB_TYPE_REDUCED_PDB,	/* AES CMAC */
+				PDCP_PDB_TYPE_FULL_PDB		/* ZUC-I */
+			},
+	};
+
+	if (rta_sec_era >= RTA_SEC_ERA_8) {
+		memset(&pdb, 0x00, sizeof(struct pdcp_pdb));
+
+		/* This is a HW issue. Bit 2 should be set to zero,
+		 * but it does not work this way. Override here.
+		 */
+		pdb.opt_res.rsvd = 0x00000002;
+
+		/* Copy relevant information from user to PDB */
+		pdb.hfn_res = hfn << PDCP_C_PLANE_PDB_HFN_SHIFT;
+		pdb.bearer_dir_res = (uint32_t)
+				((bearer << PDCP_C_PLANE_PDB_BEARER_SHIFT) |
+				 (direction << PDCP_C_PLANE_PDB_DIR_SHIFT));
+		pdb.hfn_thr_res =
+				hfn_threshold << PDCP_C_PLANE_PDB_HFN_THR_SHIFT;
+
+		/* copy PDB in descriptor*/
+		__rta_out32(p, pdb.opt_res.opt);
+		__rta_out32(p, pdb.hfn_res);
+		__rta_out32(p, pdb.bearer_dir_res);
+		__rta_out32(p, pdb.hfn_thr_res);
+
+		return PDCP_PDB_TYPE_FULL_PDB;
+	}
+
+	switch (pdb_mask[cipherdata->algtype][authdata->algtype]) {
+	case PDCP_PDB_TYPE_NO_PDB:
+		break;
+
+	case PDCP_PDB_TYPE_REDUCED_PDB:
+		__rta_out32(p, (hfn << PDCP_C_PLANE_PDB_HFN_SHIFT));
+		__rta_out32(p,
+			    (uint32_t)((bearer <<
+					PDCP_C_PLANE_PDB_BEARER_SHIFT) |
+					(direction <<
+					 PDCP_C_PLANE_PDB_DIR_SHIFT)));
+		break;
+
+	case PDCP_PDB_TYPE_FULL_PDB:
+		memset(&pdb, 0x00, sizeof(struct pdcp_pdb));
+
+		/* This is a HW issue. Bit 2 should be set to zero,
+		 * but it does not work this way. Override here.
+		 */
+		pdb.opt_res.rsvd = 0x00000002;
+
+		/* Copy relevant information from user to PDB */
+		pdb.hfn_res = hfn << PDCP_C_PLANE_PDB_HFN_SHIFT;
+		pdb.bearer_dir_res = (uint32_t)
+			((bearer << PDCP_C_PLANE_PDB_BEARER_SHIFT) |
+			 (direction << PDCP_C_PLANE_PDB_DIR_SHIFT));
+		pdb.hfn_thr_res =
+			hfn_threshold << PDCP_C_PLANE_PDB_HFN_THR_SHIFT;
+
+		/* copy PDB in descriptor*/
+		__rta_out32(p, pdb.opt_res.opt);
+		__rta_out32(p, pdb.hfn_res);
+		__rta_out32(p, pdb.bearer_dir_res);
+		__rta_out32(p, pdb.hfn_thr_res);
+
+		break;
+
+	default:
+		return PDCP_PDB_TYPE_INVALID;
+	}
+
+	return pdb_mask[cipherdata->algtype][authdata->algtype];
+}
+
+/*
+ * PDCP UPlane PDB creation function
+ */
+static inline int
+cnstr_pdcp_u_plane_pdb(struct program *p,
+		       enum pdcp_sn_size sn_size,
+		       uint32_t hfn, unsigned short bearer,
+		       unsigned short direction,
+		       uint32_t hfn_threshold)
+{
+	struct pdcp_pdb pdb;
+	/* Read options from user */
+	/* Depending on sequence number length, the HFN and HFN threshold
+	 * have different lengths.
+	 */
+	memset(&pdb, 0x00, sizeof(struct pdcp_pdb));
+
+	switch (sn_size) {
+	case PDCP_SN_SIZE_7:
+		pdb.opt_res.opt |= PDCP_U_PLANE_PDB_OPT_SHORT_SN;
+		pdb.hfn_res = hfn << PDCP_U_PLANE_PDB_SHORT_SN_HFN_SHIFT;
+		pdb.hfn_thr_res =
+			hfn_threshold<<PDCP_U_PLANE_PDB_SHORT_SN_HFN_THR_SHIFT;
+		break;
+
+	case PDCP_SN_SIZE_12:
+		pdb.opt_res.opt &= (uint32_t)(~PDCP_U_PLANE_PDB_OPT_SHORT_SN);
+		pdb.hfn_res = hfn << PDCP_U_PLANE_PDB_LONG_SN_HFN_SHIFT;
+		pdb.hfn_thr_res =
+			hfn_threshold<<PDCP_U_PLANE_PDB_LONG_SN_HFN_THR_SHIFT;
+		break;
+
+	case PDCP_SN_SIZE_15:
+		pdb.opt_res.opt = (uint32_t)(PDCP_U_PLANE_PDB_OPT_15B_SN);
+		pdb.hfn_res = hfn << PDCP_U_PLANE_PDB_15BIT_SN_HFN_SHIFT;
+		pdb.hfn_thr_res =
+			hfn_threshold<<PDCP_U_PLANE_PDB_15BIT_SN_HFN_THR_SHIFT;
+		break;
+
+	default:
+		pr_err("Invalid Sequence Number Size setting in PDB\n");
+		return -EINVAL;
+	}
+
+	pdb.bearer_dir_res = (uint32_t)
+				((bearer << PDCP_U_PLANE_PDB_BEARER_SHIFT) |
+				 (direction << PDCP_U_PLANE_PDB_DIR_SHIFT));
+
+	/* copy PDB in descriptor*/
+	__rta_out32(p, pdb.opt_res.opt);
+	__rta_out32(p, pdb.hfn_res);
+	__rta_out32(p, pdb.bearer_dir_res);
+	__rta_out32(p, pdb.hfn_thr_res);
+
+	return 0;
+}
+/**
+ * cnstr_shdsc_pdcp_c_plane_encap - Function for creating a PDCP Control Plane
+ *                                  encapsulation descriptor.
+ * @descbuf: pointer to buffer for descriptor construction
+ * @ps: if 36/40bit addressing is desired, this parameter must be true
+ * @swap: must be true when core endianness doesn't match SEC endianness
+ * @hfn: starting Hyper Frame Number to be used together with the SN from the
+ *       PDCP frames.
+ * @bearer: radio bearer ID
+ * @direction: the direction of the PDCP frame (UL/DL)
+ * @hfn_threshold: HFN value that once reached triggers a warning from SEC that
+ *                 keys should be renegotiated at the earliest convenience.
+ * @cipherdata: pointer to block cipher transform definitions
+ *              Valid algorithm values are those from cipher_type_pdcp enum.
+ * @authdata: pointer to authentication transform definitions
+ *            Valid algorithm values are those from auth_type_pdcp enum.
+ * @era_2_sw_hfn_ovrd: if software HFN override mechanism is desired for
+ *                     this descriptor. Note: Can only be used for
+ *                     SEC ERA 2.
+ * Return: size of descriptor written in words or negative number on error.
+ *         Once the function returns, the value of this parameter can be used
+ *         for reclaiming the space that wasn't used for the descriptor.
+ *
+ * Note: descbuf must be large enough to contain a full 256 byte long
+ * descriptor; after the function returns, by subtracting the actual number of
+ * bytes used, the user can reuse the remaining buffer space for other purposes.
+ */
+static inline int
+cnstr_shdsc_pdcp_c_plane_encap(uint32_t *descbuf,
+			       bool ps,
+			       bool swap,
+			       uint32_t hfn,
+			       unsigned char bearer,
+			       unsigned char direction,
+			       uint32_t hfn_threshold,
+			       struct alginfo *cipherdata,
+			       struct alginfo *authdata,
+			       unsigned char era_2_sw_hfn_ovrd)
+{
+	static int
+		(*pdcp_cp_fp[PDCP_CIPHER_TYPE_INVALID][PDCP_AUTH_TYPE_INVALID])
+			(struct program*, struct alginfo *,
+			 struct alginfo *, unsigned,
+			unsigned char __maybe_unused) = {
+		{	/* NULL */
+			pdcp_insert_cplane_null_op,	/* NULL */
+			pdcp_insert_cplane_int_only_op,	/* SNOW f9 */
+			pdcp_insert_cplane_int_only_op,	/* AES CMAC */
+			pdcp_insert_cplane_int_only_op	/* ZUC-I */
+		},
+		{	/* SNOW f8 */
+			pdcp_insert_cplane_enc_only_op,	/* NULL */
+			pdcp_insert_cplane_acc_op,	/* SNOW f9 */
+			pdcp_insert_cplane_snow_aes_op,	/* AES CMAC */
+			pdcp_insert_cplane_snow_zuc_op	/* ZUC-I */
+		},
+		{	/* AES CTR */
+			pdcp_insert_cplane_enc_only_op,	/* NULL */
+			pdcp_insert_cplane_aes_snow_op,	/* SNOW f9 */
+			pdcp_insert_cplane_acc_op,	/* AES CMAC */
+			pdcp_insert_cplane_aes_zuc_op	/* ZUC-I */
+		},
+		{	/* ZUC-E */
+			pdcp_insert_cplane_enc_only_op,	/* NULL */
+			pdcp_insert_cplane_zuc_snow_op,	/* SNOW f9 */
+			pdcp_insert_cplane_zuc_aes_op,	/* AES CMAC */
+			pdcp_insert_cplane_acc_op	/* ZUC-I */
+		},
+	};
+	static enum rta_share_type
+		desc_share[PDCP_CIPHER_TYPE_INVALID][PDCP_AUTH_TYPE_INVALID] = {
+		{	/* NULL */
+			SHR_WAIT,	/* NULL */
+			SHR_ALWAYS,	/* SNOW f9 */
+			SHR_ALWAYS,	/* AES CMAC */
+			SHR_ALWAYS	/* ZUC-I */
+		},
+		{	/* SNOW f8 */
+			SHR_ALWAYS,	/* NULL */
+			SHR_ALWAYS,	/* SNOW f9 */
+			SHR_WAIT,	/* AES CMAC */
+			SHR_WAIT	/* ZUC-I */
+		},
+		{	/* AES CTR */
+			SHR_ALWAYS,	/* NULL */
+			SHR_ALWAYS,	/* SNOW f9 */
+			SHR_ALWAYS,	/* AES CMAC */
+			SHR_WAIT	/* ZUC-I */
+		},
+		{	/* ZUC-E */
+			SHR_ALWAYS,	/* NULL */
+			SHR_WAIT,	/* SNOW f9 */
+			SHR_WAIT,	/* AES CMAC */
+			SHR_ALWAYS	/* ZUC-I */
+		},
+	};
+	enum pdb_type_e pdb_type;
+	struct program prg;
+	struct program *p = &prg;
+	int err;
+	LABEL(pdb_end);
+
+	if (rta_sec_era != RTA_SEC_ERA_2 && era_2_sw_hfn_ovrd) {
+		pr_err("Cannot select SW HFN override for other era than 2");
+		return -EINVAL;
+	}
+
+	PROGRAM_CNTXT_INIT(p, descbuf, 0);
+	if (swap)
+		PROGRAM_SET_BSWAP(p);
+	if (ps)
+		PROGRAM_SET_36BIT_ADDR(p);
+
+	SHR_HDR(p, desc_share[cipherdata->algtype][authdata->algtype], 0, 0);
+
+	pdb_type = cnstr_pdcp_c_plane_pdb(p,
+			hfn,
+			bearer,
+			direction,
+			hfn_threshold,
+			cipherdata,
+			authdata);
+
+	SET_LABEL(p, pdb_end);
+
+	err = insert_hfn_ov_op(p, PDCP_SN_SIZE_5, pdb_type,
+			       era_2_sw_hfn_ovrd);
+	if (err)
+		return err;
+
+	err = pdcp_cp_fp[cipherdata->algtype][authdata->algtype](p,
+		cipherdata,
+		authdata,
+		OP_TYPE_ENCAP_PROTOCOL,
+		era_2_sw_hfn_ovrd);
+	if (err)
+		return err;
+
+	PATCH_HDR(p, 0, pdb_end);
+
+	return PROGRAM_FINALIZE(p);
+}
+
+/**
+ * cnstr_shdsc_pdcp_c_plane_decap - Function for creating a PDCP Control Plane
+ *                                  decapsulation descriptor.
+ * @descbuf: pointer to buffer for descriptor construction
+ * @ps: if 36/40bit addressing is desired, this parameter must be true
+ * @swap: must be true when core endianness doesn't match SEC endianness
+ * @hfn: starting Hyper Frame Number to be used together with the SN from the
+ *       PDCP frames.
+ * @bearer: radio bearer ID
+ * @direction: the direction of the PDCP frame (UL/DL)
+ * @hfn_threshold: HFN value that once reached triggers a warning from SEC that
+ *                 keys should be renegotiated at the earliest convenience.
+ * @cipherdata: pointer to block cipher transform definitions
+ *              Valid algorithm values are those from cipher_type_pdcp enum.
+ * @authdata: pointer to authentication transform definitions
+ *            Valid algorithm values are those from auth_type_pdcp enum.
+ * @era_2_sw_hfn_ovrd: if software HFN override mechanism is desired for
+ *                     this descriptor. Note: Can only be used for
+ *                     SEC ERA 2.
+ *
+ * Return: size of descriptor written in words or negative number on error.
+ *         Once the function returns, the value of this parameter can be used
+ *         for reclaiming the space that wasn't used for the descriptor.
+ *
+ * Note: descbuf must be large enough to contain a full 256 byte long
+ * descriptor; after the function returns, by subtracting the actual number of
+ * bytes used, the user can reuse the remaining buffer space for other purposes.
+ */
+static inline int
+cnstr_shdsc_pdcp_c_plane_decap(uint32_t *descbuf,
+			       bool ps,
+			       bool swap,
+			       uint32_t hfn,
+			       unsigned char bearer,
+			       unsigned char direction,
+			       uint32_t hfn_threshold,
+			       struct alginfo *cipherdata,
+			       struct alginfo *authdata,
+			       unsigned char era_2_sw_hfn_ovrd)
+{
+	static int
+		(*pdcp_cp_fp[PDCP_CIPHER_TYPE_INVALID][PDCP_AUTH_TYPE_INVALID])
+			(struct program*, struct alginfo *,
+			 struct alginfo *, unsigned, unsigned char) = {
+		{	/* NULL */
+			pdcp_insert_cplane_null_op,	/* NULL */
+			pdcp_insert_cplane_int_only_op,	/* SNOW f9 */
+			pdcp_insert_cplane_int_only_op,	/* AES CMAC */
+			pdcp_insert_cplane_int_only_op	/* ZUC-I */
+		},
+		{	/* SNOW f8 */
+			pdcp_insert_cplane_enc_only_op,	/* NULL */
+			pdcp_insert_cplane_acc_op,	/* SNOW f9 */
+			pdcp_insert_cplane_snow_aes_op,	/* AES CMAC */
+			pdcp_insert_cplane_snow_zuc_op	/* ZUC-I */
+		},
+		{	/* AES CTR */
+			pdcp_insert_cplane_enc_only_op,	/* NULL */
+			pdcp_insert_cplane_aes_snow_op,	/* SNOW f9 */
+			pdcp_insert_cplane_acc_op,	/* AES CMAC */
+			pdcp_insert_cplane_aes_zuc_op	/* ZUC-I */
+		},
+		{	/* ZUC-E */
+			pdcp_insert_cplane_enc_only_op,	/* NULL */
+			pdcp_insert_cplane_zuc_snow_op,	/* SNOW f9 */
+			pdcp_insert_cplane_zuc_aes_op,	/* AES CMAC */
+			pdcp_insert_cplane_acc_op	/* ZUC-I */
+		},
+	};
+	static enum rta_share_type
+		desc_share[PDCP_CIPHER_TYPE_INVALID][PDCP_AUTH_TYPE_INVALID] = {
+		{	/* NULL */
+			SHR_WAIT,	/* NULL */
+			SHR_ALWAYS,	/* SNOW f9 */
+			SHR_ALWAYS,	/* AES CMAC */
+			SHR_ALWAYS	/* ZUC-I */
+		},
+		{	/* SNOW f8 */
+			SHR_ALWAYS,	/* NULL */
+			SHR_ALWAYS,	/* SNOW f9 */
+			SHR_WAIT,	/* AES CMAC */
+			SHR_WAIT	/* ZUC-I */
+		},
+		{	/* AES CTR */
+			SHR_ALWAYS,	/* NULL */
+			SHR_ALWAYS,	/* SNOW f9 */
+			SHR_ALWAYS,	/* AES CMAC */
+			SHR_WAIT	/* ZUC-I */
+		},
+		{	/* ZUC-E */
+			SHR_ALWAYS,	/* NULL */
+			SHR_WAIT,	/* SNOW f9 */
+			SHR_WAIT,	/* AES CMAC */
+			SHR_ALWAYS	/* ZUC-I */
+		},
+	};
+	enum pdb_type_e pdb_type;
+	struct program prg;
+	struct program *p = &prg;
+	int err;
+	LABEL(pdb_end);
+
+	if (rta_sec_era != RTA_SEC_ERA_2 && era_2_sw_hfn_ovrd) {
+		pr_err("Cannot select SW HFN override for other era than 2");
+		return -EINVAL;
+	}
+
+	PROGRAM_CNTXT_INIT(p, descbuf, 0);
+	if (swap)
+		PROGRAM_SET_BSWAP(p);
+	if (ps)
+		PROGRAM_SET_36BIT_ADDR(p);
+
+	SHR_HDR(p, desc_share[cipherdata->algtype][authdata->algtype], 0, 0);
+
+	pdb_type = cnstr_pdcp_c_plane_pdb(p,
+			hfn,
+			bearer,
+			direction,
+			hfn_threshold,
+			cipherdata,
+			authdata);
+
+	SET_LABEL(p, pdb_end);
+
+	err = insert_hfn_ov_op(p, PDCP_SN_SIZE_5, pdb_type,
+			       era_2_sw_hfn_ovrd);
+	if (err)
+		return err;
+
+	err = pdcp_cp_fp[cipherdata->algtype][authdata->algtype](p,
+		cipherdata,
+		authdata,
+		OP_TYPE_DECAP_PROTOCOL,
+		era_2_sw_hfn_ovrd);
+	if (err)
+		return err;
+
+	PATCH_HDR(p, 0, pdb_end);
+
+	return PROGRAM_FINALIZE(p);
+}
+
+/**
+ * cnstr_shdsc_pdcp_u_plane_encap - Function for creating a PDCP User Plane
+ *                                  encapsulation descriptor.
+ * @descbuf: pointer to buffer for descriptor construction
+ * @ps: if 36/40bit addressing is desired, this parameter must be true
+ * @swap: must be true when core endianness doesn't match SEC endianness
+ * @sn_size: selects Sequence Number Size: 7/12/15 bits
+ * @hfn: starting Hyper Frame Number to be used together with the SN from the
+ *       PDCP frames.
+ * @bearer: radio bearer ID
+ * @direction: the direction of the PDCP frame (UL/DL)
+ * @hfn_threshold: HFN value that once reached triggers a warning from SEC that
+ *                 keys should be renegotiated at the earliest convenience.
+ * @cipherdata: pointer to block cipher transform definitions
+ *              Valid algorithm values are those from cipher_type_pdcp enum.
+ * @era_2_sw_hfn_ovrd: if software HFN override mechanism is desired for
+ *                     this descriptor. Note: Can only be used for
+ *                     SEC ERA 2.
+ *
+ * Return: size of descriptor written in words or negative number on error.
+ *         Once the function returns, the value of this parameter can be used
+ *         for reclaiming the space that wasn't used for the descriptor.
+ *
+ * Note: descbuf must be large enough to contain a full 256 byte long
+ * descriptor; after the function returns, by subtracting the actual number of
+ * bytes used, the user can reuse the remaining buffer space for other purposes.
+ */
+static inline int
+cnstr_shdsc_pdcp_u_plane_encap(uint32_t *descbuf,
+			       bool ps,
+			       bool swap,
+			       enum pdcp_sn_size sn_size,
+			       uint32_t hfn,
+			       unsigned short bearer,
+			       unsigned short direction,
+			       uint32_t hfn_threshold,
+			       struct alginfo *cipherdata,
+			       unsigned char era_2_sw_hfn_ovrd)
+{
+	struct program prg;
+	struct program *p = &prg;
+	int err;
+	LABEL(pdb_end);
+
+	if (rta_sec_era != RTA_SEC_ERA_2 && era_2_sw_hfn_ovrd) {
+		pr_err("Cannot select SW HFN ovrd for other era than 2");
+		return -EINVAL;
+	}
+
+	PROGRAM_CNTXT_INIT(p, descbuf, 0);
+	if (swap)
+		PROGRAM_SET_BSWAP(p);
+	if (ps)
+		PROGRAM_SET_36BIT_ADDR(p);
+
+	SHR_HDR(p, SHR_ALWAYS, 0, 0);
+	if (cnstr_pdcp_u_plane_pdb(p, sn_size, hfn, bearer, direction,
+				   hfn_threshold)) {
+		pr_err("Error creating PDCP UPlane PDB\n");
+		return -EINVAL;
+	}
+	SET_LABEL(p, pdb_end);
+
+	err = insert_hfn_ov_op(p, sn_size, PDCP_PDB_TYPE_FULL_PDB,
+			       era_2_sw_hfn_ovrd);
+	if (err)
+		return err;
+
+	switch (sn_size) {
+	case PDCP_SN_SIZE_7:
+	case PDCP_SN_SIZE_12:
+		switch (cipherdata->algtype) {
+		case PDCP_CIPHER_TYPE_ZUC:
+			if (rta_sec_era < RTA_SEC_ERA_5) {
+				pr_err("Invalid era for selected algorithm\n");
+				return -ENOTSUP;
+			}
+		case PDCP_CIPHER_TYPE_AES:
+		case PDCP_CIPHER_TYPE_SNOW:
+			/* Insert Cipher Key */
+			KEY(p, KEY1, cipherdata->key_enc_flags,
+			    (uint64_t)cipherdata->key, cipherdata->keylen,
+			    INLINE_KEY(cipherdata));
+			PROTOCOL(p, OP_TYPE_ENCAP_PROTOCOL,
+				 OP_PCLID_LTE_PDCP_USER,
+				 (uint16_t)cipherdata->algtype);
+			break;
+		case PDCP_CIPHER_TYPE_NULL:
+			insert_copy_frame_op(p,
+					     cipherdata,
+					     OP_TYPE_ENCAP_PROTOCOL);
+			break;
+		default:
+			pr_err("%s: Invalid encrypt algorithm selected: %d\n",
+			       "cnstr_pcl_shdsc_pdcp_u_plane_decap",
+			       cipherdata->algtype);
+			return -EINVAL;
+		}
+		break;
+
+	case PDCP_SN_SIZE_15:
+		switch (cipherdata->algtype) {
+		case PDCP_CIPHER_TYPE_NULL:
+			insert_copy_frame_op(p,
+					     cipherdata,
+					     OP_TYPE_ENCAP_PROTOCOL);
+			break;
+
+		default:
+			err = pdcp_insert_uplane_15bit_op(p, cipherdata,
+				OP_TYPE_ENCAP_PROTOCOL);
+			if (err)
+				return err;
+			break;
+		}
+		break;
+
+	case PDCP_SN_SIZE_5:
+	default:
+		pr_err("Invalid SN size selected\n");
+		return -ENOTSUP;
+	}
+
+	PATCH_HDR(p, 0, pdb_end);
+	return PROGRAM_FINALIZE(p);
+}
+
+/**
+ * cnstr_shdsc_pdcp_u_plane_decap - Function for creating a PDCP User Plane
+ *                                  decapsulation descriptor.
+ * @descbuf: pointer to buffer for descriptor construction
+ * @ps: if 36/40bit addressing is desired, this parameter must be true
+ * @swap: must be true when core endianness doesn't match SEC endianness
+ * @sn_size: selects Sequence Number Size: 7/12/15 bits
+ * @hfn: starting Hyper Frame Number to be used together with the SN from the
+ *       PDCP frames.
+ * @bearer: radio bearer ID
+ * @direction: the direction of the PDCP frame (UL/DL)
+ * @hfn_threshold: HFN value that once reached triggers a warning from SEC that
+ *                 keys should be renegotiated at the earliest convenience.
+ * @cipherdata: pointer to block cipher transform definitions
+ *              Valid algorithm values are those from cipher_type_pdcp enum.
+ * @era_2_sw_hfn_ovrd: if software HFN override mechanism is desired for
+ *                     this descriptor. Note: Can only be used for
+ *                     SEC ERA 2.
+ *
+ * Return: size of descriptor written in words or negative number on error.
+ *         Once the function returns, the value of this parameter can be used
+ *         for reclaiming the space that wasn't used for the descriptor.
+ *
+ * Note: descbuf must be large enough to contain a full 256 byte long
+ * descriptor; after the function returns, by subtracting the actual number of
+ * bytes used, the user can reuse the remaining buffer space for other purposes.
+ */
+static inline int
+cnstr_shdsc_pdcp_u_plane_decap(uint32_t *descbuf,
+			       bool ps,
+			       bool swap,
+			       enum pdcp_sn_size sn_size,
+			       uint32_t hfn,
+			       unsigned short bearer,
+			       unsigned short direction,
+			       uint32_t hfn_threshold,
+			       struct alginfo *cipherdata,
+			       unsigned char era_2_sw_hfn_ovrd)
+{
+	struct program prg;
+	struct program *p = &prg;
+	int err;
+	LABEL(pdb_end);
+
+	if (rta_sec_era != RTA_SEC_ERA_2 && era_2_sw_hfn_ovrd) {
+		pr_err("Cannot select SW HFN override for other era than 2");
+		return -EINVAL;
+	}
+
+	PROGRAM_CNTXT_INIT(p, descbuf, 0);
+	if (swap)
+		PROGRAM_SET_BSWAP(p);
+	if (ps)
+		PROGRAM_SET_36BIT_ADDR(p);
+
+	SHR_HDR(p, SHR_ALWAYS, 0, 0);
+	if (cnstr_pdcp_u_plane_pdb(p, sn_size, hfn, bearer, direction,
+				   hfn_threshold)) {
+		pr_err("Error creating PDCP UPlane PDB\n");
+		return -EINVAL;
+	}
+	SET_LABEL(p, pdb_end);
+
+	err = insert_hfn_ov_op(p, sn_size, PDCP_PDB_TYPE_FULL_PDB,
+			       era_2_sw_hfn_ovrd);
+	if (err)
+		return err;
+
+	switch (sn_size) {
+	case PDCP_SN_SIZE_7:
+	case PDCP_SN_SIZE_12:
+		switch (cipherdata->algtype) {
+		case PDCP_CIPHER_TYPE_ZUC:
+			if (rta_sec_era < RTA_SEC_ERA_5) {
+				pr_err("Invalid era for selected algorithm\n");
+				return -ENOTSUP;
+			}
+		case PDCP_CIPHER_TYPE_AES:
+		case PDCP_CIPHER_TYPE_SNOW:
+			/* Insert Cipher Key */
+			KEY(p, KEY1, cipherdata->key_enc_flags,
+			    cipherdata->key, cipherdata->keylen,
+			    INLINE_KEY(cipherdata));
+			PROTOCOL(p, OP_TYPE_DECAP_PROTOCOL,
+				 OP_PCLID_LTE_PDCP_USER,
+				 (uint16_t)cipherdata->algtype);
+			break;
+		case PDCP_CIPHER_TYPE_NULL:
+			insert_copy_frame_op(p,
+					     cipherdata,
+					     OP_TYPE_DECAP_PROTOCOL);
+			break;
+		default:
+			pr_err("%s: Invalid encrypt algorithm selected: %d\n",
+			       "cnstr_pcl_shdsc_pdcp_u_plane_decap",
+			       cipherdata->algtype);
+			return -EINVAL;
+		}
+		break;
+
+	case PDCP_SN_SIZE_15:
+		switch (cipherdata->algtype) {
+		case PDCP_CIPHER_TYPE_NULL:
+			insert_copy_frame_op(p,
+					     cipherdata,
+					     OP_TYPE_DECAP_PROTOCOL);
+			break;
+
+		default:
+			err = pdcp_insert_uplane_15bit_op(p, cipherdata,
+				OP_TYPE_DECAP_PROTOCOL);
+			if (err)
+				return err;
+			break;
+		}
+		break;
+
+	case PDCP_SN_SIZE_5:
+	default:
+		pr_err("Invalid SN size selected\n");
+		return -ENOTSUP;
+	}
+
+	PATCH_HDR(p, 0, pdb_end);
+	return PROGRAM_FINALIZE(p);
+}
+
+/**
+ * cnstr_shdsc_pdcp_short_mac - Function for creating a PDCP Short MAC
+ *                              descriptor.
+ * @descbuf: pointer to buffer for descriptor construction
+ * @ps: if 36/40bit addressing is desired, this parameter must be true
+ * @swap: must be true when core endianness doesn't match SEC endianness
+ * @authdata: pointer to authentication transform definitions
+ *            Valid algorithm values are those from auth_type_pdcp enum.
+ *
+ * Return: size of descriptor written in words or negative number on error.
+ *         Once the function returns, the value of this parameter can be used
+ *         for reclaiming the space that wasn't used for the descriptor.
+ *
+ * Note: descbuf must be large enough to contain a full 256 byte long
+ * descriptor; after the function returns, by subtracting the actual number of
+ * bytes used, the user can reuse the remaining buffer space for other purposes.
+ */
+static inline int
+cnstr_shdsc_pdcp_short_mac(uint32_t *descbuf,
+			   bool ps,
+			   bool swap,
+			   struct alginfo *authdata)
+{
+	struct program prg;
+	struct program *p = &prg;
+	uint32_t iv[3] = {0, 0, 0};
+	LABEL(local_offset);
+	REFERENCE(move_cmd_read_descbuf);
+	REFERENCE(move_cmd_write_descbuf);
+
+	PROGRAM_CNTXT_INIT(p, descbuf, 0);
+	if (swap)
+		PROGRAM_SET_BSWAP(p);
+	if (ps)
+		PROGRAM_SET_36BIT_ADDR(p);
+
+	SHR_HDR(p, SHR_ALWAYS, 1, 0);
+
+	if (rta_sec_era > RTA_SEC_ERA_2) {
+		MATHB(p, SEQINSZ, SUB, ZERO, VSEQINSZ, 4, 0);
+		MATHB(p, SEQINSZ, SUB, ZERO, MATH1, 4, 0);
+	} else {
+		MATHB(p, SEQINSZ, ADD, ONE, MATH1, 4, 0);
+		MATHB(p, MATH1, SUB, ONE, MATH1, 4, 0);
+		MATHB(p, ZERO, ADD, MATH1, VSEQINSZ, 4, 0);
+		MOVE(p, MATH1, 0, MATH0, 0, 8, IMMED);
+
+		/*
+		 * Since MOVELEN is available only starting with
+		 * SEC ERA 3, use poor man's MOVELEN: create a MOVE
+		 * command dynamically by writing the length from M1 by
+		 * OR-ing the command in the M1 register and MOVE the
+		 * result into the descriptor buffer. Care must be taken
+		 * wrt. the location of the command because of SEC
+		 * pipelining. The actual MOVEs are written at the end
+		 * of the descriptor due to calculations needed on the
+		 * offset in the descriptor for the MOVE command.
+		 */
+		move_cmd_read_descbuf = MOVE(p, DESCBUF, 0, MATH0, 0, 6,
+					     IMMED);
+		move_cmd_write_descbuf = MOVE(p, MATH0, 0, DESCBUF, 0, 8,
+					      WAITCOMP | IMMED);
+	}
+	MATHB(p, ZERO, ADD, MATH1, VSEQOUTSZ, 4, 0);
+
+	switch (authdata->algtype) {
+	case PDCP_AUTH_TYPE_NULL:
+		SEQFIFOSTORE(p, MSG, 0, 0, VLF);
+		if (rta_sec_era > RTA_SEC_ERA_2) {
+			MOVE(p, AB1, 0, OFIFO, 0, MATH1, 0);
+		} else {
+			SET_LABEL(p, local_offset);
+
+			/* Shut off automatic Info FIFO entries */
+			LOAD(p, 0, DCTRL, LDOFF_DISABLE_AUTO_NFIFO, 0, IMMED);
+
+			/* Placeholder for MOVE command with length from M1
+			 * register
+			 */
+			MOVE(p, IFIFOAB1, 0, OFIFO, 0, 0, IMMED);
+
+			/* Enable automatic Info FIFO entries */
+			LOAD(p, 0, DCTRL, LDOFF_ENABLE_AUTO_NFIFO, 0, IMMED);
+		}
+
+		LOAD(p, (uintptr_t)iv, MATH0, 0, 8, IMMED | COPY);
+		SEQFIFOLOAD(p, MSG1, 0, VLF | LAST1 | LAST2 | FLUSH1);
+		SEQSTORE(p, MATH0, 0, 4, 0);
+
+		break;
+
+	case PDCP_AUTH_TYPE_SNOW:
+		iv[0] = 0xFFFFFFFF;
+		iv[1] = swap ? swab32(0x04000000) : 0x04000000;
+		iv[2] = swap ? swab32(0xF8000000) : 0xF8000000;
+
+		KEY(p, KEY2, authdata->key_enc_flags, authdata->key,
+		    authdata->keylen, INLINE_KEY(authdata));
+		LOAD(p, (uintptr_t)&iv, CONTEXT2, 0, 12, IMMED | COPY);
+		ALG_OPERATION(p, OP_ALG_ALGSEL_SNOW_F9,
+			      OP_ALG_AAI_F9,
+			      OP_ALG_AS_INITFINAL,
+			      ICV_CHECK_DISABLE,
+			      DIR_ENC);
+		SEQFIFOSTORE(p, MSG, 0, 0, VLF);
+
+		if (rta_sec_era > RTA_SEC_ERA_2) {
+			MOVE(p, AB1, 0, OFIFO, 0, MATH1, 0);
+		} else {
+			SET_LABEL(p, local_offset);
+
+
+			/* Shut off automatic Info FIFO entries */
+			LOAD(p, 0, DCTRL, LDOFF_DISABLE_AUTO_NFIFO, 0, IMMED);
+
+			/* Placeholder for MOVE command with length from M1
+			 * register */
+			MOVE(p, IFIFOAB1, 0, OFIFO, 0, 0, IMMED);
+
+			/* Enable automatic Info FIFO entries */
+			LOAD(p, 0, DCTRL, LDOFF_ENABLE_AUTO_NFIFO, 0, IMMED);
+		}
+		SEQFIFOLOAD(p, MSGINSNOOP, 0, VLF | LAST1 | LAST2 | FLUSH1);
+		SEQSTORE(p, CONTEXT2, 0, 4, 0);
+
+		break;
+
+	case PDCP_AUTH_TYPE_AES:
+		iv[0] = 0xFFFFFFFF;
+		iv[1] = swap ? swab32(0xFC000000) : 0xFC000000;
+		iv[2] = 0x00000000; /* unused */
+
+		KEY(p, KEY1, authdata->key_enc_flags, authdata->key,
+		    authdata->keylen, INLINE_KEY(authdata));
+		LOAD(p, (uintptr_t)&iv, MATH0, 0, 8, IMMED | COPY);
+		MOVE(p, MATH0, 0, IFIFOAB1, 0, 8, IMMED);
+		ALG_OPERATION(p, OP_ALG_ALGSEL_AES,
+			      OP_ALG_AAI_CMAC,
+			      OP_ALG_AS_INITFINAL,
+			      ICV_CHECK_DISABLE,
+			      DIR_ENC);
+		SEQFIFOSTORE(p, MSG, 0, 0, VLF);
+
+		if (rta_sec_era > RTA_SEC_ERA_2) {
+			MOVE(p, AB2, 0, OFIFO, 0, MATH1, 0);
+		} else {
+			SET_LABEL(p, local_offset);
+
+			/* Shut off automatic Info FIFO entries */
+			LOAD(p, 0, DCTRL, LDOFF_DISABLE_AUTO_NFIFO, 0, IMMED);
+
+			/* Placeholder for MOVE command with length from M1
+			 * register */
+			MOVE(p, IFIFOAB2, 0, OFIFO, 0, 0, IMMED);
+
+			/* Enable automatic Info FIFO entries */
+			LOAD(p, 0, DCTRL, LDOFF_ENABLE_AUTO_NFIFO, 0, IMMED);
+		}
+		SEQFIFOLOAD(p, MSGINSNOOP, 0, VLF | LAST1 | LAST2 | FLUSH1);
+		SEQSTORE(p, CONTEXT1, 0, 4, 0);
+
+		break;
+
+	case PDCP_AUTH_TYPE_ZUC:
+		if (rta_sec_era < RTA_SEC_ERA_5) {
+			pr_err("Invalid era for selected algorithm\n");
+			return -ENOTSUP;
+		}
+		iv[0] = 0xFFFFFFFF;
+		iv[1] = swap ? swab32(0xFC000000) : 0xFC000000;
+		iv[2] = 0x00000000; /* unused */
+
+		KEY(p, KEY2, authdata->key_enc_flags, authdata->key,
+		    authdata->keylen, INLINE_KEY(authdata));
+		LOAD(p, (uintptr_t)&iv, CONTEXT2, 0, 12, IMMED | COPY);
+		ALG_OPERATION(p, OP_ALG_ALGSEL_ZUCA,
+			      OP_ALG_AAI_F9,
+			      OP_ALG_AS_INITFINAL,
+			      ICV_CHECK_DISABLE,
+			      DIR_ENC);
+		SEQFIFOSTORE(p, MSG, 0, 0, VLF);
+		MOVE(p, AB1, 0, OFIFO, 0, MATH1, 0);
+		SEQFIFOLOAD(p, MSGINSNOOP, 0, VLF | LAST1 | LAST2 | FLUSH1);
+		SEQSTORE(p, CONTEXT2, 0, 4, 0);
+
+		break;
+
+	default:
+		pr_err("%s: Invalid integrity algorithm selected: %d\n",
+		       "cnstr_shdsc_pdcp_short_mac", authdata->algtype);
+		return -EINVAL;
+	}
+
+
+	if (rta_sec_era < RTA_SEC_ERA_3) {
+		PATCH_MOVE(p, move_cmd_read_descbuf, local_offset);
+		PATCH_MOVE(p, move_cmd_write_descbuf, local_offset);
+	}
+
+	return PROGRAM_FINALIZE(p);
+}
+
+#endif /* __DESC_PDCP_H__ */
-- 
2.17.1

^ permalink raw reply	[flat|nested] 41+ messages in thread

* [dpdk-dev] [PATCH v2 3/3] crypto/dpaa2_sec: support pdcp offload
  2018-10-05 13:33 ` [dpdk-dev] [PATCH v2 " akhil.goyal
  2018-10-05 13:33   ` [dpdk-dev] [PATCH v2 1/3] security: support pdcp protocol akhil.goyal
  2018-10-05 13:33   ` [dpdk-dev] [PATCH v2 2/3] crypto/dpaa2_sec: add sample pdcp descriptor apis akhil.goyal
@ 2018-10-05 13:33   ` akhil.goyal
  2018-10-05 13:53   ` [dpdk-dev] [PATCH v3 0/3] security: support for pdcp akhil.goyal
  3 siblings, 0 replies; 41+ messages in thread
From: akhil.goyal @ 2018-10-05 13:33 UTC (permalink / raw)
  To: dev
  Cc: pablo.de.lara.guarch, radu.nicolau, jerin.jacob,
	narayanaprasad.athreya, Shally.Verma, Anoob.Joseph,
	Vidya.Velumuri, hemant.agrawal, Akhil Goyal

From: Akhil Goyal <akhil.goyal@nxp.com>

PDCP session configuration for lookaside protocol offload
and data path is added.

Signed-off-by: Hemant Agrawal <hemant.agrawal@nxp.com>
Signed-off-by: Akhil Goyal <akhil.goyal@nxp.com>
---
 drivers/crypto/dpaa2_sec/dpaa2_sec_dpseci.c | 233 ++++++++++++++++++++
 drivers/crypto/dpaa2_sec/dpaa2_sec_priv.h   | 172 +++++++++++++++
 2 files changed, 405 insertions(+)

diff --git a/drivers/crypto/dpaa2_sec/dpaa2_sec_dpseci.c b/drivers/crypto/dpaa2_sec/dpaa2_sec_dpseci.c
index 265a8e41a..d263c9388 100644
--- a/drivers/crypto/dpaa2_sec/dpaa2_sec_dpseci.c
+++ b/drivers/crypto/dpaa2_sec/dpaa2_sec_dpseci.c
@@ -35,6 +35,7 @@ typedef uint64_t	dma_addr_t;
 
 /* RTA header files */
 #include <hw/desc/ipsec.h>
+#include <hw/desc/pdcp.h>
 #include <hw/desc/algo.h>
 
 /* Minimum job descriptor consists of a oneword job descriptor HEADER and
@@ -74,6 +75,9 @@ build_proto_compound_fd(dpaa2_sec_session *sess,
 	struct rte_mbuf *dst_mbuf = sym_op->m_dst;
 	int retval;
 
+	if (!dst_mbuf)
+		dst_mbuf = src_mbuf;
+
 	/* Save the shared descriptor */
 	flc = &priv->flc_desc[0].flc;
 
@@ -1188,6 +1192,9 @@ build_sec_fd(struct rte_crypto_op *op,
 		case DPAA2_SEC_IPSEC:
 			ret = build_proto_fd(sess, op, fd, bpid);
 			break;
+		case DPAA2_SEC_PDCP:
+			ret = build_proto_compound_fd(sess, op, fd, bpid);
+			break;
 		case DPAA2_SEC_HASH_CIPHER:
 		default:
 			DPAA2_SEC_ERR("error: Unsupported session");
@@ -2541,6 +2548,228 @@ dpaa2_sec_set_ipsec_session(struct rte_cryptodev *dev,
 	return ret;
 }
 
+static int
+dpaa2_sec_set_pdcp_session(struct rte_cryptodev *dev,
+			   struct rte_security_session_conf *conf,
+			   void *sess)
+{
+	struct rte_security_pdcp_xform *pdcp_xform = &conf->pdcp;
+	struct rte_crypto_sym_xform *xform = conf->crypto_xform;
+	struct rte_crypto_auth_xform *auth_xform = NULL;
+	struct rte_crypto_cipher_xform *cipher_xform;
+	dpaa2_sec_session *session = (dpaa2_sec_session *)sess;
+	struct ctxt_priv *priv;
+	struct dpaa2_sec_dev_private *dev_priv = dev->data->dev_private;
+	struct alginfo authdata, cipherdata;
+	int bufsize = -1;
+	struct sec_flow_context *flc;
+
+	PMD_INIT_FUNC_TRACE();
+
+	memset(session, 0, sizeof(dpaa2_sec_session));
+
+	priv = (struct ctxt_priv *)rte_zmalloc(NULL,
+				sizeof(struct ctxt_priv) +
+				sizeof(struct sec_flc_desc),
+				RTE_CACHE_LINE_SIZE);
+
+	if (priv == NULL) {
+		DPAA2_SEC_ERR("No memory for priv CTXT");
+		return -ENOMEM;
+	}
+
+	priv->fle_pool = dev_priv->fle_pool;
+	flc = &priv->flc_desc[0].flc;
+
+	/* find xfrm types */
+	if (xform->type == RTE_CRYPTO_SYM_XFORM_CIPHER && xform->next == NULL) {
+		cipher_xform = &xform->cipher;
+	} else if (xform->type == RTE_CRYPTO_SYM_XFORM_CIPHER &&
+		   xform->next->type == RTE_CRYPTO_SYM_XFORM_AUTH) {
+		session->ext_params.aead_ctxt.auth_cipher_text = true;
+		cipher_xform = &xform->cipher;
+		auth_xform = &xform->next->auth;
+	} else if (xform->type == RTE_CRYPTO_SYM_XFORM_AUTH &&
+		   xform->next->type == RTE_CRYPTO_SYM_XFORM_CIPHER) {
+		session->ext_params.aead_ctxt.auth_cipher_text = false;
+		cipher_xform = &xform->next->cipher;
+		auth_xform = &xform->auth;
+	} else {
+		DPAA2_SEC_ERR("Invalid crypto type");
+		return -EINVAL;
+	}
+
+	session->ctxt_type = DPAA2_SEC_PDCP;
+	if (cipher_xform) {
+		session->cipher_key.data = rte_zmalloc(NULL,
+					       cipher_xform->key.length,
+					       RTE_CACHE_LINE_SIZE);
+		if (session->cipher_key.data == NULL &&
+				cipher_xform->key.length > 0) {
+			DPAA2_SEC_ERR("No Memory for cipher key");
+			rte_free(priv);
+			return -ENOMEM;
+		}
+		session->cipher_key.length = cipher_xform->key.length;
+		memcpy(session->cipher_key.data, cipher_xform->key.data,
+			cipher_xform->key.length);
+		session->dir = (cipher_xform->op == RTE_CRYPTO_CIPHER_OP_ENCRYPT) ?
+					DIR_ENC : DIR_DEC;
+		session->cipher_alg = cipher_xform->algo;
+	} else {
+		session->cipher_key.data = NULL;
+		session->cipher_key.length = 0;
+		session->cipher_alg = RTE_CRYPTO_CIPHER_NULL;
+		session->dir = DIR_ENC;
+	}
+
+	cipherdata.key = (size_t)session->cipher_key.data;
+	cipherdata.keylen = session->cipher_key.length;
+	cipherdata.key_enc_flags = 0;
+	cipherdata.key_type = RTA_DATA_IMM;
+
+	switch (session->cipher_alg) {
+	case RTE_CRYPTO_CIPHER_SNOW3G_UEA2:
+		cipherdata.algtype = PDCP_CIPHER_TYPE_SNOW;
+		break;
+	case RTE_CRYPTO_CIPHER_ZUC_EEA3:
+		cipherdata.algtype = PDCP_CIPHER_TYPE_ZUC;
+		break;
+	case RTE_CRYPTO_CIPHER_AES_CTR:
+		cipherdata.algtype = PDCP_CIPHER_TYPE_AES;
+		break;
+	case RTE_CRYPTO_CIPHER_NULL:
+		cipherdata.algtype = PDCP_CIPHER_TYPE_NULL;
+		break;
+	default:
+		DPAA2_SEC_ERR("Crypto: Undefined Cipher specified %u",
+			      session->cipher_alg);
+		goto out;
+	}
+
+	/* Auth is only applicable for control mode operation. */
+	if (pdcp_xform->domain == RTE_SECURITY_PDCP_MODE_CONTROL) {
+		if (pdcp_xform->sn_size != RTE_SECURITY_PDCP_SN_SIZE_5) {
+			DPAA2_SEC_ERR(
+				"PDCP Seq Num size should be 5 bits for cmode");
+			goto out;
+		}
+		if (auth_xform) {
+			session->auth_key.data = rte_zmalloc(NULL,
+							auth_xform->key.length,
+							RTE_CACHE_LINE_SIZE);
+			if (session->auth_key.data == NULL &&
+					auth_xform->key.length > 0) {
+				DPAA2_SEC_ERR("No Memory for auth key");
+				rte_free(session->cipher_key.data);
+				rte_free(priv);
+				return -ENOMEM;
+			}
+			session->auth_key.length = auth_xform->key.length;
+			memcpy(session->auth_key.data, auth_xform->key.data,
+					auth_xform->key.length);
+			session->auth_alg = auth_xform->algo;
+		} else {
+			session->auth_key.data = NULL;
+			session->auth_key.length = 0;
+			session->auth_alg = RTE_CRYPTO_AUTH_NULL;
+		}
+		authdata.key = (size_t)session->auth_key.data;
+		authdata.keylen = session->auth_key.length;
+		authdata.key_enc_flags = 0;
+		authdata.key_type = RTA_DATA_IMM;
+
+		switch (session->auth_alg) {
+		case RTE_CRYPTO_AUTH_SNOW3G_UIA2:
+			authdata.algtype = PDCP_AUTH_TYPE_SNOW;
+			break;
+		case RTE_CRYPTO_AUTH_ZUC_EIA3:
+			authdata.algtype = PDCP_AUTH_TYPE_ZUC;
+			break;
+		case RTE_CRYPTO_AUTH_AES_CMAC:
+			authdata.algtype = PDCP_AUTH_TYPE_AES;
+			break;
+		case RTE_CRYPTO_AUTH_NULL:
+			authdata.algtype = PDCP_AUTH_TYPE_NULL;
+			break;
+		default:
+			DPAA2_SEC_ERR("Crypto: Unsupported auth alg %u",
+				      session->auth_alg);
+			goto out;
+		}
+
+		if (session->dir == DIR_ENC)
+			bufsize = cnstr_shdsc_pdcp_c_plane_encap(
+					priv->flc_desc[0].desc, 1, 0,
+					pdcp_xform->hfn,
+					pdcp_xform->bearer,
+					pdcp_xform->pkt_dir,
+					pdcp_xform->hfn_threshold,
+					&cipherdata, &authdata,
+					0);
+		else if (session->dir == DIR_DEC)
+			bufsize = cnstr_shdsc_pdcp_c_plane_decap(
+					priv->flc_desc[0].desc, 1, 0,
+					pdcp_xform->hfn,
+					pdcp_xform->bearer,
+					pdcp_xform->pkt_dir,
+					pdcp_xform->hfn_threshold,
+					&cipherdata, &authdata,
+					0);
+	} else {
+		if (session->dir == DIR_ENC)
+			bufsize = cnstr_shdsc_pdcp_u_plane_encap(
+					priv->flc_desc[0].desc, 1, 0,
+					pdcp_xform->sn_size,
+					pdcp_xform->hfn,
+					pdcp_xform->bearer,
+					pdcp_xform->pkt_dir,
+					pdcp_xform->hfn_threshold,
+					&cipherdata, 0);
+		else if (session->dir == DIR_DEC)
+			bufsize = cnstr_shdsc_pdcp_u_plane_decap(
+					priv->flc_desc[0].desc, 1, 0,
+					pdcp_xform->sn_size,
+					pdcp_xform->hfn,
+					pdcp_xform->bearer,
+					pdcp_xform->pkt_dir,
+					pdcp_xform->hfn_threshold,
+					&cipherdata, 0);
+	}
+
+	if (bufsize < 0) {
+		DPAA2_SEC_ERR("Crypto: Invalid buffer length");
+		goto out;
+	}
+
+	/* Enable the stashing control bit */
+	DPAA2_SET_FLC_RSC(flc);
+	flc->word2_rflc_31_0 = lower_32_bits(
+			(size_t)&(((struct dpaa2_sec_qp *)
+			dev->data->queue_pairs[0])->rx_vq) | 0x14);
+	flc->word3_rflc_63_32 = upper_32_bits(
+			(size_t)&(((struct dpaa2_sec_qp *)
+			dev->data->queue_pairs[0])->rx_vq));
+
+	flc->word1_sdl = (uint8_t)bufsize;
+
+	/* Set EWS bit i.e. enable write-safe */
+	DPAA2_SET_FLC_EWS(flc);
+	/* Set BS = 1 i.e reuse input buffers as output buffers */
+	DPAA2_SET_FLC_REUSE_BS(flc);
+	/* Set FF = 10; reuse input buffers if they provide sufficient space */
+	DPAA2_SET_FLC_REUSE_FF(flc);
+
+	session->ctxt = priv;
+
+	return 0;
+out:
+	rte_free(session->auth_key.data);
+	rte_free(session->cipher_key.data);
+	rte_free(priv);
+	return -1;
+}
+
 static int
 dpaa2_sec_security_session_create(void *dev,
 				  struct rte_security_session_conf *conf,
@@ -2563,6 +2792,10 @@ dpaa2_sec_security_session_create(void *dev,
 		break;
 	case RTE_SECURITY_PROTOCOL_MACSEC:
 		return -ENOTSUP;
+	case RTE_SECURITY_PROTOCOL_PDCP:
+		ret = dpaa2_sec_set_pdcp_session(cdev, conf,
+				sess_private_data);
+		break;
 	default:
 		return -EINVAL;
 	}
diff --git a/drivers/crypto/dpaa2_sec/dpaa2_sec_priv.h b/drivers/crypto/dpaa2_sec/dpaa2_sec_priv.h
index d015be1e9..907374346 100644
--- a/drivers/crypto/dpaa2_sec/dpaa2_sec_priv.h
+++ b/drivers/crypto/dpaa2_sec/dpaa2_sec_priv.h
@@ -390,6 +390,162 @@ static const struct rte_cryptodev_capabilities dpaa2_sec_capabilities[] = {
 	RTE_CRYPTODEV_END_OF_CAPABILITIES_LIST()
 };
 
+static const struct rte_cryptodev_capabilities dpaa2_pdcp_capabilities[] = {
+	{	/* SNOW 3G (UIA2) */
+		.op = RTE_CRYPTO_OP_TYPE_SYMMETRIC,
+		{.sym = {
+			.xform_type = RTE_CRYPTO_SYM_XFORM_AUTH,
+			{.auth = {
+				.algo = RTE_CRYPTO_AUTH_SNOW3G_UIA2,
+				.block_size = 16,
+				.key_size = {
+					.min = 16,
+					.max = 16,
+					.increment = 0
+				},
+				.digest_size = {
+					.min = 4,
+					.max = 4,
+					.increment = 0
+				},
+				.iv_size = {
+					.min = 16,
+					.max = 16,
+					.increment = 0
+				}
+			}, }
+		}, }
+	},
+	{	/* SNOW 3G (UEA2) */
+		.op = RTE_CRYPTO_OP_TYPE_SYMMETRIC,
+		{.sym = {
+			.xform_type = RTE_CRYPTO_SYM_XFORM_CIPHER,
+			{.cipher = {
+				.algo = RTE_CRYPTO_CIPHER_SNOW3G_UEA2,
+				.block_size = 16,
+				.key_size = {
+					.min = 16,
+					.max = 16,
+					.increment = 0
+				},
+				.iv_size = {
+					.min = 16,
+					.max = 16,
+					.increment = 0
+				}
+			}, }
+		}, }
+	},
+	{	/* AES CTR */
+		.op = RTE_CRYPTO_OP_TYPE_SYMMETRIC,
+		{.sym = {
+			.xform_type = RTE_CRYPTO_SYM_XFORM_CIPHER,
+			{.cipher = {
+				.algo = RTE_CRYPTO_CIPHER_AES_CTR,
+				.block_size = 16,
+				.key_size = {
+					.min = 16,
+					.max = 32,
+					.increment = 8
+				},
+				.iv_size = {
+					.min = 16,
+					.max = 16,
+					.increment = 0
+				}
+			}, }
+		}, }
+	},
+	{	/* NULL (AUTH) */
+		.op = RTE_CRYPTO_OP_TYPE_SYMMETRIC,
+		{.sym = {
+			.xform_type = RTE_CRYPTO_SYM_XFORM_AUTH,
+			{.auth = {
+				.algo = RTE_CRYPTO_AUTH_NULL,
+				.block_size = 1,
+				.key_size = {
+					.min = 0,
+					.max = 0,
+					.increment = 0
+				},
+				.digest_size = {
+					.min = 0,
+					.max = 0,
+					.increment = 0
+				},
+				.iv_size = { 0 }
+			}, },
+		}, },
+	},
+	{	/* NULL (CIPHER) */
+		.op = RTE_CRYPTO_OP_TYPE_SYMMETRIC,
+		{.sym = {
+			.xform_type = RTE_CRYPTO_SYM_XFORM_CIPHER,
+			{.cipher = {
+				.algo = RTE_CRYPTO_CIPHER_NULL,
+				.block_size = 1,
+				.key_size = {
+					.min = 0,
+					.max = 0,
+					.increment = 0
+				},
+				.iv_size = {
+					.min = 0,
+					.max = 0,
+					.increment = 0
+				}
+			}, },
+		}, }
+	},
+	{	/* ZUC (EEA3) */
+		.op = RTE_CRYPTO_OP_TYPE_SYMMETRIC,
+		{.sym = {
+			.xform_type = RTE_CRYPTO_SYM_XFORM_CIPHER,
+			{.cipher = {
+				.algo = RTE_CRYPTO_CIPHER_ZUC_EEA3,
+				.block_size = 16,
+				.key_size = {
+					.min = 16,
+					.max = 16,
+					.increment = 0
+				},
+				.iv_size = {
+					.min = 16,
+					.max = 16,
+					.increment = 0
+				}
+			}, }
+		}, }
+	},
+	{	/* ZUC (EIA3) */
+		.op = RTE_CRYPTO_OP_TYPE_SYMMETRIC,
+		{.sym = {
+			.xform_type = RTE_CRYPTO_SYM_XFORM_AUTH,
+			{.auth = {
+				.algo = RTE_CRYPTO_AUTH_ZUC_EIA3,
+				.block_size = 16,
+				.key_size = {
+					.min = 16,
+					.max = 16,
+					.increment = 0
+				},
+				.digest_size = {
+					.min = 4,
+					.max = 4,
+					.increment = 0
+				},
+				.iv_size = {
+					.min = 16,
+					.max = 16,
+					.increment = 0
+				}
+			}, }
+		}, }
+	},
+
+	RTE_CRYPTODEV_END_OF_CAPABILITIES_LIST()
+};
+
 static const struct rte_security_capability dpaa2_sec_security_cap[] = {
 	{ /* IPsec Lookaside Protocol offload ESP Transport Egress */
 		.action = RTE_SECURITY_ACTION_TYPE_LOOKASIDE_PROTOCOL,
@@ -413,6 +569,22 @@ static const struct rte_security_capability dpaa2_sec_security_cap[] = {
 		},
 		.crypto_capabilities = dpaa2_sec_capabilities
 	},
+	{ /* PDCP Lookaside Protocol offload Data */
+		.action = RTE_SECURITY_ACTION_TYPE_LOOKASIDE_PROTOCOL,
+		.protocol = RTE_SECURITY_PROTOCOL_PDCP,
+		.pdcp = {
+			.domain = RTE_SECURITY_PDCP_MODE_DATA,
+		},
+		.crypto_capabilities = dpaa2_pdcp_capabilities
+	},
+	{ /* PDCP Lookaside Protocol offload Control */
+		.action = RTE_SECURITY_ACTION_TYPE_LOOKASIDE_PROTOCOL,
+		.protocol = RTE_SECURITY_PROTOCOL_PDCP,
+		.pdcp = {
+			.domain = RTE_SECURITY_PDCP_MODE_CONTROL,
+		},
+		.crypto_capabilities = dpaa2_pdcp_capabilities
+	},
 	{
 		.action = RTE_SECURITY_ACTION_TYPE_NONE
 	}
-- 
2.17.1

^ permalink raw reply	[flat|nested] 41+ messages in thread

* [dpdk-dev] [PATCH v3 0/3] security: support for pdcp
  2018-10-05 13:33 ` [dpdk-dev] [PATCH v2 " akhil.goyal
                     ` (2 preceding siblings ...)
  2018-10-05 13:33   ` [dpdk-dev] [PATCH v2 3/3] crypto/dpaa2_sec: support pdcp offload akhil.goyal
@ 2018-10-05 13:53   ` akhil.goyal
  2018-10-05 13:53     ` [dpdk-dev] [PATCH v3 1/3] security: support pdcp protocol akhil.goyal
                       ` (3 more replies)
  3 siblings, 4 replies; 41+ messages in thread
From: akhil.goyal @ 2018-10-05 13:53 UTC (permalink / raw)
  To: dev
  Cc: pablo.de.lara.guarch, radu.nicolau, jerin.jacob,
	narayanaprasad.athreya, Shally.Verma, Anoob.Joseph,
	Vidya.Velumuri, hemant.agrawal, Akhil Goyal

From: Akhil Goyal <akhil.goyal@nxp.com>

Security library currently only has support for IPSec protocol.
This patchset defines structures for pdcp protocol in rte_security
and provide a sample driver implementation for lookaside protocol
offload to support PDCP.

changes in v3:
removed checkpatch warnings.

changes in v2:
- removed hfn override. Will be added later when it is supported
- added seq number size = 18bits
- coding style issues corrected in pdcp.h
- updated documentation for specifying the 3GPP specification reference
- removed some duplicate code in dpaa2_sec_dpseci.c


Akhil Goyal (3):
  security: support pdcp protocol
  crypto/dpaa2_sec: add sample pdcp descriptor apis
  crypto/dpaa2_sec: support pdcp offload

 doc/guides/prog_guide/rte_security.rst      |   96 +-
 drivers/crypto/dpaa2_sec/dpaa2_sec_dpseci.c |  233 ++
 drivers/crypto/dpaa2_sec/dpaa2_sec_priv.h   |  172 ++
 drivers/crypto/dpaa2_sec/hw/desc.h          |    2 +-
 drivers/crypto/dpaa2_sec/hw/desc/pdcp.h     | 2667 +++++++++++++++++++
 lib/librte_security/rte_security.c          |    4 +
 lib/librte_security/rte_security.h          |   67 +
 7 files changed, 3233 insertions(+), 8 deletions(-)
 create mode 100644 drivers/crypto/dpaa2_sec/hw/desc/pdcp.h

-- 
2.17.1

^ permalink raw reply	[flat|nested] 41+ messages in thread

* [dpdk-dev] [PATCH v3 1/3] security: support pdcp protocol
  2018-10-05 13:53   ` [dpdk-dev] [PATCH v3 0/3] security: support for pdcp akhil.goyal
@ 2018-10-05 13:53     ` akhil.goyal
  2018-10-05 13:53     ` [dpdk-dev] [PATCH v3 2/3] crypto/dpaa2_sec: add sample pdcp descriptor apis akhil.goyal
                       ` (2 subsequent siblings)
  3 siblings, 0 replies; 41+ messages in thread
From: akhil.goyal @ 2018-10-05 13:53 UTC (permalink / raw)
  To: dev
  Cc: pablo.de.lara.guarch, radu.nicolau, jerin.jacob,
	narayanaprasad.athreya, Shally.Verma, Anoob.Joseph,
	Vidya.Velumuri, hemant.agrawal, Akhil Goyal

From: Akhil Goyal <akhil.goyal@nxp.com>

Packet Data Convergence Protocol (PDCP) is added in rte_security
for 3GPP TS 36.323 for LTE.

The patchset provide the structure definitions for configuring the
PDCP sessions and relevant documentation is added.

Signed-off-by: Hemant Agrawal <hemant.agrawal@nxp.com>
Signed-off-by: Akhil Goyal <akhil.goyal@nxp.com>
---
 doc/guides/prog_guide/rte_security.rst | 96 ++++++++++++++++++++++++--
 lib/librte_security/rte_security.c     |  4 ++
 lib/librte_security/rte_security.h     | 67 ++++++++++++++++++
 3 files changed, 160 insertions(+), 7 deletions(-)

diff --git a/doc/guides/prog_guide/rte_security.rst b/doc/guides/prog_guide/rte_security.rst
index 0812abe77..83d9d99e0 100644
--- a/doc/guides/prog_guide/rte_security.rst
+++ b/doc/guides/prog_guide/rte_security.rst
@@ -10,8 +10,8 @@ The security library provides a framework for management and provisioning
 of security protocol operations offloaded to hardware based devices. The
 library defines generic APIs to create and free security sessions which can
 support full protocol offload as well as inline crypto operation with
-NIC or crypto devices. The framework currently only supports the IPSec protocol
-and associated operations, other protocols will be added in future.
+NIC or crypto devices. The framework currently only supports the IPSec and PDCP
+protocol and associated operations, other protocols will be added in future.
 
 Design Principles
 -----------------
@@ -253,6 +253,49 @@ for any protocol header addition.
         +--------|--------+
                  V
 
+PDCP Flow Diagram
+~~~~~~~~~~~~~~~~~
+
+Based on 3GPP TS 36.323 Evolved Universal Terrestrial Radio Access (E-UTRA);
+Packet Data Convergence Protocol (PDCP) specification
+
+.. code-block:: c
+
+        Transmitting PDCP Entity          Receiving PDCP Entity
+                  |                                   ^
+                  |                       +-----------|-----------+
+                  V                       | In order delivery and |
+        +---------|----------+            | Duplicate detection   |
+        | Sequence Numbering |            |  (Data Plane only)    |
+        +---------|----------+            +-----------|-----------+
+                  |                                   |
+        +---------|----------+            +-----------|----------+
+        | Header Compression*|            | Header Decompression*|
+        | (Data-Plane only)  |            |   (Data Plane only)  |
+        +---------|----------+            +-----------|----------+
+                  |                                   |
+        +---------|-----------+           +-----------|----------+
+        | Integrity Protection|           |Integrity Verification|
+        | (Control Plane only)|           | (Control Plane only) |
+        +---------|-----------+           +-----------|----------+
+        +---------|-----------+            +----------|----------+
+        |     Ciphering       |            |     Deciphering     |
+        +---------|-----------+            +----------|----------+
+        +---------|-----------+            +----------|----------+
+        |   Add PDCP header   |            | Remove PDCP Header  |
+        +---------|-----------+            +----------|----------+
+                  |                                   |
+                  +----------------->>----------------+
+
+
+.. note::
+
+    * Header Compression and decompression are not supported currently.
+
+Just like IPSec, in case of PDCP also header addition/deletion, cipher/
+de-cipher, integrity protection/verification is done based on the action
+type chosen.
+
 Device Features and Capabilities
 ---------------------------------
 
@@ -271,7 +314,7 @@ structure in the *DPDK API Reference*.
 
 Each driver (crypto or ethernet) defines its own private array of capabilities
 for the operations it supports. Below is an example of the capabilities for a
-PMD which supports the IPSec protocol.
+PMD which supports the IPSec and PDCP protocol.
 
 .. code-block:: c
 
@@ -298,6 +341,22 @@ PMD which supports the IPSec protocol.
                 },
                 .crypto_capabilities = pmd_capabilities
         },
+        { /* PDCP Lookaside Protocol offload Data Plane */
+                .action = RTE_SECURITY_ACTION_TYPE_LOOKASIDE_PROTOCOL,
+                .protocol = RTE_SECURITY_PROTOCOL_PDCP,
+                .pdcp = {
+                        .domain = RTE_SECURITY_PDCP_MODE_DATA,
+                },
+                .crypto_capabilities = pmd_capabilities
+        },
+        { /* PDCP Lookaside Protocol offload Control */
+                .action = RTE_SECURITY_ACTION_TYPE_LOOKASIDE_PROTOCOL,
+                .protocol = RTE_SECURITY_PROTOCOL_PDCP,
+                .pdcp = {
+                        .domain = RTE_SECURITY_PDCP_MODE_CONTROL,
+                },
+                .crypto_capabilities = pmd_capabilities
+        },
         {
                 .action = RTE_SECURITY_ACTION_TYPE_NONE
         }
@@ -429,6 +488,7 @@ Security Session configuration structure is defined as ``rte_security_session_co
         union {
                 struct rte_security_ipsec_xform ipsec;
                 struct rte_security_macsec_xform macsec;
+                struct rte_security_pdcp_xform pdcp;
         };
         /**< Configuration parameters for security session */
         struct rte_crypto_sym_xform *crypto_xform;
@@ -463,15 +523,17 @@ The ``rte_security_session_protocol`` is defined as
 .. code-block:: c
 
     enum rte_security_session_protocol {
-        RTE_SECURITY_PROTOCOL_IPSEC,
+        RTE_SECURITY_PROTOCOL_IPSEC = 1,
         /**< IPsec Protocol */
         RTE_SECURITY_PROTOCOL_MACSEC,
         /**< MACSec Protocol */
+        RTE_SECURITY_PROTOCOL_PDCP,
+        /**< PDCP Protocol */
     };
 
-Currently the library defines configuration parameters for IPSec only. For other
-protocols like MACSec, structures and enums are defined as place holders which
-will be updated in the future.
+Currently the library defines configuration parameters for IPSec and PDCP only.
+For other protocols like MACSec, structures and enums are defined as place holders
+which will be updated in the future.
 
 IPsec related configuration parameters are defined in ``rte_security_ipsec_xform``
 
@@ -494,6 +556,26 @@ IPsec related configuration parameters are defined in ``rte_security_ipsec_xform
         /**< Tunnel parameters, NULL for transport mode */
     };
 
+PDCP related configuration parameters are defined in ``rte_security_pdcp_xform``
+
+.. code-block:: c
+
+    struct rte_security_pdcp_xform {
+        int8_t bearer;	/**< PDCP bearer ID */
+        /** < PDCP mode of operation: Control or data */
+        enum rte_security_pdcp_domain domain;
+        /**< PDCP Frame Direction 0:UL 1:DL */
+        enum rte_security_pdcp_direction pkt_dir;
+        /**< Sequence number size, 5/7/12/15/18 */
+        enum rte_security_pdcp_sn_size sn_size;
+        /**< Starting Hyper Frame Number to be used together with the SN
+         * from the PDCP frames
+         */
+        uint32_t hfn;
+        /**< HFN Threashold for key renegotiation */
+        uint32_t hfn_threshold;
+    };
+
 
 Security API
 ~~~~~~~~~~~~
diff --git a/lib/librte_security/rte_security.c b/lib/librte_security/rte_security.c
index 1954960a5..c6355de95 100644
--- a/lib/librte_security/rte_security.c
+++ b/lib/librte_security/rte_security.c
@@ -131,6 +131,10 @@ rte_security_capability_get(struct rte_security_ctx *instance,
 					capability->ipsec.direction ==
 							idx->ipsec.direction)
 					return capability;
+			} else if (idx->protocol == RTE_SECURITY_PROTOCOL_PDCP) {
+				if (capability->pdcp.domain ==
+							idx->pdcp.domain)
+					return capability;
 			}
 		}
 	}
diff --git a/lib/librte_security/rte_security.h b/lib/librte_security/rte_security.h
index b0d1b97ee..b3565c612 100644
--- a/lib/librte_security/rte_security.h
+++ b/lib/librte_security/rte_security.h
@@ -206,6 +206,57 @@ struct rte_security_macsec_xform {
 	int dummy;
 };
 
+/**
+ * PDCP Mode of session
+ */
+enum rte_security_pdcp_domain {
+	RTE_SECURITY_PDCP_MODE_CONTROL,	/**< PDCP control plane */
+	RTE_SECURITY_PDCP_MODE_DATA,	/**< PDCP data plane */
+};
+
+/** PDCP Frame direction */
+enum rte_security_pdcp_direction {
+	RTE_SECURITY_PDCP_UPLINK,	/**< Uplink */
+	RTE_SECURITY_PDCP_DOWNLINK,	/**< Downlink */
+};
+
+/**
+ * PDCP Sequence Number Size selectors
+ * @PDCP_SN_SIZE_5: 5bit sequence number
+ * @PDCP_SN_SIZE_7: 7bit sequence number
+ * @PDCP_SN_SIZE_12: 12bit sequence number
+ * @PDCP_SN_SIZE_15: 15bit sequence number
+ * @PDCP_SN_SIZE_18: 18bit sequence number
+ */
+enum rte_security_pdcp_sn_size {
+	RTE_SECURITY_PDCP_SN_SIZE_5 = 5,
+	RTE_SECURITY_PDCP_SN_SIZE_7 = 7,
+	RTE_SECURITY_PDCP_SN_SIZE_12 = 12,
+	RTE_SECURITY_PDCP_SN_SIZE_15 = 15,
+	RTE_SECURITY_PDCP_SN_SIZE_18 = 18
+};
+
+/**
+ * PDCP security association configuration data.
+ *
+ * This structure contains data required to create a PDCP security session.
+ */
+struct rte_security_pdcp_xform {
+	int8_t bearer;	/**< PDCP bearer ID */
+	/** < PDCP mode of operation: Control or data */
+	enum rte_security_pdcp_domain domain;
+	/**< PDCP Frame Direction 0:UL 1:DL */
+	enum rte_security_pdcp_direction pkt_dir;
+	/**< Sequence number size, 5/7/12/15/18 */
+	enum rte_security_pdcp_sn_size sn_size;
+	/**< Starting Hyper Frame Number to be used together with the SN
+	 * from the PDCP frames
+	 */
+	uint32_t hfn;
+	/**< HFN Threshold for key renegotiation */
+	uint32_t hfn_threshold;
+};
+
 /**
  * Security session action type.
  */
@@ -232,6 +283,8 @@ enum rte_security_session_protocol {
 	/**< IPsec Protocol */
 	RTE_SECURITY_PROTOCOL_MACSEC,
 	/**< MACSec Protocol */
+	RTE_SECURITY_PROTOCOL_PDCP,
+	/**< PDCP Protocol */
 };
 
 /**
@@ -246,6 +299,7 @@ struct rte_security_session_conf {
 	union {
 		struct rte_security_ipsec_xform ipsec;
 		struct rte_security_macsec_xform macsec;
+		struct rte_security_pdcp_xform pdcp;
 	};
 	/**< Configuration parameters for security session */
 	struct rte_crypto_sym_xform *crypto_xform;
@@ -413,6 +467,10 @@ struct rte_security_ipsec_stats {
 
 };
 
+struct rte_security_pdcp_stats {
+	uint64_t reserved;
+};
+
 struct rte_security_stats {
 	enum rte_security_session_protocol protocol;
 	/**< Security protocol to be configured */
@@ -421,6 +479,7 @@ struct rte_security_stats {
 	union {
 		struct rte_security_macsec_stats macsec;
 		struct rte_security_ipsec_stats ipsec;
+		struct rte_security_pdcp_stats pdcp;
 	};
 };
 
@@ -465,6 +524,11 @@ struct rte_security_capability {
 			int dummy;
 		} macsec;
 		/**< MACsec capability */
+		struct {
+			enum rte_security_pdcp_domain domain;
+			/** < PDCP mode of operation: Control or data */
+		} pdcp;
+		/**< PDCP capability */
 	};
 
 	const struct rte_cryptodev_capabilities *crypto_capabilities;
@@ -506,6 +570,9 @@ struct rte_security_capability_idx {
 			enum rte_security_ipsec_sa_mode mode;
 			enum rte_security_ipsec_sa_direction direction;
 		} ipsec;
+		struct {
+			enum rte_security_pdcp_domain domain;
+		} pdcp;
 	};
 };
 
-- 
2.17.1

^ permalink raw reply	[flat|nested] 41+ messages in thread

* [dpdk-dev] [PATCH v3 2/3] crypto/dpaa2_sec: add sample pdcp descriptor apis
  2018-10-05 13:53   ` [dpdk-dev] [PATCH v3 0/3] security: support for pdcp akhil.goyal
  2018-10-05 13:53     ` [dpdk-dev] [PATCH v3 1/3] security: support pdcp protocol akhil.goyal
@ 2018-10-05 13:53     ` akhil.goyal
  2018-10-05 13:53     ` [dpdk-dev] [PATCH v3 3/3] crypto/dpaa2_sec: support pdcp offload akhil.goyal
  2018-10-15 12:53     ` [dpdk-dev] [PATCH v4 0/3] security: support for pdcp Akhil Goyal
  3 siblings, 0 replies; 41+ messages in thread
From: akhil.goyal @ 2018-10-05 13:53 UTC (permalink / raw)
  To: dev
  Cc: pablo.de.lara.guarch, radu.nicolau, jerin.jacob,
	narayanaprasad.athreya, Shally.Verma, Anoob.Joseph,
	Vidya.Velumuri, hemant.agrawal, Akhil Goyal

From: Akhil Goyal <akhil.goyal@nxp.com>

DPAA2 SEC platform can support look aside protocol
offload for PDCP protocol.

The relevant APIs for configuring the hardware for PDCP
is added for various modes and crypto algorithms.

Signed-off-by: Hemant Agrawal <hemant.agrawal@nxp.com>
Signed-off-by: Horia Geanta Neag <horia.geanta@nxp.com>
Signed-off-by: Alex Porosanu <alexandru.porosanu@nxp.com>
Signed-off-by: Akhil Goyal <akhil.goyal@nxp.com>
---
 drivers/crypto/dpaa2_sec/hw/desc.h      |    2 +-
 drivers/crypto/dpaa2_sec/hw/desc/pdcp.h | 2667 +++++++++++++++++++++++
 2 files changed, 2668 insertions(+), 1 deletion(-)
 create mode 100644 drivers/crypto/dpaa2_sec/hw/desc/pdcp.h

diff --git a/drivers/crypto/dpaa2_sec/hw/desc.h b/drivers/crypto/dpaa2_sec/hw/desc.h
index ca94ea3ff..5d99dd8af 100644
--- a/drivers/crypto/dpaa2_sec/hw/desc.h
+++ b/drivers/crypto/dpaa2_sec/hw/desc.h
@@ -868,7 +868,7 @@
 #define OP_PCL_LTE_MIXED_AUTH_SHIFT	0
 #define OP_PCL_LTE_MIXED_AUTH_MASK	(3 << OP_PCL_LTE_MIXED_AUTH_SHIFT)
 #define OP_PCL_LTE_MIXED_ENC_SHIFT	8
-#define OP_PCL_LTE_MIXED_ENC_MASK	(3 < OP_PCL_LTE_MIXED_ENC_SHIFT)
+#define OP_PCL_LTE_MIXED_ENC_MASK	(3 << OP_PCL_LTE_MIXED_ENC_SHIFT)
 #define OP_PCL_LTE_MIXED_AUTH_NULL	(OP_PCL_LTE_NULL << \
 					 OP_PCL_LTE_MIXED_AUTH_SHIFT)
 #define OP_PCL_LTE_MIXED_AUTH_SNOW	(OP_PCL_LTE_SNOW << \
diff --git a/drivers/crypto/dpaa2_sec/hw/desc/pdcp.h b/drivers/crypto/dpaa2_sec/hw/desc/pdcp.h
new file mode 100644
index 000000000..04b5fffbe
--- /dev/null
+++ b/drivers/crypto/dpaa2_sec/hw/desc/pdcp.h
@@ -0,0 +1,2667 @@
+/*
+ * Copyright 2008-2013 Freescale Semiconductor, Inc.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause or GPL-2.0+
+ */
+
+#ifndef __DESC_PDCP_H__
+#define __DESC_PDCP_H__
+
+#include "hw/rta.h"
+#include "common.h"
+
+/**
+ * DOC: PDCP Shared Descriptor Constructors
+ *
+ * Shared descriptors for PDCP protocol.
+ */
+
+/**
+ * PDCP_NULL_MAX_FRAME_LEN - The maximum frame frame length that is supported by
+ *                           PDCP NULL protocol.
+ */
+#define PDCP_NULL_MAX_FRAME_LEN		0x00002FFF
+
+/**
+ * PDCP_MAC_I_LEN - The length of the MAC-I for PDCP protocol operation
+ */
+#define PDCP_MAC_I_LEN			0x00000004
+
+/**
+ * PDCP_MAX_FRAME_LEN_STATUS - The status returned in FD status/command field in
+ *                             case the input frame is larger than
+ *                             PDCP_NULL_MAX_FRAME_LEN.
+ */
+#define PDCP_MAX_FRAME_LEN_STATUS	0xF1
+
+/**
+ * PDCP_C_PLANE_SN_MASK - This mask is used in the PDCP descriptors for
+ *                        extracting the sequence number (SN) from the PDCP
+ *                        Control Plane header. For PDCP Control Plane, the SN
+ *                        is constant (5 bits) as opposed to PDCP Data Plane
+ *                        (7/12/15 bits).
+ */
+#define PDCP_C_PLANE_SN_MASK		0x0000001F
+
+/**
+ * PDCP_U_PLANE_15BIT_SN_MASK - This mask is used in the PDCP descriptors for
+ *                              extracting the sequence number (SN) from the
+ *                              PDCP User Plane header. For PDCP Control Plane,
+ *                              the SN is constant (5 bits) as opposed to PDCP
+ *                              Data Plane (7/12/15 bits).
+ */
+#define PDCP_U_PLANE_15BIT_SN_MASK	0x00007FFF
+
+/**
+ * PDCP_BEARER_MASK - This mask is used masking out the bearer for PDCP
+ *                    processing with SNOW f9 in LTE.
+ *
+ * The value on which this mask is applied is formatted as below:
+ *     Count-C (32 bit) | Bearer (5 bit) | Direction (1 bit) | 0 (26 bits)
+ *
+ * Applying this mask is done for creating the upper 64 bits of the IV needed
+ * for SNOW f9.
+ *
+ * The lower 32 bits of the mask are used for masking the direction for AES
+ * CMAC IV.
+ */
+#define PDCP_BEARER_MASK		0xFFFFFFFF04000000ull
+
+/**
+ * PDCP_DIR_MASK - This mask is used masking out the direction for PDCP
+ *                 processing with SNOW f9 in LTE.
+ *
+ * The value on which this mask is applied is formatted as below:
+ *     Bearer (5 bit) | Direction (1 bit) | 0 (26 bits)
+ *
+ * Applying this mask is done for creating the lower 32 bits of the IV needed
+ * for SNOW f9.
+ *
+ * The upper 32 bits of the mask are used for masking the direction for AES
+ * CMAC IV.
+ */
+#define PDCP_DIR_MASK			0xF800000000000000ull
+
+/**
+ * PDCP_NULL_INT_MAC_I_VAL - The value of the PDCP PDU MAC-I in case NULL
+ *                           integrity is used.
+ */
+
+#define PDCP_NULL_INT_MAC_I_VAL		0x00000000
+
+/**
+ * PDCP_NULL_INT_ICV_CHECK_FAILED_STATUS - The status used to report ICV check
+ *                                         failed in case of NULL integrity
+ *                                         Control Plane processing.
+ */
+#define PDCP_NULL_INT_ICV_CHECK_FAILED_STATUS	0x0A
+/**
+ * PDCP_DPOVRD_HFN_OV_EN - Value to be used in the FD status/cmd field to
+ *                         indicate the HFN override mechanism is active for the
+ *                         frame.
+ */
+#define PDCP_DPOVRD_HFN_OV_EN		0x80000000
+
+/**
+ * PDCP_P4080REV2_HFN_OV_BUFLEN - The length in bytes of the supplementary space
+ *                                that must be provided by the user at the
+ *                                beginning of the input frame buffer for
+ *                                P4080 REV 2.
+ *
+ * The format of the frame buffer is the following:
+ *
+ *  |<---PDCP_P4080REV2_HFN_OV_BUFLEN-->|
+ * //===================================||============||==============\\
+ * || PDCP_DPOVRD_HFN_OV_EN | HFN value || PDCP Header|| PDCP Payload ||
+ * \\===================================||============||==============//
+ *
+ * If HFN override mechanism is not desired, then the MSB of the first 4 bytes
+ * must be set to 0b.
+ */
+#define PDCP_P4080REV2_HFN_OV_BUFLEN	4
+
+/**
+ * enum cipher_type_pdcp - Type selectors for cipher types in PDCP protocol OP
+ *                         instructions.
+ * @PDCP_CIPHER_TYPE_NULL: NULL
+ * @PDCP_CIPHER_TYPE_SNOW: SNOW F8
+ * @PDCP_CIPHER_TYPE_AES: AES
+ * @PDCP_CIPHER_TYPE_ZUC: ZUCE
+ * @PDCP_CIPHER_TYPE_INVALID: invalid option
+ */
+enum cipher_type_pdcp {
+	PDCP_CIPHER_TYPE_NULL,
+	PDCP_CIPHER_TYPE_SNOW,
+	PDCP_CIPHER_TYPE_AES,
+	PDCP_CIPHER_TYPE_ZUC,
+	PDCP_CIPHER_TYPE_INVALID
+};
+
+/**
+ * enum auth_type_pdcp - Type selectors for integrity types in PDCP protocol OP
+ *                       instructions.
+ * @PDCP_AUTH_TYPE_NULL: NULL
+ * @PDCP_AUTH_TYPE_SNOW: SNOW F9
+ * @PDCP_AUTH_TYPE_AES: AES CMAC
+ * @PDCP_AUTH_TYPE_ZUC: ZUCA
+ * @PDCP_AUTH_TYPE_INVALID: invalid option
+ */
+enum auth_type_pdcp {
+	PDCP_AUTH_TYPE_NULL,
+	PDCP_AUTH_TYPE_SNOW,
+	PDCP_AUTH_TYPE_AES,
+	PDCP_AUTH_TYPE_ZUC,
+	PDCP_AUTH_TYPE_INVALID
+};
+
+/**
+ * enum pdcp_dir - Type selectors for direction for PDCP protocol
+ * @PDCP_DIR_UPLINK: uplink direction
+ * @PDCP_DIR_DOWNLINK: downlink direction
+ * @PDCP_DIR_INVALID: invalid option
+ */
+enum pdcp_dir {
+	PDCP_DIR_UPLINK = 0,
+	PDCP_DIR_DOWNLINK = 1,
+	PDCP_DIR_INVALID
+};
+
+/**
+ * enum pdcp_plane - PDCP domain selectors
+ * @PDCP_CONTROL_PLANE: Control Plane
+ * @PDCP_DATA_PLANE: Data Plane
+ * @PDCP_SHORT_MAC: Short MAC
+ */
+enum pdcp_plane {
+	PDCP_CONTROL_PLANE,
+	PDCP_DATA_PLANE,
+	PDCP_SHORT_MAC
+};
+
+/**
+ * enum pdcp_sn_size - Sequence Number Size selectors for PDCP protocol
+ * @PDCP_SN_SIZE_5: 5bit sequence number
+ * @PDCP_SN_SIZE_7: 7bit sequence number
+ * @PDCP_SN_SIZE_12: 12bit sequence number
+ * @PDCP_SN_SIZE_15: 15bit sequence number
+ * @PDCP_SN_SIZE_18: 18bit sequence number
+ */
+enum pdcp_sn_size {
+	PDCP_SN_SIZE_5 = 5,
+	PDCP_SN_SIZE_7 = 7,
+	PDCP_SN_SIZE_12 = 12,
+	PDCP_SN_SIZE_15 = 15
+};
+
+/*
+ * PDCP Control Plane Protocol Data Blocks
+ */
+#define PDCP_C_PLANE_PDB_HFN_SHIFT		5
+#define PDCP_C_PLANE_PDB_BEARER_SHIFT		27
+#define PDCP_C_PLANE_PDB_DIR_SHIFT		26
+#define PDCP_C_PLANE_PDB_HFN_THR_SHIFT		5
+
+#define PDCP_U_PLANE_PDB_OPT_SHORT_SN		0x2
+#define PDCP_U_PLANE_PDB_OPT_15B_SN		0x4
+#define PDCP_U_PLANE_PDB_SHORT_SN_HFN_SHIFT	7
+#define PDCP_U_PLANE_PDB_LONG_SN_HFN_SHIFT	12
+#define PDCP_U_PLANE_PDB_15BIT_SN_HFN_SHIFT	15
+#define PDCP_U_PLANE_PDB_BEARER_SHIFT		27
+#define PDCP_U_PLANE_PDB_DIR_SHIFT		26
+#define PDCP_U_PLANE_PDB_SHORT_SN_HFN_THR_SHIFT	7
+#define PDCP_U_PLANE_PDB_LONG_SN_HFN_THR_SHIFT	12
+#define PDCP_U_PLANE_PDB_15BIT_SN_HFN_THR_SHIFT	15
+
+struct pdcp_pdb {
+	union {
+		uint32_t opt;
+		uint32_t rsvd;
+	} opt_res;
+	uint32_t hfn_res;	/* HyperFrame number,(27, 25 or 21 bits),
+				 * left aligned & right-padded with zeros.
+				 */
+	uint32_t bearer_dir_res;/* Bearer(5 bits), packet direction (1 bit),
+				 * left aligned & right-padded with zeros.
+				 */
+	uint32_t hfn_thr_res;	/* HyperFrame number threshold (27, 25 or 21
+				 * bits), left aligned & right-padded with
+				 * zeros.
+				 */
+};
+
+/*
+ * PDCP internal PDB types
+ */
+enum pdb_type_e {
+	PDCP_PDB_TYPE_NO_PDB,
+	PDCP_PDB_TYPE_FULL_PDB,
+	PDCP_PDB_TYPE_REDUCED_PDB,
+	PDCP_PDB_TYPE_INVALID
+};
+
+/*
+ * Function for appending the portion of a PDCP Control Plane shared descriptor
+ * which performs NULL encryption and integrity (i.e. copies the input frame
+ * to the output frame, appending 32 bits of zeros at the end (MAC-I for
+ * NULL integrity).
+ */
+static inline int
+pdcp_insert_cplane_null_op(struct program *p,
+			   struct alginfo *cipherdata __maybe_unused,
+			   struct alginfo *authdata __maybe_unused,
+			   unsigned int dir,
+			   unsigned char era_2_sw_hfn_ovrd __maybe_unused)
+{
+	LABEL(local_offset);
+	REFERENCE(move_cmd_read_descbuf);
+	REFERENCE(move_cmd_write_descbuf);
+
+	if (rta_sec_era > RTA_SEC_ERA_2) {
+		MATHB(p, SEQINSZ, ADD, ZERO, VSEQINSZ, 4, 0);
+		if (dir == OP_TYPE_ENCAP_PROTOCOL)
+			MATHB(p, SEQINSZ, ADD, PDCP_MAC_I_LEN, VSEQOUTSZ, 4,
+			      IMMED2);
+		else
+			MATHB(p, SEQINSZ, SUB, PDCP_MAC_I_LEN, VSEQOUTSZ, 4,
+			      IMMED2);
+	} else {
+		MATHB(p, SEQINSZ, ADD, ONE, VSEQINSZ, 4, 0);
+		MATHB(p, VSEQINSZ, SUB, ONE, VSEQINSZ, 4, 0);
+
+		if (dir == OP_TYPE_ENCAP_PROTOCOL) {
+			MATHB(p, SEQINSZ, ADD, PDCP_MAC_I_LEN, VSEQOUTSZ, 4,
+			      IMMED2);
+			MATHB(p, VSEQINSZ, SUB, ONE, MATH0, 4, 0);
+		} else {
+			MATHB(p, VSEQINSZ, SUB, PDCP_MAC_I_LEN, VSEQINSZ, 4,
+			      IMMED2);
+			MATHB(p, SEQINSZ, SUB, PDCP_MAC_I_LEN, VSEQOUTSZ, 4,
+			      IMMED2);
+			MATHB(p, VSEQOUTSZ, SUB, ONE, MATH0, 4, 0);
+		}
+
+		MATHB(p, MATH0, ADD, ONE, MATH0, 4, 0);
+
+		/*
+		 * Since MOVELEN is available only starting with
+		 * SEC ERA 3, use poor man's MOVELEN: create a MOVE
+		 * command dynamically by writing the length from M1 by
+		 * OR-ing the command in the M1 register and MOVE the
+		 * result into the descriptor buffer. Care must be taken
+		 * wrt. the location of the command because of SEC
+		 * pipelining. The actual MOVEs are written at the end
+		 * of the descriptor due to calculations needed on the
+		 * offset in the descriptor for the MOVE command.
+		 */
+		move_cmd_read_descbuf = MOVE(p, DESCBUF, 0, MATH0, 0, 6,
+					     IMMED);
+		move_cmd_write_descbuf = MOVE(p, MATH0, 0, DESCBUF, 0, 8,
+					      WAITCOMP | IMMED);
+	}
+	MATHB(p, VSEQINSZ, SUB, PDCP_NULL_MAX_FRAME_LEN, NONE, 4,
+	      IMMED2);
+	JUMP(p, PDCP_MAX_FRAME_LEN_STATUS, HALT_STATUS, ALL_FALSE, MATH_N);
+
+	if (rta_sec_era > RTA_SEC_ERA_2) {
+		if (dir == OP_TYPE_ENCAP_PROTOCOL)
+			MATHB(p, VSEQINSZ, ADD, ZERO, MATH0, 4, 0);
+		else
+			MATHB(p, VSEQOUTSZ, ADD, ZERO, MATH0, 4, 0);
+	}
+	SEQFIFOSTORE(p, MSG, 0, 0, VLF);
+	SEQFIFOLOAD(p, MSG1, 0, VLF | LAST1 | FLUSH1);
+
+	if (rta_sec_era > RTA_SEC_ERA_2) {
+		MOVE(p, AB1, 0, OFIFO, 0, MATH0, 0);
+	} else {
+		SET_LABEL(p, local_offset);
+
+		/* Shut off automatic Info FIFO entries */
+		LOAD(p, 0, DCTRL, LDOFF_DISABLE_AUTO_NFIFO, 0, IMMED);
+		/* Placeholder for MOVE command with length from M1 register */
+		MOVE(p, IFIFOAB1, 0, OFIFO, 0, 0, IMMED);
+		/* Enable automatic Info FIFO entries */
+		LOAD(p, 0, DCTRL, LDOFF_ENABLE_AUTO_NFIFO, 0, IMMED);
+	}
+
+	if (dir == OP_TYPE_ENCAP_PROTOCOL) {
+		MATHB(p, MATH1, XOR, MATH1, MATH0, 8, 0);
+		MOVE(p, MATH0, 0, OFIFO, 0, 4, IMMED);
+	}
+
+	if (rta_sec_era < RTA_SEC_ERA_3) {
+		PATCH_MOVE(p, move_cmd_read_descbuf, local_offset);
+		PATCH_MOVE(p, move_cmd_write_descbuf, local_offset);
+	}
+
+	return 0;
+}
+
+static inline int
+insert_copy_frame_op(struct program *p,
+		     struct alginfo *cipherdata __maybe_unused,
+		     unsigned int dir __maybe_unused)
+{
+	LABEL(local_offset);
+	REFERENCE(move_cmd_read_descbuf);
+	REFERENCE(move_cmd_write_descbuf);
+
+	if (rta_sec_era > RTA_SEC_ERA_2) {
+		MATHB(p, SEQINSZ, ADD, ZERO, VSEQINSZ,  4, 0);
+		MATHB(p, SEQINSZ, ADD, ZERO, VSEQOUTSZ,  4, 0);
+	} else {
+		MATHB(p, SEQINSZ, ADD, ONE, VSEQINSZ,  4, 0);
+		MATHB(p, VSEQINSZ, SUB, ONE, VSEQINSZ,  4, 0);
+		MATHB(p, SEQINSZ, ADD, ONE, VSEQOUTSZ,  4, 0);
+		MATHB(p, VSEQOUTSZ, SUB, ONE, VSEQOUTSZ,  4, 0);
+		MATHB(p, VSEQINSZ, SUB, ONE, MATH0,  4, 0);
+		MATHB(p, MATH0, ADD, ONE, MATH0,  4, 0);
+
+		/*
+		 * Since MOVELEN is available only starting with
+		 * SEC ERA 3, use poor man's MOVELEN: create a MOVE
+		 * command dynamically by writing the length from M1 by
+		 * OR-ing the command in the M1 register and MOVE the
+		 * result into the descriptor buffer. Care must be taken
+		 * wrt. the location of the command because of SEC
+		 * pipelining. The actual MOVEs are written at the end
+		 * of the descriptor due to calculations needed on the
+		 * offset in the descriptor for the MOVE command.
+		 */
+		move_cmd_read_descbuf = MOVE(p, DESCBUF, 0, MATH0, 0, 6,
+					     IMMED);
+		move_cmd_write_descbuf = MOVE(p, MATH0, 0, DESCBUF, 0, 8,
+					      WAITCOMP | IMMED);
+	}
+	MATHB(p, SEQINSZ, SUB, PDCP_NULL_MAX_FRAME_LEN, NONE,  4,
+	      IFB | IMMED2);
+	JUMP(p, PDCP_MAX_FRAME_LEN_STATUS, HALT_STATUS, ALL_FALSE, MATH_N);
+
+	if (rta_sec_era > RTA_SEC_ERA_2)
+		MATHB(p, VSEQINSZ, ADD, ZERO, MATH0,  4, 0);
+
+	SEQFIFOLOAD(p, MSG1, 0, VLF | LAST1 | FLUSH1);
+	if (rta_sec_era > RTA_SEC_ERA_2) {
+		MOVE(p, AB1, 0, OFIFO, 0, MATH0, 0);
+	} else {
+		SET_LABEL(p, local_offset);
+
+		/* Shut off automatic Info FIFO entries */
+		LOAD(p, 0, DCTRL, LDOFF_DISABLE_AUTO_NFIFO, 0, IMMED);
+
+		/* Placeholder for MOVE command with length from M0 register */
+		MOVE(p, IFIFOAB1, 0, OFIFO, 0, 0, IMMED);
+
+		/* Enable automatic Info FIFO entries */
+		LOAD(p, 0, DCTRL, LDOFF_ENABLE_AUTO_NFIFO, 0, IMMED);
+	}
+
+	SEQFIFOSTORE(p, MSG, 0, 0, VLF);
+
+	if (rta_sec_era < RTA_SEC_ERA_3) {
+		PATCH_MOVE(p, move_cmd_read_descbuf, local_offset);
+		PATCH_MOVE(p, move_cmd_write_descbuf, local_offset);
+	}
+	return 0;
+}
+
+static inline int
+pdcp_insert_cplane_int_only_op(struct program *p,
+			       struct alginfo *cipherdata __maybe_unused,
+			       struct alginfo *authdata, unsigned int dir,
+			       unsigned char era_2_sw_hfn_ovrd)
+{
+	LABEL(local_offset);
+	REFERENCE(move_cmd_read_descbuf);
+	REFERENCE(move_cmd_write_descbuf);
+
+	switch (authdata->algtype) {
+	case PDCP_AUTH_TYPE_SNOW:
+		/* Insert Auth Key */
+		KEY(p, KEY2, authdata->key_enc_flags, authdata->key,
+		    authdata->keylen, INLINE_KEY(authdata));
+		SEQLOAD(p, MATH0, 7, 1, 0);
+		JUMP(p, 1, LOCAL_JUMP, ALL_TRUE, CALM);
+
+		if (rta_sec_era > RTA_SEC_ERA_2 ||
+		    (rta_sec_era == RTA_SEC_ERA_2 &&
+				   era_2_sw_hfn_ovrd == 0)) {
+			SEQINPTR(p, 0, 1, RTO);
+		} else {
+			SEQINPTR(p, 0, 5, RTO);
+			SEQFIFOLOAD(p, SKIP, 4, 0);
+		}
+
+		MATHB(p, MATH0, AND, PDCP_C_PLANE_SN_MASK, MATH1,  8,
+		      IFB | IMMED2);
+		MATHB(p, MATH1, SHLD, MATH1, MATH1,  8, 0);
+		MOVE(p, DESCBUF, 8, MATH2, 0, 8, WAITCOMP | IMMED);
+		MATHB(p, MATH2, AND, PDCP_BEARER_MASK, MATH2, 8,
+		      IMMED2);
+		MOVE(p, DESCBUF, 0x0C, MATH3, 0, 4, WAITCOMP | IMMED);
+		MATHB(p, MATH3, AND, PDCP_DIR_MASK, MATH3, 8,
+		      IMMED2);
+		MATHB(p, MATH1, OR, MATH2, MATH2, 8, 0);
+		MOVE(p, MATH2, 0, CONTEXT2, 0, 0x0C, WAITCOMP | IMMED);
+
+		if (dir == OP_TYPE_DECAP_PROTOCOL) {
+			MATHB(p, SEQINSZ, SUB, PDCP_MAC_I_LEN, MATH1, 4,
+			      IMMED2);
+		} else {
+			if (rta_sec_era > RTA_SEC_ERA_2) {
+				MATHB(p, SEQINSZ, SUB, ZERO, MATH1, 4,
+				      0);
+			} else {
+				MATHB(p, SEQINSZ, ADD, ONE, MATH1, 4,
+				      0);
+				MATHB(p, MATH1, SUB, ONE, MATH1, 4,
+				      0);
+			}
+		}
+
+		if (rta_sec_era > RTA_SEC_ERA_2) {
+			MATHB(p, MATH1, SUB, ZERO, VSEQINSZ, 4, 0);
+			MATHB(p, MATH1, SUB, ZERO, VSEQOUTSZ, 4, 0);
+		} else {
+			MATHB(p, ZERO, ADD, MATH1, VSEQINSZ, 4, 0);
+			MATHB(p, ZERO, ADD, MATH1, VSEQOUTSZ, 4, 0);
+
+			/*
+			 * Since MOVELEN is available only starting with
+			 * SEC ERA 3, use poor man's MOVELEN: create a MOVE
+			 * command dynamically by writing the length from M1 by
+			 * OR-ing the command in the M1 register and MOVE the
+			 * result into the descriptor buffer. Care must be taken
+			 * wrt. the location of the command because of SEC
+			 * pipelining. The actual MOVEs are written at the end
+			 * of the descriptor due to calculations needed on the
+			 * offset in the descriptor for the MOVE command.
+			 */
+			move_cmd_read_descbuf = MOVE(p, DESCBUF, 0, MATH1, 0, 6,
+						     IMMED);
+			move_cmd_write_descbuf = MOVE(p, MATH1, 0, DESCBUF, 0,
+						      8, WAITCOMP | IMMED);
+		}
+
+		SEQFIFOSTORE(p, MSG, 0, 0, VLF);
+		ALG_OPERATION(p, OP_ALG_ALGSEL_SNOW_F9, OP_ALG_AAI_F9,
+			      OP_ALG_AS_INITFINAL,
+			      dir == OP_TYPE_ENCAP_PROTOCOL ?
+				     ICV_CHECK_DISABLE : ICV_CHECK_ENABLE,
+			      DIR_ENC);
+
+		if (rta_sec_era > RTA_SEC_ERA_2) {
+			SEQFIFOLOAD(p, MSGINSNOOP, 0,
+				    VLF | LAST1 | LAST2 | FLUSH1);
+			MOVE(p, AB1, 0, OFIFO, 0, MATH1, 0);
+		} else {
+			SEQFIFOLOAD(p, MSGINSNOOP, 0,
+				    VLF | LAST1 | LAST2 | FLUSH1);
+			SET_LABEL(p, local_offset);
+
+			/* Shut off automatic Info FIFO entries */
+			LOAD(p, 0, DCTRL, LDOFF_DISABLE_AUTO_NFIFO, 0, IMMED);
+			/*
+			 * Placeholder for MOVE command with length from M1
+			 * register
+			 */
+			MOVE(p, IFIFOAB1, 0, OFIFO, 0, 0, IMMED);
+			/* Enable automatic Info FIFO entries */
+			LOAD(p, 0, DCTRL, LDOFF_ENABLE_AUTO_NFIFO, 0, IMMED);
+		}
+
+		if (dir == OP_TYPE_DECAP_PROTOCOL)
+			SEQFIFOLOAD(p, ICV2, 4, LAST2);
+		else
+			SEQSTORE(p, CONTEXT2, 0, 4, 0);
+
+		break;
+
+	case PDCP_AUTH_TYPE_AES:
+		/* Insert Auth Key */
+		KEY(p, KEY1, authdata->key_enc_flags, authdata->key,
+		    authdata->keylen, INLINE_KEY(authdata));
+		SEQLOAD(p, MATH0, 7, 1, 0);
+		JUMP(p, 1, LOCAL_JUMP, ALL_TRUE, CALM);
+		if (rta_sec_era > RTA_SEC_ERA_2 ||
+		    (rta_sec_era == RTA_SEC_ERA_2 &&
+		     era_2_sw_hfn_ovrd == 0)) {
+			SEQINPTR(p, 0, 1, RTO);
+		} else {
+			SEQINPTR(p, 0, 5, RTO);
+			SEQFIFOLOAD(p, SKIP, 4, 0);
+		}
+
+		MATHB(p, MATH0, AND, PDCP_C_PLANE_SN_MASK, MATH1, 8,
+		      IFB | IMMED2);
+		MATHB(p, MATH1, SHLD, MATH1, MATH1, 8, 0);
+		MOVE(p, DESCBUF, 8, MATH2, 0, 8, WAITCOMP | IMMED);
+		MATHB(p, MATH1, OR, MATH2, MATH2, 8, 0);
+		MOVE(p, MATH2, 0, IFIFOAB1, 0, 8, IMMED);
+		if (dir == OP_TYPE_DECAP_PROTOCOL) {
+			MATHB(p, SEQINSZ, SUB, PDCP_MAC_I_LEN, MATH1, 4,
+			      IMMED2);
+		} else {
+			if (rta_sec_era > RTA_SEC_ERA_2) {
+				MATHB(p, SEQINSZ, SUB, ZERO, MATH1, 4,
+				      0);
+			} else {
+				MATHB(p, SEQINSZ, ADD, ONE, MATH1, 4,
+				      0);
+				MATHB(p, MATH1, SUB, ONE, MATH1, 4,
+				      0);
+			}
+		}
+
+		if (rta_sec_era > RTA_SEC_ERA_2) {
+			MATHB(p, MATH1, SUB, ZERO, VSEQINSZ, 4, 0);
+			MATHB(p, MATH1, SUB, ZERO, VSEQOUTSZ, 4, 0);
+		} else {
+			MATHB(p, ZERO, ADD, MATH1, VSEQINSZ, 4, 0);
+			MATHB(p, ZERO, ADD, MATH1, VSEQOUTSZ, 4, 0);
+
+			/*
+			 * Since MOVELEN is available only starting with
+			 * SEC ERA 3, use poor man's MOVELEN: create a MOVE
+			 * command dynamically by writing the length from M1 by
+			 * OR-ing the command in the M1 register and MOVE the
+			 * result into the descriptor buffer. Care must be taken
+			 * wrt. the location of the command because of SEC
+			 * pipelining. The actual MOVEs are written at the end
+			 * of the descriptor due to calculations needed on the
+			 * offset in the descriptor for the MOVE command.
+			 */
+			move_cmd_read_descbuf = MOVE(p, DESCBUF, 0, MATH1, 0, 6,
+						     IMMED);
+			move_cmd_write_descbuf = MOVE(p, MATH1, 0, DESCBUF, 0,
+						      8, WAITCOMP | IMMED);
+		}
+		SEQFIFOSTORE(p, MSG, 0, 0, VLF);
+		ALG_OPERATION(p, OP_ALG_ALGSEL_AES,
+			      OP_ALG_AAI_CMAC,
+			      OP_ALG_AS_INITFINAL,
+			      dir == OP_TYPE_ENCAP_PROTOCOL ?
+				     ICV_CHECK_DISABLE : ICV_CHECK_ENABLE,
+			      DIR_ENC);
+
+		if (rta_sec_era > RTA_SEC_ERA_2) {
+			MOVE(p, AB2, 0, OFIFO, 0, MATH1, 0);
+			SEQFIFOLOAD(p, MSGINSNOOP, 0,
+				    VLF | LAST1 | LAST2 | FLUSH1);
+		} else {
+			SEQFIFOLOAD(p, MSGINSNOOP, 0,
+				    VLF | LAST1 | LAST2 | FLUSH1);
+			SET_LABEL(p, local_offset);
+
+			/* Shut off automatic Info FIFO entries */
+			LOAD(p, 0, DCTRL, LDOFF_DISABLE_AUTO_NFIFO, 0, IMMED);
+
+			/*
+			 * Placeholder for MOVE command with length from
+			 * M1 register
+			 */
+			MOVE(p, IFIFOAB2, 0, OFIFO, 0, 0, IMMED);
+
+			/* Enable automatic Info FIFO entries */
+			LOAD(p, 0, DCTRL, LDOFF_ENABLE_AUTO_NFIFO, 0, IMMED);
+		}
+
+		if (dir == OP_TYPE_DECAP_PROTOCOL)
+			SEQFIFOLOAD(p, ICV1, 4, LAST1 | FLUSH1);
+		else
+			SEQSTORE(p, CONTEXT1, 0, 4, 0);
+
+		break;
+
+	case PDCP_AUTH_TYPE_ZUC:
+		if (rta_sec_era < RTA_SEC_ERA_5) {
+			pr_err("Invalid era for selected algorithm\n");
+			return -ENOTSUP;
+		}
+		/* Insert Auth Key */
+		KEY(p, KEY2, authdata->key_enc_flags, authdata->key,
+		    authdata->keylen, INLINE_KEY(authdata));
+		SEQLOAD(p, MATH0, 7, 1, 0);
+		JUMP(p, 1, LOCAL_JUMP, ALL_TRUE, CALM);
+		SEQINPTR(p, 0, 1, RTO);
+		MATHB(p, MATH0, AND, PDCP_C_PLANE_SN_MASK, MATH1, 8,
+		      IFB | IMMED2);
+		MATHB(p, MATH1, SHLD, MATH1, MATH1, 8, 0);
+		MOVE(p, DESCBUF, 8, MATH2, 0, 8, WAITCOMP | IMMED);
+		MATHB(p, MATH1, OR, MATH2, MATH2, 8, 0);
+		MOVE(p, MATH2, 0, CONTEXT2, 0, 8, IMMED);
+
+		if (dir == OP_TYPE_DECAP_PROTOCOL)
+			MATHB(p, SEQINSZ, SUB, PDCP_MAC_I_LEN, MATH1, 4,
+			      IMMED2);
+		else
+			MATHB(p, SEQINSZ, SUB, ZERO, MATH1, 4, 0);
+
+		MATHB(p, MATH1, SUB, ZERO, VSEQINSZ, 4, 0);
+		MATHB(p, MATH1, SUB, ZERO, VSEQOUTSZ, 4, 0);
+		SEQFIFOSTORE(p, MSG, 0, 0, VLF);
+		ALG_OPERATION(p, OP_ALG_ALGSEL_ZUCA,
+			      OP_ALG_AAI_F9,
+			      OP_ALG_AS_INITFINAL,
+			      dir == OP_TYPE_ENCAP_PROTOCOL ?
+				     ICV_CHECK_DISABLE : ICV_CHECK_ENABLE,
+			      DIR_ENC);
+		SEQFIFOLOAD(p, MSGINSNOOP, 0, VLF | LAST1 | LAST2 | FLUSH1);
+		MOVE(p, AB1, 0, OFIFO, 0, MATH1, 0);
+
+		if (dir == OP_TYPE_DECAP_PROTOCOL)
+			SEQFIFOLOAD(p, ICV2, 4, LAST2);
+		else
+			SEQSTORE(p, CONTEXT2, 0, 4, 0);
+
+		break;
+
+	default:
+		pr_err("%s: Invalid integrity algorithm selected: %d\n",
+		       "pdcp_insert_cplane_int_only_op", authdata->algtype);
+		return -EINVAL;
+	}
+
+	if (rta_sec_era < RTA_SEC_ERA_3) {
+		PATCH_MOVE(p, move_cmd_read_descbuf, local_offset);
+		PATCH_MOVE(p, move_cmd_write_descbuf, local_offset);
+	}
+
+	return 0;
+}
+
+static inline int
+pdcp_insert_cplane_enc_only_op(struct program *p,
+			       struct alginfo *cipherdata,
+			       struct alginfo *authdata __maybe_unused,
+			       unsigned int dir,
+			       unsigned char era_2_sw_hfn_ovrd __maybe_unused)
+{
+	/* Insert Cipher Key */
+	KEY(p, KEY1, cipherdata->key_enc_flags, cipherdata->key,
+	    cipherdata->keylen, INLINE_KEY(cipherdata));
+
+	if (rta_sec_era >= RTA_SEC_ERA_8) {
+		PROTOCOL(p, dir, OP_PCLID_LTE_PDCP_CTRL_MIXED,
+				(uint16_t)cipherdata->algtype << 8);
+		return 0;
+	}
+
+	SEQLOAD(p, MATH0, 7, 1, 0);
+	JUMP(p, 1, LOCAL_JUMP, ALL_TRUE, CALM);
+	MATHB(p, MATH0, AND, PDCP_C_PLANE_SN_MASK, MATH1, 8, IFB | IMMED2);
+	SEQSTORE(p, MATH0, 7, 1, 0);
+	MATHB(p, MATH1, SHLD, MATH1, MATH1, 8, 0);
+	MOVE(p, DESCBUF, 8, MATH2, 0, 8, WAITCOMP | IMMED);
+	MATHB(p, MATH1, OR, MATH2, MATH2, 8, 0);
+
+	switch (cipherdata->algtype) {
+	case PDCP_CIPHER_TYPE_SNOW:
+		MOVE(p, MATH2, 0, CONTEXT1, 0, 8, WAITCOMP | IMMED);
+
+		if (rta_sec_era > RTA_SEC_ERA_2) {
+			MATHB(p, SEQINSZ, SUB, ZERO, VSEQINSZ, 4, 0);
+		} else {
+			MATHB(p, SEQINSZ, SUB, ONE, MATH1, 4, 0);
+			MATHB(p, MATH1, ADD, ONE, VSEQINSZ, 4, 0);
+		}
+
+		if (dir == OP_TYPE_ENCAP_PROTOCOL)
+			MATHB(p, SEQINSZ, ADD, PDCP_MAC_I_LEN, VSEQOUTSZ, 4,
+			      IMMED2);
+		else
+			MATHB(p, SEQINSZ, SUB, PDCP_MAC_I_LEN, VSEQOUTSZ, 4,
+			      IMMED2);
+		SEQFIFOSTORE(p, MSG, 0, 0, VLF | CONT);
+		ALG_OPERATION(p, OP_ALG_ALGSEL_SNOW_F8,
+			      OP_ALG_AAI_F8,
+			      OP_ALG_AS_INITFINAL, ICV_CHECK_DISABLE,
+			      dir == OP_TYPE_ENCAP_PROTOCOL ?
+					DIR_ENC : DIR_DEC);
+		break;
+
+	case PDCP_CIPHER_TYPE_AES:
+		MOVE(p, MATH2, 0, CONTEXT1, 0x10, 0x10, WAITCOMP | IMMED);
+
+		if (rta_sec_era > RTA_SEC_ERA_2) {
+			MATHB(p, SEQINSZ, SUB, ZERO, VSEQINSZ, 4, 0);
+		} else {
+			MATHB(p, SEQINSZ, SUB, ONE, MATH1, 4, 0);
+			MATHB(p, MATH1, ADD, ONE, VSEQINSZ, 4, 0);
+		}
+
+		if (dir == OP_TYPE_ENCAP_PROTOCOL)
+			MATHB(p, SEQINSZ, ADD, PDCP_MAC_I_LEN, VSEQOUTSZ, 4,
+			      IMMED2);
+		else
+			MATHB(p, SEQINSZ, SUB, PDCP_MAC_I_LEN, VSEQOUTSZ, 4,
+			      IMMED2);
+
+		SEQFIFOSTORE(p, MSG, 0, 0, VLF | CONT);
+		ALG_OPERATION(p, OP_ALG_ALGSEL_AES,
+			      OP_ALG_AAI_CTR,
+			      OP_ALG_AS_INITFINAL,
+			      ICV_CHECK_DISABLE,
+			      dir == OP_TYPE_ENCAP_PROTOCOL ?
+					DIR_ENC : DIR_DEC);
+		break;
+
+	case PDCP_CIPHER_TYPE_ZUC:
+		if (rta_sec_era < RTA_SEC_ERA_5) {
+			pr_err("Invalid era for selected algorithm\n");
+			return -ENOTSUP;
+		}
+
+		MOVE(p, MATH2, 0, CONTEXT1, 0, 0x08, IMMED);
+		MOVE(p, MATH2, 0, CONTEXT1, 0x08, 0x08, WAITCOMP | IMMED);
+		MATHB(p, SEQINSZ, SUB, ZERO, VSEQINSZ, 4, 0);
+		if (dir == OP_TYPE_ENCAP_PROTOCOL)
+			MATHB(p, SEQINSZ, ADD, PDCP_MAC_I_LEN, VSEQOUTSZ, 4,
+			      IMMED2);
+		else
+			MATHB(p, SEQINSZ, SUB, PDCP_MAC_I_LEN, VSEQOUTSZ, 4,
+			      IMMED2);
+
+		SEQFIFOSTORE(p, MSG, 0, 0, VLF | CONT);
+		ALG_OPERATION(p, OP_ALG_ALGSEL_ZUCE,
+			      OP_ALG_AAI_F8,
+			      OP_ALG_AS_INITFINAL,
+			      ICV_CHECK_DISABLE,
+			      dir == OP_TYPE_ENCAP_PROTOCOL ?
+					DIR_ENC : DIR_DEC);
+		break;
+
+	default:
+		pr_err("%s: Invalid encrypt algorithm selected: %d\n",
+		       "pdcp_insert_cplane_enc_only_op", cipherdata->algtype);
+		return -EINVAL;
+	}
+
+	if (dir == OP_TYPE_ENCAP_PROTOCOL) {
+		SEQFIFOLOAD(p, MSG1, 0, VLF);
+		FIFOLOAD(p, MSG1, PDCP_NULL_INT_MAC_I_VAL, 4,
+			 LAST1 | FLUSH1 | IMMED);
+	} else {
+		SEQFIFOLOAD(p, MSG1, 0, VLF | LAST1 | FLUSH1);
+		MOVE(p, OFIFO, 0, MATH1, 4, PDCP_MAC_I_LEN, WAITCOMP | IMMED);
+		MATHB(p, MATH1, XOR, PDCP_NULL_INT_MAC_I_VAL, NONE, 4, IMMED2);
+		JUMP(p, PDCP_NULL_INT_ICV_CHECK_FAILED_STATUS,
+		     HALT_STATUS, ALL_FALSE, MATH_Z);
+	}
+
+	return 0;
+}
+
+static inline int
+pdcp_insert_cplane_acc_op(struct program *p,
+			  struct alginfo *cipherdata,
+			  struct alginfo *authdata,
+			  unsigned int dir,
+			  unsigned char era_2_hfn_ovrd __maybe_unused)
+{
+	/* Insert Auth Key */
+	KEY(p, KEY2, authdata->key_enc_flags, authdata->key, authdata->keylen,
+	    INLINE_KEY(authdata));
+
+	/* Insert Cipher Key */
+	KEY(p, KEY1, cipherdata->key_enc_flags, cipherdata->key,
+	    cipherdata->keylen, INLINE_KEY(cipherdata));
+	PROTOCOL(p, dir, OP_PCLID_LTE_PDCP_CTRL, (uint16_t)cipherdata->algtype);
+
+	return 0;
+}
+
+static inline int
+pdcp_insert_cplane_snow_aes_op(struct program *p,
+			       struct alginfo *cipherdata,
+			       struct alginfo *authdata,
+			       unsigned int dir,
+			       unsigned char era_2_sw_hfn_ovrd)
+{
+	LABEL(back_to_sd_offset);
+	LABEL(end_desc);
+	LABEL(local_offset);
+	LABEL(jump_to_beginning);
+	LABEL(fifo_load_mac_i_offset);
+	REFERENCE(seqin_ptr_read);
+	REFERENCE(seqin_ptr_write);
+	REFERENCE(seq_out_read);
+	REFERENCE(jump_back_to_sd_cmd);
+	REFERENCE(move_mac_i_to_desc_buf);
+
+	if (rta_sec_era >= RTA_SEC_ERA_8) {
+		KEY(p, KEY1, cipherdata->key_enc_flags, cipherdata->key,
+				cipherdata->keylen, INLINE_KEY(cipherdata));
+		KEY(p, KEY2, authdata->key_enc_flags, authdata->key,
+				authdata->keylen, INLINE_KEY(authdata));
+
+		PROTOCOL(p, dir, OP_PCLID_LTE_PDCP_CTRL_MIXED,
+			 ((uint16_t)cipherdata->algtype << 8) |
+			 (uint16_t)authdata->algtype);
+
+		return 0;
+	}
+
+	SEQLOAD(p, MATH0, 7, 1, 0);
+	JUMP(p, 1, LOCAL_JUMP, ALL_TRUE, CALM);
+	MATHB(p, MATH0, AND, PDCP_C_PLANE_SN_MASK, MATH1, 8, IFB | IMMED2);
+	MATHB(p, MATH1, SHLD, MATH1, MATH1, 8, 0);
+	MOVE(p, DESCBUF, 4, MATH2, 0, 0x08, WAITCOMP | IMMED);
+	MATHB(p, MATH1, OR, MATH2, MATH2, 8, 0);
+	SEQSTORE(p, MATH0, 7, 1, 0);
+	if (dir == OP_TYPE_ENCAP_PROTOCOL) {
+		if (rta_sec_era > RTA_SEC_ERA_2 ||
+		    (rta_sec_era == RTA_SEC_ERA_2 &&
+				   era_2_sw_hfn_ovrd == 0)) {
+			SEQINPTR(p, 0, 1, RTO);
+		} else {
+			SEQINPTR(p, 0, 5, RTO);
+			SEQFIFOLOAD(p, SKIP, 4, 0);
+		}
+		KEY(p, KEY1, authdata->key_enc_flags, authdata->key,
+		    authdata->keylen, INLINE_KEY(authdata));
+		MOVE(p, MATH2, 0, IFIFOAB1, 0, 0x08, IMMED);
+
+		if (rta_sec_era > RTA_SEC_ERA_2) {
+			MATHB(p, SEQINSZ, SUB, ZERO, VSEQINSZ, 4, 0);
+			MATHB(p, SEQINSZ, SUB, ZERO, MATH1, 4, 0);
+			MATHB(p, VSEQINSZ, ADD, PDCP_MAC_I_LEN - 1, VSEQOUTSZ,
+			      4, IMMED2);
+		} else {
+			MATHB(p, SEQINSZ, SUB, MATH3, VSEQINSZ, 4, 0);
+			MATHB(p, VSEQINSZ, ADD, PDCP_MAC_I_LEN - 1, VSEQOUTSZ,
+			      4, IMMED2);
+			/*
+			 * Note: Although the calculations below might seem a
+			 * little off, the logic is the following:
+			 *
+			 * - SEQ IN PTR RTO below needs the full length of the
+			 *   frame; in case of P4080_REV_2_HFN_OV_WORKAROUND,
+			 *   this means the length of the frame to be processed
+			 *   + 4 bytes (the HFN override flag and value).
+			 *   The length of the frame to be processed minus 1
+			 *   byte is in the VSIL register (because
+			 *   VSIL = SIL + 3, due to 1 byte, the header being
+			 *   already written by the SEQ STORE above). So for
+			 *   calculating the length to use in RTO, I add one
+			 *   to the VSIL value in order to obtain the total
+			 *   frame length. This helps in case of P4080 which
+			 *   can have the value 0 as an operand in a MATH
+			 *   command only as SRC1 When the HFN override
+			 *   workaround is not enabled, the length of the
+			 *   frame is given by the SIL register; the
+			 *   calculation is similar to the one in the SEC 4.2
+			 *   and SEC 5.3 cases.
+			 */
+			if (era_2_sw_hfn_ovrd)
+				MATHB(p, VSEQOUTSZ, ADD, ONE, MATH1, 4,
+				      0);
+			else
+				MATHB(p, SEQINSZ, ADD, MATH3, MATH1, 4,
+				      0);
+		}
+		/*
+		 * Placeholder for filling the length in
+		 * SEQIN PTR RTO below
+		 */
+		seqin_ptr_read = MOVE(p, DESCBUF, 0, MATH1, 0, 6, IMMED);
+		seqin_ptr_write = MOVE(p, MATH1, 0, DESCBUF, 0, 8,
+				       WAITCOMP | IMMED);
+		ALG_OPERATION(p, OP_ALG_ALGSEL_AES,
+			      OP_ALG_AAI_CMAC,
+			      OP_ALG_AS_INITFINAL,
+			      ICV_CHECK_DISABLE,
+			      DIR_DEC);
+		SEQFIFOLOAD(p, MSG1, 0, VLF | LAST1 | FLUSH1);
+		MOVE(p, CONTEXT1, 0, MATH3, 0, 4, WAITCOMP | IMMED);
+		if (rta_sec_era <= RTA_SEC_ERA_3)
+			LOAD(p, CLRW_CLR_C1KEY |
+			     CLRW_CLR_C1CTX |
+			     CLRW_CLR_C1ICV |
+			     CLRW_CLR_C1DATAS |
+			     CLRW_CLR_C1MODE,
+			     CLRW, 0, 4, IMMED);
+		else
+			LOAD(p, CLRW_RESET_CLS1_CHA |
+			     CLRW_CLR_C1KEY |
+			     CLRW_CLR_C1CTX |
+			     CLRW_CLR_C1ICV |
+			     CLRW_CLR_C1DATAS |
+			     CLRW_CLR_C1MODE,
+			     CLRW, 0, 4, IMMED);
+
+		if (rta_sec_era <= RTA_SEC_ERA_3)
+			LOAD(p, CCTRL_RESET_CHA_ALL, CCTRL, 0, 4, IMMED);
+
+		KEY(p, KEY1, cipherdata->key_enc_flags, cipherdata->key,
+		    cipherdata->keylen, INLINE_KEY(cipherdata));
+		SET_LABEL(p, local_offset);
+		MOVE(p, MATH2, 0, CONTEXT1, 0, 8, IMMED);
+		SEQINPTR(p, 0, 0, RTO);
+
+		if (rta_sec_era == RTA_SEC_ERA_2 && era_2_sw_hfn_ovrd) {
+			SEQFIFOLOAD(p, SKIP, 5, 0);
+			MATHB(p, SEQINSZ, ADD, ONE, SEQINSZ, 4, 0);
+		}
+
+		MATHB(p, SEQINSZ, SUB, ONE, VSEQINSZ, 4, 0);
+		ALG_OPERATION(p, OP_ALG_ALGSEL_SNOW_F8,
+			      OP_ALG_AAI_F8,
+			      OP_ALG_AS_INITFINAL,
+			      ICV_CHECK_DISABLE,
+			      DIR_ENC);
+		SEQFIFOSTORE(p, MSG, 0, 0, VLF);
+
+		if (rta_sec_era > RTA_SEC_ERA_2 ||
+		    (rta_sec_era == RTA_SEC_ERA_2 &&
+				   era_2_sw_hfn_ovrd == 0))
+			SEQFIFOLOAD(p, SKIP, 1, 0);
+
+		SEQFIFOLOAD(p, MSG1, 0, VLF);
+		MOVE(p, MATH3, 0, IFIFOAB1, 0, 4, LAST1 | FLUSH1 | IMMED);
+		PATCH_MOVE(p, seqin_ptr_read, local_offset);
+		PATCH_MOVE(p, seqin_ptr_write, local_offset);
+	} else {
+		MOVE(p, MATH2, 0, CONTEXT1, 0, 8, IMMED);
+
+		if (rta_sec_era >= RTA_SEC_ERA_5)
+			MOVE(p, CONTEXT1, 0, CONTEXT2, 0, 8, IMMED);
+
+		if (rta_sec_era > RTA_SEC_ERA_2)
+			MATHB(p, SEQINSZ, SUB, ZERO, VSEQINSZ, 4, 0);
+		else
+			MATHB(p, SEQINSZ, SUB, MATH3, VSEQINSZ, 4, 0);
+
+		MATHB(p, SEQINSZ, SUB, PDCP_MAC_I_LEN, VSEQOUTSZ, 4, IMMED2);
+/*
+ * TODO: To be changed when proper support is added in RTA (can't load a
+ * command that is also written by RTA (or patch it for that matter).
+ * Change when proper RTA support is added.
+ */
+		if (p->ps)
+			WORD(p, 0x168B0004);
+		else
+			WORD(p, 0x16880404);
+
+		jump_back_to_sd_cmd = JUMP(p, 0, LOCAL_JUMP, ALL_TRUE, 0);
+		/*
+		 * Placeholder for command reading  the SEQ OUT command in
+		 * JD. Done for rereading the decrypted data and performing
+		 * the integrity check
+		 */
+/*
+ * TODO: RTA currently doesn't support patching of length of a MOVE command
+ * Thus, it is inserted as a raw word, as per PS setting.
+ */
+		if (p->ps)
+			seq_out_read = MOVE(p, DESCBUF, 0, MATH1, 0, 20,
+					    WAITCOMP | IMMED);
+		else
+			seq_out_read = MOVE(p, DESCBUF, 0, MATH1, 0, 16,
+					    WAITCOMP | IMMED);
+
+		MATHB(p, MATH1, XOR, CMD_SEQ_IN_PTR ^ CMD_SEQ_OUT_PTR, MATH1, 4,
+		      IMMED2);
+		/* Placeholder for overwriting the SEQ IN  with SEQ OUT */
+/*
+ * TODO: RTA currently doesn't support patching of length of a MOVE command
+ * Thus, it is inserted as a raw word, as per PS setting.
+ */
+		if (p->ps)
+			MOVE(p, MATH1, 0, DESCBUF, 0, 24, IMMED);
+		else
+			MOVE(p, MATH1, 0, DESCBUF, 0, 20, IMMED);
+
+		KEY(p, KEY1, cipherdata->key_enc_flags, cipherdata->key,
+		    cipherdata->keylen, INLINE_KEY(cipherdata));
+
+		if (rta_sec_era >= RTA_SEC_ERA_4)
+			MOVE(p, CONTEXT1, 0, CONTEXT2, 0, 8, IMMED);
+		else
+			MOVE(p, CONTEXT1, 0, MATH3, 0, 8, IMMED);
+
+		ALG_OPERATION(p, OP_ALG_ALGSEL_SNOW_F8,
+			      OP_ALG_AAI_F8,
+			      OP_ALG_AS_INITFINAL,
+			      ICV_CHECK_DISABLE,
+			      DIR_DEC);
+		SEQFIFOSTORE(p, MSG, 0, 0, VLF | CONT);
+		SEQFIFOLOAD(p, MSG1, 0, VLF | LAST1 | FLUSH1);
+
+		if (rta_sec_era <= RTA_SEC_ERA_3)
+			move_mac_i_to_desc_buf = MOVE(p, OFIFO, 0, DESCBUF, 0,
+						      4, WAITCOMP | IMMED);
+		else
+			MOVE(p, OFIFO, 0, MATH3, 0, 4, IMMED);
+
+		if (rta_sec_era <= RTA_SEC_ERA_3)
+			LOAD(p, CCTRL_RESET_CHA_ALL, CCTRL, 0, 4, IMMED);
+		else
+			LOAD(p, CLRW_RESET_CLS1_CHA |
+			     CLRW_CLR_C1KEY |
+			     CLRW_CLR_C1CTX |
+			     CLRW_CLR_C1ICV |
+			     CLRW_CLR_C1DATAS |
+			     CLRW_CLR_C1MODE,
+			     CLRW, 0, 4, IMMED);
+
+		KEY(p, KEY1, authdata->key_enc_flags, authdata->key,
+		    authdata->keylen, INLINE_KEY(authdata));
+		/*
+		 * Placeholder for jump in SD for executing the new SEQ IN PTR
+		 * command (which is actually the old SEQ OUT PTR command
+		 * copied over from JD.
+		 */
+		SET_LABEL(p, jump_to_beginning);
+		JUMP(p, 1 - jump_to_beginning, LOCAL_JUMP, ALL_TRUE, 0);
+		SET_LABEL(p, back_to_sd_offset);
+		ALG_OPERATION(p, OP_ALG_ALGSEL_AES,
+			      OP_ALG_AAI_CMAC,
+			      OP_ALG_AS_INITFINAL,
+			      ICV_CHECK_ENABLE,
+			      DIR_DEC);
+
+		/* Read the # of bytes written in the output buffer + 1 (HDR) */
+		MATHB(p, VSEQOUTSZ, ADD, ONE, VSEQINSZ, 4, 0);
+
+		if (rta_sec_era <= RTA_SEC_ERA_3)
+			MOVE(p, MATH3, 0, IFIFOAB1, 0, 8, IMMED);
+		else
+			MOVE(p, CONTEXT2, 0, IFIFOAB1, 0, 8, IMMED);
+
+		if (rta_sec_era == RTA_SEC_ERA_2 && era_2_sw_hfn_ovrd)
+			SEQFIFOLOAD(p, SKIP, 4, 0);
+
+		SEQFIFOLOAD(p, MSG1, 0, VLF | LAST1 | FLUSH1);
+
+		if (rta_sec_era >= RTA_SEC_ERA_4) {
+			LOAD(p, NFIFOENTRY_STYPE_ALTSOURCE |
+			     NFIFOENTRY_DEST_CLASS1 |
+			     NFIFOENTRY_DTYPE_ICV |
+			     NFIFOENTRY_LC1 |
+			     NFIFOENTRY_FC1 | 4, NFIFO_SZL, 0, 4, IMMED);
+			MOVE(p, MATH3, 0, ALTSOURCE, 0, 4, IMMED);
+		} else {
+			SET_LABEL(p, fifo_load_mac_i_offset);
+			FIFOLOAD(p, ICV1, fifo_load_mac_i_offset, 4,
+				 LAST1 | FLUSH1 | IMMED);
+		}
+
+		SET_LABEL(p, end_desc);
+
+		if (!p->ps) {
+			PATCH_MOVE(p, seq_out_read, end_desc + 1);
+			PATCH_JUMP(p, jump_back_to_sd_cmd,
+				   back_to_sd_offset + jump_back_to_sd_cmd - 5);
+
+			if (rta_sec_era <= RTA_SEC_ERA_3)
+				PATCH_MOVE(p, move_mac_i_to_desc_buf,
+					   fifo_load_mac_i_offset + 1);
+		} else {
+			PATCH_MOVE(p, seq_out_read, end_desc + 2);
+			PATCH_JUMP(p, jump_back_to_sd_cmd,
+				   back_to_sd_offset + jump_back_to_sd_cmd - 5);
+
+			if (rta_sec_era <= RTA_SEC_ERA_3)
+				PATCH_MOVE(p, move_mac_i_to_desc_buf,
+					   fifo_load_mac_i_offset + 1);
+		}
+	}
+
+	return 0;
+}
+
+static inline int
+pdcp_insert_cplane_aes_snow_op(struct program *p,
+			       struct alginfo *cipherdata,
+			       struct alginfo *authdata,
+			       unsigned int dir,
+			       unsigned char era_2_sw_hfn_ovrd __maybe_unused)
+{
+	KEY(p, KEY1, cipherdata->key_enc_flags, cipherdata->key,
+	    cipherdata->keylen, INLINE_KEY(cipherdata));
+	KEY(p, KEY2, authdata->key_enc_flags, authdata->key, authdata->keylen,
+	    INLINE_KEY(authdata));
+
+	if (rta_sec_era >= RTA_SEC_ERA_8) {
+		PROTOCOL(p, dir, OP_PCLID_LTE_PDCP_CTRL_MIXED,
+			 ((uint16_t)cipherdata->algtype << 8) |
+			 (uint16_t)authdata->algtype);
+
+		return 0;
+	}
+
+	if (dir == OP_TYPE_ENCAP_PROTOCOL)
+		MATHB(p, SEQINSZ, SUB, ONE, VSEQINSZ, 4, 0);
+
+	SEQLOAD(p, MATH0, 7, 1, 0);
+	JUMP(p, 1, LOCAL_JUMP, ALL_TRUE, CALM);
+	MOVE(p, MATH0, 7, IFIFOAB2, 0, 1, IMMED);
+	MATHB(p, MATH0, AND, PDCP_C_PLANE_SN_MASK, MATH1, 8, IFB | IMMED2);
+	SEQSTORE(p, MATH0, 7, 1, 0);
+	MATHB(p, MATH1, SHLD, MATH1, MATH1, 8, 0);
+	MOVE(p, DESCBUF, 4, MATH2, 0, 8, WAITCOMP | IMMED);
+	MATHB(p, MATH1, OR, MATH2, MATH1, 8, 0);
+	MOVE(p, MATH1, 0, CONTEXT1, 16, 8, IMMED);
+	MOVE(p, MATH1, 0, CONTEXT2, 0, 4, IMMED);
+	MATHB(p, MATH1, AND, lower_32_bits(PDCP_BEARER_MASK), MATH2, 4, IMMED2);
+	MATHB(p, MATH1, AND, upper_32_bits(PDCP_DIR_MASK), MATH3, 4, IMMED2);
+	MATHB(p, MATH3, SHLD, MATH3, MATH3, 8, 0);
+	MOVE(p, MATH2, 4, OFIFO, 0, 12, IMMED);
+	MOVE(p, OFIFO, 0, CONTEXT2, 4, 12, IMMED);
+	if (dir == OP_TYPE_ENCAP_PROTOCOL) {
+		MATHB(p, SEQINSZ, ADD, PDCP_MAC_I_LEN, VSEQOUTSZ, 4, IMMED2);
+	} else {
+		MATHB(p, SEQINSZ, SUB, PDCP_MAC_I_LEN, MATH1, 4, IMMED2);
+
+		MATHB(p, ZERO, ADD, MATH1, VSEQOUTSZ, 4, 0);
+		MATHB(p, ZERO, ADD, MATH1, VSEQINSZ, 4, 0);
+	}
+
+	if (dir == OP_TYPE_ENCAP_PROTOCOL)
+		SEQFIFOSTORE(p, MSG, 0, 0, VLF);
+	else
+		SEQFIFOSTORE(p, MSG, 0, 0, VLF | CONT);
+
+	ALG_OPERATION(p, OP_ALG_ALGSEL_SNOW_F9,
+		      OP_ALG_AAI_F9,
+		      OP_ALG_AS_INITFINAL,
+		      dir == OP_TYPE_ENCAP_PROTOCOL ?
+			     ICV_CHECK_DISABLE : ICV_CHECK_ENABLE,
+		      DIR_DEC);
+	ALG_OPERATION(p, OP_ALG_ALGSEL_AES,
+		      OP_ALG_AAI_CTR,
+		      OP_ALG_AS_INITFINAL,
+		      ICV_CHECK_DISABLE,
+		      dir == OP_TYPE_ENCAP_PROTOCOL ? DIR_ENC : DIR_DEC);
+
+	if (dir == OP_TYPE_ENCAP_PROTOCOL) {
+		SEQFIFOLOAD(p, MSGINSNOOP, 0, VLF | LAST2);
+		MOVE(p, CONTEXT2, 0, IFIFOAB1, 0, 4, LAST1 | FLUSH1 | IMMED);
+	} else {
+		SEQFIFOLOAD(p, MSGOUTSNOOP, 0, VLF | LAST2);
+		SEQFIFOLOAD(p, MSG1, 4, LAST1 | FLUSH1);
+		JUMP(p, 1, LOCAL_JUMP, ALL_TRUE, CLASS1 | NOP | NIFP);
+
+		if (rta_sec_era >= RTA_SEC_ERA_6)
+			LOAD(p, 0, DCTRL, 0, LDLEN_RST_CHA_OFIFO_PTR, IMMED);
+
+		MOVE(p, OFIFO, 0, MATH0, 0, 4, WAITCOMP | IMMED);
+
+		NFIFOADD(p, IFIFO, ICV2, 4, LAST2);
+
+		if (rta_sec_era <= RTA_SEC_ERA_2) {
+			/* Shut off automatic Info FIFO entries */
+			LOAD(p, 0, DCTRL, LDOFF_DISABLE_AUTO_NFIFO, 0, IMMED);
+			MOVE(p, MATH0, 0, IFIFOAB2, 0, 4, WAITCOMP | IMMED);
+		} else {
+			MOVE(p, MATH0, 0, IFIFO, 0, 4, WAITCOMP | IMMED);
+		}
+	}
+
+	return 0;
+}
+
+static inline int
+pdcp_insert_cplane_snow_zuc_op(struct program *p,
+			       struct alginfo *cipherdata,
+			       struct alginfo *authdata,
+			       unsigned int dir,
+			       unsigned char era_2_sw_hfn_ovrd __maybe_unused)
+{
+	LABEL(keyjump);
+	REFERENCE(pkeyjump);
+
+	if (rta_sec_era < RTA_SEC_ERA_5) {
+		pr_err("Invalid era for selected algorithm\n");
+		return -ENOTSUP;
+	}
+
+	pkeyjump = JUMP(p, keyjump, LOCAL_JUMP, ALL_TRUE, SHRD | SELF | BOTH);
+	KEY(p, KEY1, cipherdata->key_enc_flags, cipherdata->key,
+	    cipherdata->keylen, INLINE_KEY(cipherdata));
+	KEY(p, KEY2, authdata->key_enc_flags, authdata->key, authdata->keylen,
+	    INLINE_KEY(authdata));
+
+	SET_LABEL(p, keyjump);
+
+	if (rta_sec_era >= RTA_SEC_ERA_8) {
+		PROTOCOL(p, dir, OP_PCLID_LTE_PDCP_CTRL_MIXED,
+			 ((uint16_t)cipherdata->algtype << 8) |
+			 (uint16_t)authdata->algtype);
+		return 0;
+	}
+
+	SEQLOAD(p, MATH0, 7, 1, 0);
+	JUMP(p, 1, LOCAL_JUMP, ALL_TRUE, CALM);
+	MOVE(p, MATH0, 7, IFIFOAB2, 0, 1, IMMED);
+	MATHB(p, MATH0, AND, PDCP_C_PLANE_SN_MASK, MATH1, 8, IFB | IMMED2);
+	MATHB(p, MATH1, SHLD, MATH1, MATH1, 8, 0);
+	MOVE(p, DESCBUF, 4, MATH2, 0, 8, WAITCOMP | IMMED);
+	MATHB(p, MATH1, OR, MATH2, MATH2, 8, 0);
+	MOVE(p, MATH2, 0, CONTEXT1, 0, 8, IMMED);
+	MOVE(p, MATH2, 0, CONTEXT2, 0, 8, WAITCOMP | IMMED);
+
+	if (dir == OP_TYPE_ENCAP_PROTOCOL)
+		MATHB(p, SEQINSZ, ADD, PDCP_MAC_I_LEN, VSEQOUTSZ, 4, IMMED2);
+	else
+		MATHB(p, SEQINSZ, SUB, PDCP_MAC_I_LEN, VSEQOUTSZ, 4, IMMED2);
+
+	MATHB(p, SEQINSZ, SUB, ZERO, VSEQINSZ, 4, 0);
+	SEQSTORE(p, MATH0, 7, 1, 0);
+
+	if (dir == OP_TYPE_ENCAP_PROTOCOL) {
+		SEQFIFOSTORE(p, MSG, 0, 0, VLF);
+		SEQFIFOLOAD(p, MSGINSNOOP, 0, VLF | LAST2);
+	} else {
+		SEQFIFOSTORE(p, MSG, 0, 0, VLF | CONT);
+		SEQFIFOLOAD(p, MSGOUTSNOOP, 0, VLF | LAST1 | FLUSH1);
+	}
+
+	ALG_OPERATION(p, OP_ALG_ALGSEL_ZUCA,
+		      OP_ALG_AAI_F9,
+		      OP_ALG_AS_INITFINAL,
+		      dir == OP_TYPE_ENCAP_PROTOCOL ?
+			     ICV_CHECK_DISABLE : ICV_CHECK_ENABLE,
+		      DIR_ENC);
+
+	ALG_OPERATION(p, OP_ALG_ALGSEL_SNOW_F8,
+		      OP_ALG_AAI_F8,
+		      OP_ALG_AS_INITFINAL,
+		      ICV_CHECK_DISABLE,
+		      dir == OP_TYPE_ENCAP_PROTOCOL ? DIR_ENC : DIR_DEC);
+	if (dir == OP_TYPE_ENCAP_PROTOCOL) {
+		MOVE(p, CONTEXT2, 0, IFIFOAB1, 0, 4, LAST1 | FLUSH1 | IMMED);
+	} else {
+		/* Save ICV */
+		MOVE(p, OFIFO, 0, MATH0, 0, 4, IMMED);
+		LOAD(p, NFIFOENTRY_STYPE_ALTSOURCE |
+		     NFIFOENTRY_DEST_CLASS2 |
+		     NFIFOENTRY_DTYPE_ICV |
+		     NFIFOENTRY_LC2 | 4, NFIFO_SZL, 0, 4, IMMED);
+		MOVE(p, MATH0, 0, ALTSOURCE, 0, 4, WAITCOMP | IMMED);
+	}
+
+	/* Reset ZUCA mode and done interrupt */
+	LOAD(p, CLRW_CLR_C2MODE, CLRW, 0, 4, IMMED);
+	LOAD(p, CIRQ_ZADI, ICTRL, 0, 4, IMMED);
+
+	PATCH_JUMP(p, pkeyjump, keyjump);
+	return 0;
+}
+
+static inline int
+pdcp_insert_cplane_aes_zuc_op(struct program *p,
+			      struct alginfo *cipherdata,
+			      struct alginfo *authdata,
+			      unsigned int dir,
+			      unsigned char era_2_sw_hfn_ovrd __maybe_unused)
+{
+	LABEL(keyjump);
+	REFERENCE(pkeyjump);
+
+	if (rta_sec_era < RTA_SEC_ERA_5) {
+		pr_err("Invalid era for selected algorithm\n");
+		return -ENOTSUP;
+	}
+
+	pkeyjump = JUMP(p, keyjump, LOCAL_JUMP, ALL_TRUE, SHRD | SELF | BOTH);
+	KEY(p, KEY1, cipherdata->key_enc_flags, cipherdata->key,
+	    cipherdata->keylen, INLINE_KEY(cipherdata));
+	KEY(p, KEY2, authdata->key_enc_flags, authdata->key, authdata->keylen,
+	    INLINE_KEY(authdata));
+
+	if (rta_sec_era >= RTA_SEC_ERA_8) {
+		PROTOCOL(p, dir, OP_PCLID_LTE_PDCP_CTRL_MIXED,
+			 ((uint16_t)cipherdata->algtype << 8) |
+			 (uint16_t)authdata->algtype);
+
+		return 0;
+	}
+
+	SET_LABEL(p, keyjump);
+	SEQLOAD(p, MATH0, 7, 1, 0);
+	JUMP(p, 1, LOCAL_JUMP, ALL_TRUE, CALM);
+	MOVE(p, MATH0, 7, IFIFOAB2, 0, 1, IMMED);
+	MATHB(p, MATH0, AND, PDCP_C_PLANE_SN_MASK, MATH1, 8, IFB | IMMED2);
+
+	MATHB(p, MATH1, SHLD, MATH1, MATH1, 8, 0);
+	MOVE(p, DESCBUF, 4, MATH2, 0, 8, WAITCOMP | IMMED);
+	MATHB(p, MATH1, OR, MATH2, MATH2, 8, 0);
+	MOVE(p, MATH2, 0, CONTEXT1, 16, 8, IMMED);
+	MOVE(p, MATH2, 0, CONTEXT2, 0, 8, WAITCOMP | IMMED);
+
+	if (dir == OP_TYPE_ENCAP_PROTOCOL)
+		MATHB(p, SEQINSZ, ADD, PDCP_MAC_I_LEN, VSEQOUTSZ, 4, IMMED2);
+	else
+		MATHB(p, SEQINSZ, SUB, PDCP_MAC_I_LEN, VSEQOUTSZ, 4, IMMED2);
+
+	MATHB(p, SEQINSZ, SUB, ZERO, VSEQINSZ, 4, 0);
+	SEQSTORE(p, MATH0, 7, 1, 0);
+
+	if (dir == OP_TYPE_ENCAP_PROTOCOL) {
+		SEQFIFOSTORE(p, MSG, 0, 0, VLF);
+		SEQFIFOLOAD(p, MSGINSNOOP, 0, VLF | LAST2);
+	} else {
+		SEQFIFOSTORE(p, MSG, 0, 0, VLF | CONT);
+		SEQFIFOLOAD(p, MSGOUTSNOOP, 0, VLF | LAST1 | FLUSH1);
+	}
+
+	ALG_OPERATION(p, OP_ALG_ALGSEL_ZUCA,
+		      OP_ALG_AAI_F9,
+		      OP_ALG_AS_INITFINAL,
+		      dir == OP_TYPE_ENCAP_PROTOCOL ?
+			     ICV_CHECK_DISABLE : ICV_CHECK_ENABLE,
+		      DIR_ENC);
+
+	ALG_OPERATION(p, OP_ALG_ALGSEL_AES,
+		      OP_ALG_AAI_CTR,
+		      OP_ALG_AS_INITFINAL,
+		      ICV_CHECK_DISABLE,
+		      dir == OP_TYPE_ENCAP_PROTOCOL ? DIR_ENC : DIR_DEC);
+
+	if (dir == OP_TYPE_ENCAP_PROTOCOL) {
+		MOVE(p, CONTEXT2, 0, IFIFOAB1, 0, 4, LAST1 | FLUSH1 | IMMED);
+	} else {
+		/* Save ICV */
+		MOVE(p, OFIFO, 0, MATH0, 0, 4, IMMED);
+
+		LOAD(p, NFIFOENTRY_STYPE_ALTSOURCE |
+		     NFIFOENTRY_DEST_CLASS2 |
+		     NFIFOENTRY_DTYPE_ICV |
+		     NFIFOENTRY_LC2 | 4, NFIFO_SZL, 0, 4, IMMED);
+		MOVE(p, MATH0, 0, ALTSOURCE, 0, 4, WAITCOMP | IMMED);
+	}
+
+	/* Reset ZUCA mode and done interrupt */
+	LOAD(p, CLRW_CLR_C2MODE, CLRW, 0, 4, IMMED);
+	LOAD(p, CIRQ_ZADI, ICTRL, 0, 4, IMMED);
+
+	PATCH_JUMP(p, pkeyjump, keyjump);
+
+	return 0;
+}
+
+static inline int
+pdcp_insert_cplane_zuc_snow_op(struct program *p,
+			       struct alginfo *cipherdata,
+			       struct alginfo *authdata,
+			       unsigned int dir,
+			       unsigned char era_2_sw_hfn_ovrd __maybe_unused)
+{
+	LABEL(keyjump);
+	REFERENCE(pkeyjump);
+
+	if (rta_sec_era < RTA_SEC_ERA_5) {
+		pr_err("Invalid era for selected algorithm\n");
+		return -ENOTSUP;
+	}
+
+	pkeyjump = JUMP(p, keyjump, LOCAL_JUMP, ALL_TRUE, SHRD | SELF | BOTH);
+	KEY(p, KEY1, cipherdata->key_enc_flags, cipherdata->key,
+	    cipherdata->keylen, INLINE_KEY(cipherdata));
+	KEY(p, KEY2, authdata->key_enc_flags, authdata->key, authdata->keylen,
+	    INLINE_KEY(authdata));
+
+	if (rta_sec_era >= RTA_SEC_ERA_8) {
+		PROTOCOL(p, dir, OP_PCLID_LTE_PDCP_CTRL_MIXED,
+			 ((uint16_t)cipherdata->algtype << 8) |
+			 (uint16_t)authdata->algtype);
+
+		return 0;
+	}
+
+	SET_LABEL(p, keyjump);
+	SEQLOAD(p, MATH0, 7, 1, 0);
+	JUMP(p, 1, LOCAL_JUMP, ALL_TRUE, CALM);
+	MOVE(p, MATH0, 7, IFIFOAB2, 0, 1, IMMED);
+	MATHB(p, MATH0, AND, PDCP_C_PLANE_SN_MASK, MATH1, 8, IFB | IMMED2);
+	MATHB(p, MATH1, SHLD, MATH1, MATH1, 8, 0);
+	MOVE(p, DESCBUF, 4, MATH2, 0, 8, WAITCOMP | IMMED);
+	MATHB(p, MATH1, OR, MATH2, MATH1, 8, 0);
+	MOVE(p, MATH1, 0, CONTEXT1, 0, 8, IMMED);
+	MOVE(p, MATH1, 0, CONTEXT2, 0, 4, IMMED);
+	MATHB(p, MATH1, AND, lower_32_bits(PDCP_BEARER_MASK), MATH2, 4, IMMED2);
+	MATHB(p, MATH1, AND, upper_32_bits(PDCP_DIR_MASK), MATH3, 4, IMMED2);
+	MATHB(p, MATH3, SHLD, MATH3, MATH3, 8, 0);
+	MOVE(p, MATH2, 4, OFIFO, 0, 12, IMMED);
+	MOVE(p, OFIFO, 0, CONTEXT2, 4, 12, IMMED);
+
+	if (dir == OP_TYPE_ENCAP_PROTOCOL) {
+		MATHB(p, SEQINSZ, ADD, PDCP_MAC_I_LEN, VSEQOUTSZ, 4, IMMED2);
+		MATHB(p, SEQINSZ, SUB, ZERO, VSEQINSZ, 4, 0);
+	} else {
+		MATHB(p, SEQINSZ, SUB, PDCP_MAC_I_LEN, VSEQOUTSZ, 4, IMMED2);
+		MATHB(p, VSEQOUTSZ, SUB, ZERO, VSEQINSZ, 4, 0);
+	}
+
+	SEQSTORE(p, MATH0, 7, 1, 0);
+
+	if (dir == OP_TYPE_ENCAP_PROTOCOL) {
+		SEQFIFOSTORE(p, MSG, 0, 0, VLF);
+		SEQFIFOLOAD(p, MSGINSNOOP, 0, VLF | LAST2);
+	} else {
+		SEQFIFOSTORE(p, MSG, 0, 0, VLF | CONT);
+		SEQFIFOLOAD(p, MSGOUTSNOOP, 0, VLF | LAST2);
+	}
+
+	ALG_OPERATION(p, OP_ALG_ALGSEL_SNOW_F9,
+		      OP_ALG_AAI_F9,
+		      OP_ALG_AS_INITFINAL,
+		      dir == OP_TYPE_ENCAP_PROTOCOL ?
+			     ICV_CHECK_DISABLE : ICV_CHECK_ENABLE,
+		      DIR_DEC);
+
+	ALG_OPERATION(p, OP_ALG_ALGSEL_ZUCE,
+		      OP_ALG_AAI_F8,
+		      OP_ALG_AS_INITFINAL,
+		      ICV_CHECK_DISABLE,
+		      dir == OP_TYPE_ENCAP_PROTOCOL ? DIR_ENC : DIR_DEC);
+
+	if (dir == OP_TYPE_ENCAP_PROTOCOL) {
+		MOVE(p, CONTEXT2, 0, IFIFOAB1, 0, 4, LAST1 | FLUSH1 | IMMED);
+	} else {
+		SEQFIFOLOAD(p, MSG1, 4, LAST1 | FLUSH1);
+		JUMP(p, 1, LOCAL_JUMP, ALL_TRUE, CLASS1 | NOP | NIFP);
+
+		if (rta_sec_era >= RTA_SEC_ERA_6)
+			/*
+			 * For SEC ERA 6, there's a problem with the OFIFO
+			 * pointer, and thus it needs to be reset here before
+			 * moving to M0.
+			 */
+			LOAD(p, 0, DCTRL, 0, LDLEN_RST_CHA_OFIFO_PTR, IMMED);
+
+		/* Put ICV to M0 before sending it to C2 for comparison. */
+		MOVE(p, OFIFO, 0, MATH0, 0, 4, WAITCOMP | IMMED);
+
+		LOAD(p, NFIFOENTRY_STYPE_ALTSOURCE |
+		     NFIFOENTRY_DEST_CLASS2 |
+		     NFIFOENTRY_DTYPE_ICV |
+		     NFIFOENTRY_LC2 | 4, NFIFO_SZL, 0, 4, IMMED);
+		MOVE(p, MATH0, 0, ALTSOURCE, 0, 4, IMMED);
+	}
+
+	PATCH_JUMP(p, pkeyjump, keyjump);
+	return 0;
+}
+
+static inline int
+pdcp_insert_cplane_zuc_aes_op(struct program *p,
+			      struct alginfo *cipherdata,
+			      struct alginfo *authdata,
+			      unsigned int dir,
+			      unsigned char era_2_sw_hfn_ovrd __maybe_unused)
+{
+	if (rta_sec_era < RTA_SEC_ERA_5) {
+		pr_err("Invalid era for selected algorithm\n");
+		return -ENOTSUP;
+	}
+
+	if (rta_sec_era >= RTA_SEC_ERA_8) {
+		KEY(p, KEY1, cipherdata->key_enc_flags, cipherdata->key,
+				cipherdata->keylen, INLINE_KEY(cipherdata));
+		KEY(p, KEY2, authdata->key_enc_flags, authdata->key,
+				authdata->keylen, INLINE_KEY(authdata));
+
+		PROTOCOL(p, dir, OP_PCLID_LTE_PDCP_CTRL_MIXED,
+			 ((uint16_t)cipherdata->algtype << 8) |
+			 (uint16_t)authdata->algtype);
+		return 0;
+	}
+
+	SEQLOAD(p, MATH0, 7, 1, 0);
+	JUMP(p, 1, LOCAL_JUMP, ALL_TRUE, CALM);
+	MATHB(p, MATH0, AND, PDCP_C_PLANE_SN_MASK, MATH1, 8, IFB | IMMED2);
+	MATHB(p, MATH1, SHLD, MATH1, MATH1, 8, 0);
+	MOVE(p, DESCBUF, 4, MATH2, 0, 0x08, WAITCOMP | IMMED);
+	MATHB(p, MATH1, OR, MATH2, MATH2, 8, 0);
+	SEQSTORE(p, MATH0, 7, 1, 0);
+	if (dir == OP_TYPE_ENCAP_PROTOCOL) {
+		KEY(p, KEY1, authdata->key_enc_flags, authdata->key,
+		    authdata->keylen, INLINE_KEY(authdata));
+		MOVE(p, MATH2, 0, IFIFOAB1, 0, 0x08, IMMED);
+		MOVE(p, MATH0, 7, IFIFOAB1, 0, 1, IMMED);
+
+		MATHB(p, SEQINSZ, SUB, ZERO, VSEQINSZ, 4, 0);
+		MATHB(p, VSEQINSZ, ADD, PDCP_MAC_I_LEN, VSEQOUTSZ, 4, IMMED2);
+
+		ALG_OPERATION(p, OP_ALG_ALGSEL_AES,
+			      OP_ALG_AAI_CMAC,
+			      OP_ALG_AS_INITFINAL,
+			      ICV_CHECK_DISABLE,
+			      DIR_DEC);
+		SEQFIFOLOAD(p, MSG1, 0, VLF | LAST1 | FLUSH1);
+		MOVE(p, CONTEXT1, 0, MATH3, 0, 4, WAITCOMP | IMMED);
+		LOAD(p, CLRW_RESET_CLS1_CHA |
+		     CLRW_CLR_C1KEY |
+		     CLRW_CLR_C1CTX |
+		     CLRW_CLR_C1ICV |
+		     CLRW_CLR_C1DATAS |
+		     CLRW_CLR_C1MODE,
+		     CLRW, 0, 4, IMMED);
+
+		KEY(p, KEY1, cipherdata->key_enc_flags, cipherdata->key,
+		    cipherdata->keylen, INLINE_KEY(cipherdata));
+
+		MOVE(p, MATH2, 0, CONTEXT1, 0, 8, IMMED);
+		SEQINPTR(p, 0, PDCP_NULL_MAX_FRAME_LEN, RTO);
+
+		ALG_OPERATION(p, OP_ALG_ALGSEL_ZUCE,
+			      OP_ALG_AAI_F8,
+			      OP_ALG_AS_INITFINAL,
+			      ICV_CHECK_DISABLE,
+			      DIR_ENC);
+		SEQFIFOSTORE(p, MSG, 0, 0, VLF);
+
+		SEQFIFOLOAD(p, SKIP, 1, 0);
+
+		SEQFIFOLOAD(p, MSG1, 0, VLF);
+		MOVE(p, MATH3, 0, IFIFOAB1, 0, 4, LAST1 | FLUSH1 | IMMED);
+	} else {
+		MOVE(p, MATH2, 0, CONTEXT1, 0, 8, IMMED);
+
+		MOVE(p, CONTEXT1, 0, CONTEXT2, 0, 8, IMMED);
+
+		MATHB(p, SEQINSZ, SUB, ZERO, VSEQINSZ, 4, 0);
+
+		MATHB(p, SEQINSZ, SUB, PDCP_MAC_I_LEN, VSEQOUTSZ, 4, IMMED2);
+
+		KEY(p, KEY1, cipherdata->key_enc_flags, cipherdata->key,
+		    cipherdata->keylen, INLINE_KEY(cipherdata));
+
+		MOVE(p, CONTEXT1, 0, CONTEXT2, 0, 8, IMMED);
+
+		ALG_OPERATION(p, OP_ALG_ALGSEL_ZUCE,
+			      OP_ALG_AAI_F8,
+			      OP_ALG_AS_INITFINAL,
+			      ICV_CHECK_DISABLE,
+			      DIR_DEC);
+		SEQFIFOSTORE(p, MSG, 0, 0, VLF | CONT);
+		SEQFIFOLOAD(p, MSG1, 0, VLF | LAST1 | FLUSH1);
+
+		MOVE(p, OFIFO, 0, MATH3, 0, 4, IMMED);
+
+		LOAD(p, CLRW_RESET_CLS1_CHA |
+		     CLRW_CLR_C1KEY |
+		     CLRW_CLR_C1CTX |
+		     CLRW_CLR_C1ICV |
+		     CLRW_CLR_C1DATAS |
+		     CLRW_CLR_C1MODE,
+		     CLRW, 0, 4, IMMED);
+
+		KEY(p, KEY1, authdata->key_enc_flags, authdata->key,
+		    authdata->keylen, INLINE_KEY(authdata));
+
+		SEQINPTR(p, 0, 0, SOP);
+
+		ALG_OPERATION(p, OP_ALG_ALGSEL_AES,
+			      OP_ALG_AAI_CMAC,
+			      OP_ALG_AS_INITFINAL,
+			      ICV_CHECK_ENABLE,
+			      DIR_DEC);
+
+		MATHB(p, SEQINSZ, SUB, ZERO, VSEQINSZ, 4, 0);
+
+		MOVE(p, CONTEXT2, 0, IFIFOAB1, 0, 8, IMMED);
+
+		SEQFIFOLOAD(p, MSG1, 0, VLF | LAST1 | FLUSH1);
+
+		LOAD(p, NFIFOENTRY_STYPE_ALTSOURCE |
+		     NFIFOENTRY_DEST_CLASS1 |
+		     NFIFOENTRY_DTYPE_ICV |
+		     NFIFOENTRY_LC1 |
+		     NFIFOENTRY_FC1 | 4, NFIFO_SZL, 0, 4, IMMED);
+		MOVE(p, MATH3, 0, ALTSOURCE, 0, 4, IMMED);
+	}
+
+	return 0;
+}
+
+static inline int
+pdcp_insert_uplane_15bit_op(struct program *p,
+			    struct alginfo *cipherdata,
+			    unsigned int dir)
+{
+	int op;
+	/* Insert Cipher Key */
+	KEY(p, KEY1, cipherdata->key_enc_flags, cipherdata->key,
+	    cipherdata->keylen, INLINE_KEY(cipherdata));
+
+	if (rta_sec_era >= RTA_SEC_ERA_8) {
+		PROTOCOL(p, dir, OP_PCLID_LTE_PDCP_USER,
+			 (uint16_t)cipherdata->algtype);
+		return 0;
+	}
+
+	SEQLOAD(p, MATH0, 6, 2, 0);
+	JUMP(p, 1, LOCAL_JUMP, ALL_TRUE, CALM);
+	MATHB(p, MATH0, AND, PDCP_U_PLANE_15BIT_SN_MASK, MATH1, 8,
+	      IFB | IMMED2);
+	SEQSTORE(p, MATH0, 6, 2, 0);
+	MATHB(p, MATH1, SHLD, MATH1, MATH1, 8, 0);
+	MOVE(p, DESCBUF, 8, MATH2, 0, 8, WAITCOMP | IMMED);
+	MATHB(p, MATH1, OR, MATH2, MATH2, 8, 0);
+
+	MATHB(p, SEQINSZ, SUB, MATH3, VSEQINSZ, 4, 0);
+	MATHB(p, SEQINSZ, SUB, MATH3, VSEQOUTSZ, 4, 0);
+
+	SEQFIFOSTORE(p, MSG, 0, 0, VLF);
+
+	op = dir == OP_TYPE_ENCAP_PROTOCOL ? DIR_ENC : DIR_DEC;
+	switch (cipherdata->algtype) {
+	case PDCP_CIPHER_TYPE_SNOW:
+		MOVE(p, MATH2, 0, CONTEXT1, 0, 8, WAITCOMP | IMMED);
+		ALG_OPERATION(p, OP_ALG_ALGSEL_SNOW_F8,
+			      OP_ALG_AAI_F8,
+			      OP_ALG_AS_INITFINAL,
+			      ICV_CHECK_DISABLE,
+			      op);
+		break;
+
+	case PDCP_CIPHER_TYPE_AES:
+		MOVE(p, MATH2, 0, CONTEXT1, 0x10, 0x10, WAITCOMP | IMMED);
+		ALG_OPERATION(p, OP_ALG_ALGSEL_AES,
+			      OP_ALG_AAI_CTR,
+			      OP_ALG_AS_INITFINAL,
+			      ICV_CHECK_DISABLE,
+			      op);
+		break;
+
+	case PDCP_CIPHER_TYPE_ZUC:
+		if (rta_sec_era < RTA_SEC_ERA_5) {
+			pr_err("Invalid era for selected algorithm\n");
+			return -ENOTSUP;
+		}
+		MOVE(p, MATH2, 0, CONTEXT1, 0, 0x08, IMMED);
+		MOVE(p, MATH2, 0, CONTEXT1, 0x08, 0x08, WAITCOMP | IMMED);
+
+		ALG_OPERATION(p, OP_ALG_ALGSEL_ZUCE,
+			      OP_ALG_AAI_F8,
+			      OP_ALG_AS_INITFINAL,
+			      ICV_CHECK_DISABLE,
+			      op);
+		break;
+
+	default:
+		pr_err("%s: Invalid encrypt algorithm selected: %d\n",
+		       "pdcp_insert_uplane_15bit_op", cipherdata->algtype);
+		return -EINVAL;
+	}
+
+	SEQFIFOLOAD(p, MSG1, 0, VLF | LAST1 | FLUSH1);
+
+	return 0;
+}
+
+/*
+ * Function for inserting the snippet of code responsible for creating
+ * the HFN override code via either DPOVRD or via the input frame.
+ */
+static inline int
+insert_hfn_ov_op(struct program *p,
+		 uint32_t shift,
+		 enum pdb_type_e pdb_type,
+		 unsigned char era_2_sw_hfn_ovrd)
+{
+	uint32_t imm = 0x80000000;
+	uint16_t hfn_pdb_offset;
+
+	if (rta_sec_era == RTA_SEC_ERA_2 && !era_2_sw_hfn_ovrd)
+		return 0;
+
+	switch (pdb_type) {
+	case PDCP_PDB_TYPE_NO_PDB:
+		/*
+		 * If there is no PDB, then HFN override mechanism does not
+		 * make any sense, thus in this case the function will
+		 * return the pointer to the current position in the
+		 * descriptor buffer
+		 */
+		return 0;
+
+	case PDCP_PDB_TYPE_REDUCED_PDB:
+		hfn_pdb_offset = 4;
+		break;
+
+	case PDCP_PDB_TYPE_FULL_PDB:
+		hfn_pdb_offset = 8;
+		break;
+
+	default:
+		return -EINVAL;
+	}
+
+	if (rta_sec_era > RTA_SEC_ERA_2) {
+		MATHB(p, DPOVRD, AND, imm, NONE, 8, IFB | IMMED2);
+	} else {
+		SEQLOAD(p, MATH0, 4, 4, 0);
+		JUMP(p, 1, LOCAL_JUMP, ALL_TRUE, CALM);
+		MATHB(p, MATH0, AND, imm, NONE, 8, IFB | IMMED2);
+		SEQSTORE(p, MATH0, 4, 4, 0);
+	}
+
+	JUMP(p, 5, LOCAL_JUMP, ALL_TRUE, MATH_Z);
+
+	if (rta_sec_era > RTA_SEC_ERA_2)
+		MATHB(p, DPOVRD, LSHIFT, shift, MATH0, 4, IMMED2);
+	else
+		MATHB(p, MATH0, LSHIFT, shift, MATH0, 4, IMMED2);
+
+	MATHB(p, MATH0, SHLD, MATH0, MATH0, 8, 0);
+	MOVE(p, MATH0, 0, DESCBUF, hfn_pdb_offset, 4, IMMED);
+
+	return 0;
+}
+
+/*
+ * PDCP Control PDB creation function
+ */
+static inline enum pdb_type_e
+cnstr_pdcp_c_plane_pdb(struct program *p,
+		       uint32_t hfn,
+		       unsigned char bearer,
+		       unsigned char direction,
+		       uint32_t hfn_threshold,
+		       struct alginfo *cipherdata,
+		       struct alginfo *authdata)
+{
+	struct pdcp_pdb pdb;
+	enum pdb_type_e
+		pdb_mask[PDCP_CIPHER_TYPE_INVALID][PDCP_AUTH_TYPE_INVALID] = {
+			{	/* NULL */
+				PDCP_PDB_TYPE_NO_PDB,		/* NULL */
+				PDCP_PDB_TYPE_FULL_PDB,		/* SNOW f9 */
+				PDCP_PDB_TYPE_FULL_PDB,		/* AES CMAC */
+				PDCP_PDB_TYPE_FULL_PDB		/* ZUC-I */
+			},
+			{	/* SNOW f8 */
+				PDCP_PDB_TYPE_FULL_PDB,		/* NULL */
+				PDCP_PDB_TYPE_FULL_PDB,		/* SNOW f9 */
+				PDCP_PDB_TYPE_REDUCED_PDB,	/* AES CMAC */
+				PDCP_PDB_TYPE_REDUCED_PDB	/* ZUC-I */
+			},
+			{	/* AES CTR */
+				PDCP_PDB_TYPE_FULL_PDB,		/* NULL */
+				PDCP_PDB_TYPE_REDUCED_PDB,	/* SNOW f9 */
+				PDCP_PDB_TYPE_FULL_PDB,		/* AES CMAC */
+				PDCP_PDB_TYPE_REDUCED_PDB	/* ZUC-I */
+			},
+			{	/* ZUC-E */
+				PDCP_PDB_TYPE_FULL_PDB,		/* NULL */
+				PDCP_PDB_TYPE_REDUCED_PDB,	/* SNOW f9 */
+				PDCP_PDB_TYPE_REDUCED_PDB,	/* AES CMAC */
+				PDCP_PDB_TYPE_FULL_PDB		/* ZUC-I */
+			},
+	};
+
+	if (rta_sec_era >= RTA_SEC_ERA_8) {
+		memset(&pdb, 0x00, sizeof(struct pdcp_pdb));
+
+		/* This is a HW issue. Bit 2 should be set to zero,
+		 * but it does not work this way. Override here.
+		 */
+		pdb.opt_res.rsvd = 0x00000002;
+
+		/* Copy relevant information from user to PDB */
+		pdb.hfn_res = hfn << PDCP_C_PLANE_PDB_HFN_SHIFT;
+		pdb.bearer_dir_res = (uint32_t)
+				((bearer << PDCP_C_PLANE_PDB_BEARER_SHIFT) |
+				 (direction << PDCP_C_PLANE_PDB_DIR_SHIFT));
+		pdb.hfn_thr_res =
+				hfn_threshold << PDCP_C_PLANE_PDB_HFN_THR_SHIFT;
+
+		/* copy PDB in descriptor*/
+		__rta_out32(p, pdb.opt_res.opt);
+		__rta_out32(p, pdb.hfn_res);
+		__rta_out32(p, pdb.bearer_dir_res);
+		__rta_out32(p, pdb.hfn_thr_res);
+
+		return PDCP_PDB_TYPE_FULL_PDB;
+	}
+
+	switch (pdb_mask[cipherdata->algtype][authdata->algtype]) {
+	case PDCP_PDB_TYPE_NO_PDB:
+		break;
+
+	case PDCP_PDB_TYPE_REDUCED_PDB:
+		__rta_out32(p, (hfn << PDCP_C_PLANE_PDB_HFN_SHIFT));
+		__rta_out32(p,
+			    (uint32_t)((bearer <<
+					PDCP_C_PLANE_PDB_BEARER_SHIFT) |
+					(direction <<
+					 PDCP_C_PLANE_PDB_DIR_SHIFT)));
+		break;
+
+	case PDCP_PDB_TYPE_FULL_PDB:
+		memset(&pdb, 0x00, sizeof(struct pdcp_pdb));
+
+		/* This is a HW issue. Bit 2 should be set to zero,
+		 * but it does not work this way. Override here.
+		 */
+		pdb.opt_res.rsvd = 0x00000002;
+
+		/* Copy relevant information from user to PDB */
+		pdb.hfn_res = hfn << PDCP_C_PLANE_PDB_HFN_SHIFT;
+		pdb.bearer_dir_res = (uint32_t)
+			((bearer << PDCP_C_PLANE_PDB_BEARER_SHIFT) |
+			 (direction << PDCP_C_PLANE_PDB_DIR_SHIFT));
+		pdb.hfn_thr_res =
+			hfn_threshold << PDCP_C_PLANE_PDB_HFN_THR_SHIFT;
+
+		/* copy PDB in descriptor*/
+		__rta_out32(p, pdb.opt_res.opt);
+		__rta_out32(p, pdb.hfn_res);
+		__rta_out32(p, pdb.bearer_dir_res);
+		__rta_out32(p, pdb.hfn_thr_res);
+
+		break;
+
+	default:
+		return PDCP_PDB_TYPE_INVALID;
+	}
+
+	return pdb_mask[cipherdata->algtype][authdata->algtype];
+}
+
+/*
+ * PDCP UPlane PDB creation function
+ */
+static inline int
+cnstr_pdcp_u_plane_pdb(struct program *p,
+		       enum pdcp_sn_size sn_size,
+		       uint32_t hfn, unsigned short bearer,
+		       unsigned short direction,
+		       uint32_t hfn_threshold)
+{
+	struct pdcp_pdb pdb;
+	/* Read options from user */
+	/* Depending on sequence number length, the HFN and HFN threshold
+	 * have different lengths.
+	 */
+	memset(&pdb, 0x00, sizeof(struct pdcp_pdb));
+
+	switch (sn_size) {
+	case PDCP_SN_SIZE_7:
+		pdb.opt_res.opt |= PDCP_U_PLANE_PDB_OPT_SHORT_SN;
+		pdb.hfn_res = hfn << PDCP_U_PLANE_PDB_SHORT_SN_HFN_SHIFT;
+		pdb.hfn_thr_res =
+			hfn_threshold<<PDCP_U_PLANE_PDB_SHORT_SN_HFN_THR_SHIFT;
+		break;
+
+	case PDCP_SN_SIZE_12:
+		pdb.opt_res.opt &= (uint32_t)(~PDCP_U_PLANE_PDB_OPT_SHORT_SN);
+		pdb.hfn_res = hfn << PDCP_U_PLANE_PDB_LONG_SN_HFN_SHIFT;
+		pdb.hfn_thr_res =
+			hfn_threshold<<PDCP_U_PLANE_PDB_LONG_SN_HFN_THR_SHIFT;
+		break;
+
+	case PDCP_SN_SIZE_15:
+		pdb.opt_res.opt = (uint32_t)(PDCP_U_PLANE_PDB_OPT_15B_SN);
+		pdb.hfn_res = hfn << PDCP_U_PLANE_PDB_15BIT_SN_HFN_SHIFT;
+		pdb.hfn_thr_res =
+			hfn_threshold<<PDCP_U_PLANE_PDB_15BIT_SN_HFN_THR_SHIFT;
+		break;
+
+	default:
+		pr_err("Invalid Sequence Number Size setting in PDB\n");
+		return -EINVAL;
+	}
+
+	pdb.bearer_dir_res = (uint32_t)
+				((bearer << PDCP_U_PLANE_PDB_BEARER_SHIFT) |
+				 (direction << PDCP_U_PLANE_PDB_DIR_SHIFT));
+
+	/* copy PDB in descriptor*/
+	__rta_out32(p, pdb.opt_res.opt);
+	__rta_out32(p, pdb.hfn_res);
+	__rta_out32(p, pdb.bearer_dir_res);
+	__rta_out32(p, pdb.hfn_thr_res);
+
+	return 0;
+}
+/**
+ * cnstr_shdsc_pdcp_c_plane_encap - Function for creating a PDCP Control Plane
+ *                                  encapsulation descriptor.
+ * @descbuf: pointer to buffer for descriptor construction
+ * @ps: if 36/40bit addressing is desired, this parameter must be true
+ * @swap: must be true when core endianness doesn't match SEC endianness
+ * @hfn: starting Hyper Frame Number to be used together with the SN from the
+ *       PDCP frames.
+ * @bearer: radio bearer ID
+ * @direction: the direction of the PDCP frame (UL/DL)
+ * @hfn_threshold: HFN value that once reached triggers a warning from SEC that
+ *                 keys should be renegotiated at the earliest convenience.
+ * @cipherdata: pointer to block cipher transform definitions
+ *              Valid algorithm values are those from cipher_type_pdcp enum.
+ * @authdata: pointer to authentication transform definitions
+ *            Valid algorithm values are those from auth_type_pdcp enum.
+ * @era_2_sw_hfn_ovrd: if software HFN override mechanism is desired for
+ *                     this descriptor. Note: Can only be used for
+ *                     SEC ERA 2.
+ * Return: size of descriptor written in words or negative number on error.
+ *         Once the function returns, the value of this parameter can be used
+ *         for reclaiming the space that wasn't used for the descriptor.
+ *
+ * Note: descbuf must be large enough to contain a full 256 byte long
+ * descriptor; after the function returns, by subtracting the actual number of
+ * bytes used, the user can reuse the remaining buffer space for other purposes.
+ */
+static inline int
+cnstr_shdsc_pdcp_c_plane_encap(uint32_t *descbuf,
+			       bool ps,
+			       bool swap,
+			       uint32_t hfn,
+			       unsigned char bearer,
+			       unsigned char direction,
+			       uint32_t hfn_threshold,
+			       struct alginfo *cipherdata,
+			       struct alginfo *authdata,
+			       unsigned char era_2_sw_hfn_ovrd)
+{
+	static int
+		(*pdcp_cp_fp[PDCP_CIPHER_TYPE_INVALID][PDCP_AUTH_TYPE_INVALID])
+			(struct program*, struct alginfo *,
+			 struct alginfo *, unsigned int,
+			unsigned char __maybe_unused) = {
+		{	/* NULL */
+			pdcp_insert_cplane_null_op,	/* NULL */
+			pdcp_insert_cplane_int_only_op,	/* SNOW f9 */
+			pdcp_insert_cplane_int_only_op,	/* AES CMAC */
+			pdcp_insert_cplane_int_only_op	/* ZUC-I */
+		},
+		{	/* SNOW f8 */
+			pdcp_insert_cplane_enc_only_op,	/* NULL */
+			pdcp_insert_cplane_acc_op,	/* SNOW f9 */
+			pdcp_insert_cplane_snow_aes_op,	/* AES CMAC */
+			pdcp_insert_cplane_snow_zuc_op	/* ZUC-I */
+		},
+		{	/* AES CTR */
+			pdcp_insert_cplane_enc_only_op,	/* NULL */
+			pdcp_insert_cplane_aes_snow_op,	/* SNOW f9 */
+			pdcp_insert_cplane_acc_op,	/* AES CMAC */
+			pdcp_insert_cplane_aes_zuc_op	/* ZUC-I */
+		},
+		{	/* ZUC-E */
+			pdcp_insert_cplane_enc_only_op,	/* NULL */
+			pdcp_insert_cplane_zuc_snow_op,	/* SNOW f9 */
+			pdcp_insert_cplane_zuc_aes_op,	/* AES CMAC */
+			pdcp_insert_cplane_acc_op	/* ZUC-I */
+		},
+	};
+	static enum rta_share_type
+		desc_share[PDCP_CIPHER_TYPE_INVALID][PDCP_AUTH_TYPE_INVALID] = {
+		{	/* NULL */
+			SHR_WAIT,	/* NULL */
+			SHR_ALWAYS,	/* SNOW f9 */
+			SHR_ALWAYS,	/* AES CMAC */
+			SHR_ALWAYS	/* ZUC-I */
+		},
+		{	/* SNOW f8 */
+			SHR_ALWAYS,	/* NULL */
+			SHR_ALWAYS,	/* SNOW f9 */
+			SHR_WAIT,	/* AES CMAC */
+			SHR_WAIT	/* ZUC-I */
+		},
+		{	/* AES CTR */
+			SHR_ALWAYS,	/* NULL */
+			SHR_ALWAYS,	/* SNOW f9 */
+			SHR_ALWAYS,	/* AES CMAC */
+			SHR_WAIT	/* ZUC-I */
+		},
+		{	/* ZUC-E */
+			SHR_ALWAYS,	/* NULL */
+			SHR_WAIT,	/* SNOW f9 */
+			SHR_WAIT,	/* AES CMAC */
+			SHR_ALWAYS	/* ZUC-I */
+		},
+	};
+	enum pdb_type_e pdb_type;
+	struct program prg;
+	struct program *p = &prg;
+	int err;
+	LABEL(pdb_end);
+
+	if (rta_sec_era != RTA_SEC_ERA_2 && era_2_sw_hfn_ovrd) {
+		pr_err("Cannot select SW HFN override for other era than 2");
+		return -EINVAL;
+	}
+
+	PROGRAM_CNTXT_INIT(p, descbuf, 0);
+	if (swap)
+		PROGRAM_SET_BSWAP(p);
+	if (ps)
+		PROGRAM_SET_36BIT_ADDR(p);
+
+	SHR_HDR(p, desc_share[cipherdata->algtype][authdata->algtype], 0, 0);
+
+	pdb_type = cnstr_pdcp_c_plane_pdb(p,
+			hfn,
+			bearer,
+			direction,
+			hfn_threshold,
+			cipherdata,
+			authdata);
+
+	SET_LABEL(p, pdb_end);
+
+	err = insert_hfn_ov_op(p, PDCP_SN_SIZE_5, pdb_type,
+			       era_2_sw_hfn_ovrd);
+	if (err)
+		return err;
+
+	err = pdcp_cp_fp[cipherdata->algtype][authdata->algtype](p,
+		cipherdata,
+		authdata,
+		OP_TYPE_ENCAP_PROTOCOL,
+		era_2_sw_hfn_ovrd);
+	if (err)
+		return err;
+
+	PATCH_HDR(p, 0, pdb_end);
+
+	return PROGRAM_FINALIZE(p);
+}
+
+/**
+ * cnstr_shdsc_pdcp_c_plane_decap - Function for creating a PDCP Control Plane
+ *                                  decapsulation descriptor.
+ * @descbuf: pointer to buffer for descriptor construction
+ * @ps: if 36/40bit addressing is desired, this parameter must be true
+ * @swap: must be true when core endianness doesn't match SEC endianness
+ * @hfn: starting Hyper Frame Number to be used together with the SN from the
+ *       PDCP frames.
+ * @bearer: radio bearer ID
+ * @direction: the direction of the PDCP frame (UL/DL)
+ * @hfn_threshold: HFN value that once reached triggers a warning from SEC that
+ *                 keys should be renegotiated at the earliest convenience.
+ * @cipherdata: pointer to block cipher transform definitions
+ *              Valid algorithm values are those from cipher_type_pdcp enum.
+ * @authdata: pointer to authentication transform definitions
+ *            Valid algorithm values are those from auth_type_pdcp enum.
+ * @era_2_sw_hfn_ovrd: if software HFN override mechanism is desired for
+ *                     this descriptor. Note: Can only be used for
+ *                     SEC ERA 2.
+ *
+ * Return: size of descriptor written in words or negative number on error.
+ *         Once the function returns, the value of this parameter can be used
+ *         for reclaiming the space that wasn't used for the descriptor.
+ *
+ * Note: descbuf must be large enough to contain a full 256 byte long
+ * descriptor; after the function returns, by subtracting the actual number of
+ * bytes used, the user can reuse the remaining buffer space for other purposes.
+ */
+static inline int
+cnstr_shdsc_pdcp_c_plane_decap(uint32_t *descbuf,
+			       bool ps,
+			       bool swap,
+			       uint32_t hfn,
+			       unsigned char bearer,
+			       unsigned char direction,
+			       uint32_t hfn_threshold,
+			       struct alginfo *cipherdata,
+			       struct alginfo *authdata,
+			       unsigned char era_2_sw_hfn_ovrd)
+{
+	static int
+		(*pdcp_cp_fp[PDCP_CIPHER_TYPE_INVALID][PDCP_AUTH_TYPE_INVALID])
+			(struct program*, struct alginfo *,
+			 struct alginfo *, unsigned int, unsigned char) = {
+		{	/* NULL */
+			pdcp_insert_cplane_null_op,	/* NULL */
+			pdcp_insert_cplane_int_only_op,	/* SNOW f9 */
+			pdcp_insert_cplane_int_only_op,	/* AES CMAC */
+			pdcp_insert_cplane_int_only_op	/* ZUC-I */
+		},
+		{	/* SNOW f8 */
+			pdcp_insert_cplane_enc_only_op,	/* NULL */
+			pdcp_insert_cplane_acc_op,	/* SNOW f9 */
+			pdcp_insert_cplane_snow_aes_op,	/* AES CMAC */
+			pdcp_insert_cplane_snow_zuc_op	/* ZUC-I */
+		},
+		{	/* AES CTR */
+			pdcp_insert_cplane_enc_only_op,	/* NULL */
+			pdcp_insert_cplane_aes_snow_op,	/* SNOW f9 */
+			pdcp_insert_cplane_acc_op,	/* AES CMAC */
+			pdcp_insert_cplane_aes_zuc_op	/* ZUC-I */
+		},
+		{	/* ZUC-E */
+			pdcp_insert_cplane_enc_only_op,	/* NULL */
+			pdcp_insert_cplane_zuc_snow_op,	/* SNOW f9 */
+			pdcp_insert_cplane_zuc_aes_op,	/* AES CMAC */
+			pdcp_insert_cplane_acc_op	/* ZUC-I */
+		},
+	};
+	static enum rta_share_type
+		desc_share[PDCP_CIPHER_TYPE_INVALID][PDCP_AUTH_TYPE_INVALID] = {
+		{	/* NULL */
+			SHR_WAIT,	/* NULL */
+			SHR_ALWAYS,	/* SNOW f9 */
+			SHR_ALWAYS,	/* AES CMAC */
+			SHR_ALWAYS	/* ZUC-I */
+		},
+		{	/* SNOW f8 */
+			SHR_ALWAYS,	/* NULL */
+			SHR_ALWAYS,	/* SNOW f9 */
+			SHR_WAIT,	/* AES CMAC */
+			SHR_WAIT	/* ZUC-I */
+		},
+		{	/* AES CTR */
+			SHR_ALWAYS,	/* NULL */
+			SHR_ALWAYS,	/* SNOW f9 */
+			SHR_ALWAYS,	/* AES CMAC */
+			SHR_WAIT	/* ZUC-I */
+		},
+		{	/* ZUC-E */
+			SHR_ALWAYS,	/* NULL */
+			SHR_WAIT,	/* SNOW f9 */
+			SHR_WAIT,	/* AES CMAC */
+			SHR_ALWAYS	/* ZUC-I */
+		},
+	};
+	enum pdb_type_e pdb_type;
+	struct program prg;
+	struct program *p = &prg;
+	int err;
+	LABEL(pdb_end);
+
+	if (rta_sec_era != RTA_SEC_ERA_2 && era_2_sw_hfn_ovrd) {
+		pr_err("Cannot select SW HFN override for other era than 2");
+		return -EINVAL;
+	}
+
+	PROGRAM_CNTXT_INIT(p, descbuf, 0);
+	if (swap)
+		PROGRAM_SET_BSWAP(p);
+	if (ps)
+		PROGRAM_SET_36BIT_ADDR(p);
+
+	SHR_HDR(p, desc_share[cipherdata->algtype][authdata->algtype], 0, 0);
+
+	pdb_type = cnstr_pdcp_c_plane_pdb(p,
+			hfn,
+			bearer,
+			direction,
+			hfn_threshold,
+			cipherdata,
+			authdata);
+
+	SET_LABEL(p, pdb_end);
+
+	err = insert_hfn_ov_op(p, PDCP_SN_SIZE_5, pdb_type,
+			       era_2_sw_hfn_ovrd);
+	if (err)
+		return err;
+
+	err = pdcp_cp_fp[cipherdata->algtype][authdata->algtype](p,
+		cipherdata,
+		authdata,
+		OP_TYPE_DECAP_PROTOCOL,
+		era_2_sw_hfn_ovrd);
+	if (err)
+		return err;
+
+	PATCH_HDR(p, 0, pdb_end);
+
+	return PROGRAM_FINALIZE(p);
+}
+
+/**
+ * cnstr_shdsc_pdcp_u_plane_encap - Function for creating a PDCP User Plane
+ *                                  encapsulation descriptor.
+ * @descbuf: pointer to buffer for descriptor construction
+ * @ps: if 36/40bit addressing is desired, this parameter must be true
+ * @swap: must be true when core endianness doesn't match SEC endianness
+ * @sn_size: selects Sequence Number Size: 7/12/15 bits
+ * @hfn: starting Hyper Frame Number to be used together with the SN from the
+ *       PDCP frames.
+ * @bearer: radio bearer ID
+ * @direction: the direction of the PDCP frame (UL/DL)
+ * @hfn_threshold: HFN value that once reached triggers a warning from SEC that
+ *                 keys should be renegotiated at the earliest convenience.
+ * @cipherdata: pointer to block cipher transform definitions
+ *              Valid algorithm values are those from cipher_type_pdcp enum.
+ * @era_2_sw_hfn_ovrd: if software HFN override mechanism is desired for
+ *                     this descriptor. Note: Can only be used for
+ *                     SEC ERA 2.
+ *
+ * Return: size of descriptor written in words or negative number on error.
+ *         Once the function returns, the value of this parameter can be used
+ *         for reclaiming the space that wasn't used for the descriptor.
+ *
+ * Note: descbuf must be large enough to contain a full 256 byte long
+ * descriptor; after the function returns, by subtracting the actual number of
+ * bytes used, the user can reuse the remaining buffer space for other purposes.
+ */
+static inline int
+cnstr_shdsc_pdcp_u_plane_encap(uint32_t *descbuf,
+			       bool ps,
+			       bool swap,
+			       enum pdcp_sn_size sn_size,
+			       uint32_t hfn,
+			       unsigned short bearer,
+			       unsigned short direction,
+			       uint32_t hfn_threshold,
+			       struct alginfo *cipherdata,
+			       unsigned char era_2_sw_hfn_ovrd)
+{
+	struct program prg;
+	struct program *p = &prg;
+	int err;
+	LABEL(pdb_end);
+
+	if (rta_sec_era != RTA_SEC_ERA_2 && era_2_sw_hfn_ovrd) {
+		pr_err("Cannot select SW HFN ovrd for other era than 2");
+		return -EINVAL;
+	}
+
+	PROGRAM_CNTXT_INIT(p, descbuf, 0);
+	if (swap)
+		PROGRAM_SET_BSWAP(p);
+	if (ps)
+		PROGRAM_SET_36BIT_ADDR(p);
+
+	SHR_HDR(p, SHR_ALWAYS, 0, 0);
+	if (cnstr_pdcp_u_plane_pdb(p, sn_size, hfn, bearer, direction,
+				   hfn_threshold)) {
+		pr_err("Error creating PDCP UPlane PDB\n");
+		return -EINVAL;
+	}
+	SET_LABEL(p, pdb_end);
+
+	err = insert_hfn_ov_op(p, sn_size, PDCP_PDB_TYPE_FULL_PDB,
+			       era_2_sw_hfn_ovrd);
+	if (err)
+		return err;
+
+	switch (sn_size) {
+	case PDCP_SN_SIZE_7:
+	case PDCP_SN_SIZE_12:
+		switch (cipherdata->algtype) {
+		case PDCP_CIPHER_TYPE_ZUC:
+			if (rta_sec_era < RTA_SEC_ERA_5) {
+				pr_err("Invalid era for selected algorithm\n");
+				return -ENOTSUP;
+			}
+		case PDCP_CIPHER_TYPE_AES:
+		case PDCP_CIPHER_TYPE_SNOW:
+			/* Insert Cipher Key */
+			KEY(p, KEY1, cipherdata->key_enc_flags,
+			    (uint64_t)cipherdata->key, cipherdata->keylen,
+			    INLINE_KEY(cipherdata));
+			PROTOCOL(p, OP_TYPE_ENCAP_PROTOCOL,
+				 OP_PCLID_LTE_PDCP_USER,
+				 (uint16_t)cipherdata->algtype);
+			break;
+		case PDCP_CIPHER_TYPE_NULL:
+			insert_copy_frame_op(p,
+					     cipherdata,
+					     OP_TYPE_ENCAP_PROTOCOL);
+			break;
+		default:
+			pr_err("%s: Invalid encrypt algorithm selected: %d\n",
+			       "cnstr_pcl_shdsc_pdcp_u_plane_decap",
+			       cipherdata->algtype);
+			return -EINVAL;
+		}
+		break;
+
+	case PDCP_SN_SIZE_15:
+		switch (cipherdata->algtype) {
+		case PDCP_CIPHER_TYPE_NULL:
+			insert_copy_frame_op(p,
+					     cipherdata,
+					     OP_TYPE_ENCAP_PROTOCOL);
+			break;
+
+		default:
+			err = pdcp_insert_uplane_15bit_op(p, cipherdata,
+				OP_TYPE_ENCAP_PROTOCOL);
+			if (err)
+				return err;
+			break;
+		}
+		break;
+
+	case PDCP_SN_SIZE_5:
+	default:
+		pr_err("Invalid SN size selected\n");
+		return -ENOTSUP;
+	}
+
+	PATCH_HDR(p, 0, pdb_end);
+	return PROGRAM_FINALIZE(p);
+}
+
+/**
+ * cnstr_shdsc_pdcp_u_plane_decap - Function for creating a PDCP User Plane
+ *                                  decapsulation descriptor.
+ * @descbuf: pointer to buffer for descriptor construction
+ * @ps: if 36/40bit addressing is desired, this parameter must be true
+ * @swap: must be true when core endianness doesn't match SEC endianness
+ * @sn_size: selects Sequence Number Size: 7/12/15 bits
+ * @hfn: starting Hyper Frame Number to be used together with the SN from the
+ *       PDCP frames.
+ * @bearer: radio bearer ID
+ * @direction: the direction of the PDCP frame (UL/DL)
+ * @hfn_threshold: HFN value that once reached triggers a warning from SEC that
+ *                 keys should be renegotiated at the earliest convenience.
+ * @cipherdata: pointer to block cipher transform definitions
+ *              Valid algorithm values are those from cipher_type_pdcp enum.
+ * @era_2_sw_hfn_ovrd: if software HFN override mechanism is desired for
+ *                     this descriptor. Note: Can only be used for
+ *                     SEC ERA 2.
+ *
+ * Return: size of descriptor written in words or negative number on error.
+ *         Once the function returns, the value of this parameter can be used
+ *         for reclaiming the space that wasn't used for the descriptor.
+ *
+ * Note: descbuf must be large enough to contain a full 256 byte long
+ * descriptor; after the function returns, by subtracting the actual number of
+ * bytes used, the user can reuse the remaining buffer space for other purposes.
+ */
+static inline int
+cnstr_shdsc_pdcp_u_plane_decap(uint32_t *descbuf,
+			       bool ps,
+			       bool swap,
+			       enum pdcp_sn_size sn_size,
+			       uint32_t hfn,
+			       unsigned short bearer,
+			       unsigned short direction,
+			       uint32_t hfn_threshold,
+			       struct alginfo *cipherdata,
+			       unsigned char era_2_sw_hfn_ovrd)
+{
+	struct program prg;
+	struct program *p = &prg;
+	int err;
+	LABEL(pdb_end);
+
+	if (rta_sec_era != RTA_SEC_ERA_2 && era_2_sw_hfn_ovrd) {
+		pr_err("Cannot select SW HFN override for other era than 2");
+		return -EINVAL;
+	}
+
+	PROGRAM_CNTXT_INIT(p, descbuf, 0);
+	if (swap)
+		PROGRAM_SET_BSWAP(p);
+	if (ps)
+		PROGRAM_SET_36BIT_ADDR(p);
+
+	SHR_HDR(p, SHR_ALWAYS, 0, 0);
+	if (cnstr_pdcp_u_plane_pdb(p, sn_size, hfn, bearer, direction,
+				   hfn_threshold)) {
+		pr_err("Error creating PDCP UPlane PDB\n");
+		return -EINVAL;
+	}
+	SET_LABEL(p, pdb_end);
+
+	err = insert_hfn_ov_op(p, sn_size, PDCP_PDB_TYPE_FULL_PDB,
+			       era_2_sw_hfn_ovrd);
+	if (err)
+		return err;
+
+	switch (sn_size) {
+	case PDCP_SN_SIZE_7:
+	case PDCP_SN_SIZE_12:
+		switch (cipherdata->algtype) {
+		case PDCP_CIPHER_TYPE_ZUC:
+			if (rta_sec_era < RTA_SEC_ERA_5) {
+				pr_err("Invalid era for selected algorithm\n");
+				return -ENOTSUP;
+			}
+		case PDCP_CIPHER_TYPE_AES:
+		case PDCP_CIPHER_TYPE_SNOW:
+			/* Insert Cipher Key */
+			KEY(p, KEY1, cipherdata->key_enc_flags,
+			    cipherdata->key, cipherdata->keylen,
+			    INLINE_KEY(cipherdata));
+			PROTOCOL(p, OP_TYPE_DECAP_PROTOCOL,
+				 OP_PCLID_LTE_PDCP_USER,
+				 (uint16_t)cipherdata->algtype);
+			break;
+		case PDCP_CIPHER_TYPE_NULL:
+			insert_copy_frame_op(p,
+					     cipherdata,
+					     OP_TYPE_DECAP_PROTOCOL);
+			break;
+		default:
+			pr_err("%s: Invalid encrypt algorithm selected: %d\n",
+			       "cnstr_pcl_shdsc_pdcp_u_plane_decap",
+			       cipherdata->algtype);
+			return -EINVAL;
+		}
+		break;
+
+	case PDCP_SN_SIZE_15:
+		switch (cipherdata->algtype) {
+		case PDCP_CIPHER_TYPE_NULL:
+			insert_copy_frame_op(p,
+					     cipherdata,
+					     OP_TYPE_DECAP_PROTOCOL);
+			break;
+
+		default:
+			err = pdcp_insert_uplane_15bit_op(p, cipherdata,
+				OP_TYPE_DECAP_PROTOCOL);
+			if (err)
+				return err;
+			break;
+		}
+		break;
+
+	case PDCP_SN_SIZE_5:
+	default:
+		pr_err("Invalid SN size selected\n");
+		return -ENOTSUP;
+	}
+
+	PATCH_HDR(p, 0, pdb_end);
+	return PROGRAM_FINALIZE(p);
+}
+
+/**
+ * cnstr_shdsc_pdcp_short_mac - Function for creating a PDCP Short MAC
+ *                              descriptor.
+ * @descbuf: pointer to buffer for descriptor construction
+ * @ps: if 36/40bit addressing is desired, this parameter must be true
+ * @swap: must be true when core endianness doesn't match SEC endianness
+ * @authdata: pointer to authentication transform definitions
+ *            Valid algorithm values are those from auth_type_pdcp enum.
+ *
+ * Return: size of descriptor written in words or negative number on error.
+ *         Once the function returns, the value of this parameter can be used
+ *         for reclaiming the space that wasn't used for the descriptor.
+ *
+ * Note: descbuf must be large enough to contain a full 256 byte long
+ * descriptor; after the function returns, by subtracting the actual number of
+ * bytes used, the user can reuse the remaining buffer space for other purposes.
+ */
+static inline int
+cnstr_shdsc_pdcp_short_mac(uint32_t *descbuf,
+			   bool ps,
+			   bool swap,
+			   struct alginfo *authdata)
+{
+	struct program prg;
+	struct program *p = &prg;
+	uint32_t iv[3] = {0, 0, 0};
+	LABEL(local_offset);
+	REFERENCE(move_cmd_read_descbuf);
+	REFERENCE(move_cmd_write_descbuf);
+
+	PROGRAM_CNTXT_INIT(p, descbuf, 0);
+	if (swap)
+		PROGRAM_SET_BSWAP(p);
+	if (ps)
+		PROGRAM_SET_36BIT_ADDR(p);
+
+	SHR_HDR(p, SHR_ALWAYS, 1, 0);
+
+	if (rta_sec_era > RTA_SEC_ERA_2) {
+		MATHB(p, SEQINSZ, SUB, ZERO, VSEQINSZ, 4, 0);
+		MATHB(p, SEQINSZ, SUB, ZERO, MATH1, 4, 0);
+	} else {
+		MATHB(p, SEQINSZ, ADD, ONE, MATH1, 4, 0);
+		MATHB(p, MATH1, SUB, ONE, MATH1, 4, 0);
+		MATHB(p, ZERO, ADD, MATH1, VSEQINSZ, 4, 0);
+		MOVE(p, MATH1, 0, MATH0, 0, 8, IMMED);
+
+		/*
+		 * Since MOVELEN is available only starting with
+		 * SEC ERA 3, use poor man's MOVELEN: create a MOVE
+		 * command dynamically by writing the length from M1 by
+		 * OR-ing the command in the M1 register and MOVE the
+		 * result into the descriptor buffer. Care must be taken
+		 * wrt. the location of the command because of SEC
+		 * pipelining. The actual MOVEs are written at the end
+		 * of the descriptor due to calculations needed on the
+		 * offset in the descriptor for the MOVE command.
+		 */
+		move_cmd_read_descbuf = MOVE(p, DESCBUF, 0, MATH0, 0, 6,
+					     IMMED);
+		move_cmd_write_descbuf = MOVE(p, MATH0, 0, DESCBUF, 0, 8,
+					      WAITCOMP | IMMED);
+	}
+	MATHB(p, ZERO, ADD, MATH1, VSEQOUTSZ, 4, 0);
+
+	switch (authdata->algtype) {
+	case PDCP_AUTH_TYPE_NULL:
+		SEQFIFOSTORE(p, MSG, 0, 0, VLF);
+		if (rta_sec_era > RTA_SEC_ERA_2) {
+			MOVE(p, AB1, 0, OFIFO, 0, MATH1, 0);
+		} else {
+			SET_LABEL(p, local_offset);
+
+			/* Shut off automatic Info FIFO entries */
+			LOAD(p, 0, DCTRL, LDOFF_DISABLE_AUTO_NFIFO, 0, IMMED);
+
+			/* Placeholder for MOVE command with length from M1
+			 * register
+			 */
+			MOVE(p, IFIFOAB1, 0, OFIFO, 0, 0, IMMED);
+
+			/* Enable automatic Info FIFO entries */
+			LOAD(p, 0, DCTRL, LDOFF_ENABLE_AUTO_NFIFO, 0, IMMED);
+		}
+
+		LOAD(p, (uintptr_t)iv, MATH0, 0, 8, IMMED | COPY);
+		SEQFIFOLOAD(p, MSG1, 0, VLF | LAST1 | LAST2 | FLUSH1);
+		SEQSTORE(p, MATH0, 0, 4, 0);
+
+		break;
+
+	case PDCP_AUTH_TYPE_SNOW:
+		iv[0] = 0xFFFFFFFF;
+		iv[1] = swap ? swab32(0x04000000) : 0x04000000;
+		iv[2] = swap ? swab32(0xF8000000) : 0xF8000000;
+
+		KEY(p, KEY2, authdata->key_enc_flags, authdata->key,
+		    authdata->keylen, INLINE_KEY(authdata));
+		LOAD(p, (uintptr_t)&iv, CONTEXT2, 0, 12, IMMED | COPY);
+		ALG_OPERATION(p, OP_ALG_ALGSEL_SNOW_F9,
+			      OP_ALG_AAI_F9,
+			      OP_ALG_AS_INITFINAL,
+			      ICV_CHECK_DISABLE,
+			      DIR_ENC);
+		SEQFIFOSTORE(p, MSG, 0, 0, VLF);
+
+		if (rta_sec_era > RTA_SEC_ERA_2) {
+			MOVE(p, AB1, 0, OFIFO, 0, MATH1, 0);
+		} else {
+			SET_LABEL(p, local_offset);
+
+
+			/* Shut off automatic Info FIFO entries */
+			LOAD(p, 0, DCTRL, LDOFF_DISABLE_AUTO_NFIFO, 0, IMMED);
+
+			/* Placeholder for MOVE command with length from M1
+			 * register
+			 */
+			MOVE(p, IFIFOAB1, 0, OFIFO, 0, 0, IMMED);
+
+			/* Enable automatic Info FIFO entries */
+			LOAD(p, 0, DCTRL, LDOFF_ENABLE_AUTO_NFIFO, 0, IMMED);
+		}
+		SEQFIFOLOAD(p, MSGINSNOOP, 0, VLF | LAST1 | LAST2 | FLUSH1);
+		SEQSTORE(p, CONTEXT2, 0, 4, 0);
+
+		break;
+
+	case PDCP_AUTH_TYPE_AES:
+		iv[0] = 0xFFFFFFFF;
+		iv[1] = swap ? swab32(0xFC000000) : 0xFC000000;
+		iv[2] = 0x00000000; /* unused */
+
+		KEY(p, KEY1, authdata->key_enc_flags, authdata->key,
+		    authdata->keylen, INLINE_KEY(authdata));
+		LOAD(p, (uintptr_t)&iv, MATH0, 0, 8, IMMED | COPY);
+		MOVE(p, MATH0, 0, IFIFOAB1, 0, 8, IMMED);
+		ALG_OPERATION(p, OP_ALG_ALGSEL_AES,
+			      OP_ALG_AAI_CMAC,
+			      OP_ALG_AS_INITFINAL,
+			      ICV_CHECK_DISABLE,
+			      DIR_ENC);
+		SEQFIFOSTORE(p, MSG, 0, 0, VLF);
+
+		if (rta_sec_era > RTA_SEC_ERA_2) {
+			MOVE(p, AB2, 0, OFIFO, 0, MATH1, 0);
+		} else {
+			SET_LABEL(p, local_offset);
+
+			/* Shut off automatic Info FIFO entries */
+			LOAD(p, 0, DCTRL, LDOFF_DISABLE_AUTO_NFIFO, 0, IMMED);
+
+			/* Placeholder for MOVE command with length from M1
+			 * register
+			 */
+			MOVE(p, IFIFOAB2, 0, OFIFO, 0, 0, IMMED);
+
+			/* Enable automatic Info FIFO entries */
+			LOAD(p, 0, DCTRL, LDOFF_ENABLE_AUTO_NFIFO, 0, IMMED);
+		}
+		SEQFIFOLOAD(p, MSGINSNOOP, 0, VLF | LAST1 | LAST2 | FLUSH1);
+		SEQSTORE(p, CONTEXT1, 0, 4, 0);
+
+		break;
+
+	case PDCP_AUTH_TYPE_ZUC:
+		if (rta_sec_era < RTA_SEC_ERA_5) {
+			pr_err("Invalid era for selected algorithm\n");
+			return -ENOTSUP;
+		}
+		iv[0] = 0xFFFFFFFF;
+		iv[1] = swap ? swab32(0xFC000000) : 0xFC000000;
+		iv[2] = 0x00000000; /* unused */
+
+		KEY(p, KEY2, authdata->key_enc_flags, authdata->key,
+		    authdata->keylen, INLINE_KEY(authdata));
+		LOAD(p, (uintptr_t)&iv, CONTEXT2, 0, 12, IMMED | COPY);
+		ALG_OPERATION(p, OP_ALG_ALGSEL_ZUCA,
+			      OP_ALG_AAI_F9,
+			      OP_ALG_AS_INITFINAL,
+			      ICV_CHECK_DISABLE,
+			      DIR_ENC);
+		SEQFIFOSTORE(p, MSG, 0, 0, VLF);
+		MOVE(p, AB1, 0, OFIFO, 0, MATH1, 0);
+		SEQFIFOLOAD(p, MSGINSNOOP, 0, VLF | LAST1 | LAST2 | FLUSH1);
+		SEQSTORE(p, CONTEXT2, 0, 4, 0);
+
+		break;
+
+	default:
+		pr_err("%s: Invalid integrity algorithm selected: %d\n",
+		       "cnstr_shdsc_pdcp_short_mac", authdata->algtype);
+		return -EINVAL;
+	}
+
+
+	if (rta_sec_era < RTA_SEC_ERA_3) {
+		PATCH_MOVE(p, move_cmd_read_descbuf, local_offset);
+		PATCH_MOVE(p, move_cmd_write_descbuf, local_offset);
+	}
+
+	return PROGRAM_FINALIZE(p);
+}
+
+#endif /* __DESC_PDCP_H__ */
-- 
2.17.1

^ permalink raw reply	[flat|nested] 41+ messages in thread

* [dpdk-dev] [PATCH v3 3/3] crypto/dpaa2_sec: support pdcp offload
  2018-10-05 13:53   ` [dpdk-dev] [PATCH v3 0/3] security: support for pdcp akhil.goyal
  2018-10-05 13:53     ` [dpdk-dev] [PATCH v3 1/3] security: support pdcp protocol akhil.goyal
  2018-10-05 13:53     ` [dpdk-dev] [PATCH v3 2/3] crypto/dpaa2_sec: add sample pdcp descriptor apis akhil.goyal
@ 2018-10-05 13:53     ` akhil.goyal
  2018-10-15 12:53     ` [dpdk-dev] [PATCH v4 0/3] security: support for pdcp Akhil Goyal
  3 siblings, 0 replies; 41+ messages in thread
From: akhil.goyal @ 2018-10-05 13:53 UTC (permalink / raw)
  To: dev
  Cc: pablo.de.lara.guarch, radu.nicolau, jerin.jacob,
	narayanaprasad.athreya, Shally.Verma, Anoob.Joseph,
	Vidya.Velumuri, hemant.agrawal, Akhil Goyal

From: Akhil Goyal <akhil.goyal@nxp.com>

PDCP session configuration for lookaside protocol offload
and data path is added.

Signed-off-by: Hemant Agrawal <hemant.agrawal@nxp.com>
Signed-off-by: Akhil Goyal <akhil.goyal@nxp.com>
---
 drivers/crypto/dpaa2_sec/dpaa2_sec_dpseci.c | 233 ++++++++++++++++++++
 drivers/crypto/dpaa2_sec/dpaa2_sec_priv.h   | 172 +++++++++++++++
 2 files changed, 405 insertions(+)

diff --git a/drivers/crypto/dpaa2_sec/dpaa2_sec_dpseci.c b/drivers/crypto/dpaa2_sec/dpaa2_sec_dpseci.c
index 265a8e41a..d263c9388 100644
--- a/drivers/crypto/dpaa2_sec/dpaa2_sec_dpseci.c
+++ b/drivers/crypto/dpaa2_sec/dpaa2_sec_dpseci.c
@@ -35,6 +35,7 @@ typedef uint64_t	dma_addr_t;
 
 /* RTA header files */
 #include <hw/desc/ipsec.h>
+#include <hw/desc/pdcp.h>
 #include <hw/desc/algo.h>
 
 /* Minimum job descriptor consists of a oneword job descriptor HEADER and
@@ -74,6 +75,9 @@ build_proto_compound_fd(dpaa2_sec_session *sess,
 	struct rte_mbuf *dst_mbuf = sym_op->m_dst;
 	int retval;
 
+	if (!dst_mbuf)
+		dst_mbuf = src_mbuf;
+
 	/* Save the shared descriptor */
 	flc = &priv->flc_desc[0].flc;
 
@@ -1188,6 +1192,9 @@ build_sec_fd(struct rte_crypto_op *op,
 		case DPAA2_SEC_IPSEC:
 			ret = build_proto_fd(sess, op, fd, bpid);
 			break;
+		case DPAA2_SEC_PDCP:
+			ret = build_proto_compound_fd(sess, op, fd, bpid);
+			break;
 		case DPAA2_SEC_HASH_CIPHER:
 		default:
 			DPAA2_SEC_ERR("error: Unsupported session");
@@ -2541,6 +2548,228 @@ dpaa2_sec_set_ipsec_session(struct rte_cryptodev *dev,
 	return ret;
 }
 
+static int
+dpaa2_sec_set_pdcp_session(struct rte_cryptodev *dev,
+			   struct rte_security_session_conf *conf,
+			   void *sess)
+{
+	struct rte_security_pdcp_xform *pdcp_xform = &conf->pdcp;
+	struct rte_crypto_sym_xform *xform = conf->crypto_xform;
+	struct rte_crypto_auth_xform *auth_xform = NULL;
+	struct rte_crypto_cipher_xform *cipher_xform;
+	dpaa2_sec_session *session = (dpaa2_sec_session *)sess;
+	struct ctxt_priv *priv;
+	struct dpaa2_sec_dev_private *dev_priv = dev->data->dev_private;
+	struct alginfo authdata, cipherdata;
+	int bufsize = -1;
+	struct sec_flow_context *flc;
+
+	PMD_INIT_FUNC_TRACE();
+
+	memset(session, 0, sizeof(dpaa2_sec_session));
+
+	priv = (struct ctxt_priv *)rte_zmalloc(NULL,
+				sizeof(struct ctxt_priv) +
+				sizeof(struct sec_flc_desc),
+				RTE_CACHE_LINE_SIZE);
+
+	if (priv == NULL) {
+		DPAA2_SEC_ERR("No memory for priv CTXT");
+		return -ENOMEM;
+	}
+
+	priv->fle_pool = dev_priv->fle_pool;
+	flc = &priv->flc_desc[0].flc;
+
+	/* find xfrm types */
+	if (xform->type == RTE_CRYPTO_SYM_XFORM_CIPHER && xform->next == NULL) {
+		cipher_xform = &xform->cipher;
+	} else if (xform->type == RTE_CRYPTO_SYM_XFORM_CIPHER &&
+		   xform->next->type == RTE_CRYPTO_SYM_XFORM_AUTH) {
+		session->ext_params.aead_ctxt.auth_cipher_text = true;
+		cipher_xform = &xform->cipher;
+		auth_xform = &xform->next->auth;
+	} else if (xform->type == RTE_CRYPTO_SYM_XFORM_AUTH &&
+		   xform->next->type == RTE_CRYPTO_SYM_XFORM_CIPHER) {
+		session->ext_params.aead_ctxt.auth_cipher_text = false;
+		cipher_xform = &xform->next->cipher;
+		auth_xform = &xform->auth;
+	} else {
+		DPAA2_SEC_ERR("Invalid crypto type");
+		return -EINVAL;
+	}
+
+	session->ctxt_type = DPAA2_SEC_PDCP;
+	if (cipher_xform) {
+		session->cipher_key.data = rte_zmalloc(NULL,
+					       cipher_xform->key.length,
+					       RTE_CACHE_LINE_SIZE);
+		if (session->cipher_key.data == NULL &&
+				cipher_xform->key.length > 0) {
+			DPAA2_SEC_ERR("No Memory for cipher key");
+			rte_free(priv);
+			return -ENOMEM;
+		}
+		session->cipher_key.length = cipher_xform->key.length;
+		memcpy(session->cipher_key.data, cipher_xform->key.data,
+			cipher_xform->key.length);
+		session->dir = (cipher_xform->op == RTE_CRYPTO_CIPHER_OP_ENCRYPT) ?
+					DIR_ENC : DIR_DEC;
+		session->cipher_alg = cipher_xform->algo;
+	} else {
+		session->cipher_key.data = NULL;
+		session->cipher_key.length = 0;
+		session->cipher_alg = RTE_CRYPTO_CIPHER_NULL;
+		session->dir = DIR_ENC;
+	}
+
+	cipherdata.key = (size_t)session->cipher_key.data;
+	cipherdata.keylen = session->cipher_key.length;
+	cipherdata.key_enc_flags = 0;
+	cipherdata.key_type = RTA_DATA_IMM;
+
+	switch (session->cipher_alg) {
+	case RTE_CRYPTO_CIPHER_SNOW3G_UEA2:
+		cipherdata.algtype = PDCP_CIPHER_TYPE_SNOW;
+		break;
+	case RTE_CRYPTO_CIPHER_ZUC_EEA3:
+		cipherdata.algtype = PDCP_CIPHER_TYPE_ZUC;
+		break;
+	case RTE_CRYPTO_CIPHER_AES_CTR:
+		cipherdata.algtype = PDCP_CIPHER_TYPE_AES;
+		break;
+	case RTE_CRYPTO_CIPHER_NULL:
+		cipherdata.algtype = PDCP_CIPHER_TYPE_NULL;
+		break;
+	default:
+		DPAA2_SEC_ERR("Crypto: Undefined Cipher specified %u",
+			      session->cipher_alg);
+		goto out;
+	}
+
+	/* Auth is only applicable for control mode operation. */
+	if (pdcp_xform->domain == RTE_SECURITY_PDCP_MODE_CONTROL) {
+		if (pdcp_xform->sn_size != RTE_SECURITY_PDCP_SN_SIZE_5) {
+			DPAA2_SEC_ERR(
+				"PDCP Seq Num size should be 5 bits for cmode");
+			goto out;
+		}
+		if (auth_xform) {
+			session->auth_key.data = rte_zmalloc(NULL,
+							auth_xform->key.length,
+							RTE_CACHE_LINE_SIZE);
+			if (session->auth_key.data == NULL &&
+					auth_xform->key.length > 0) {
+				DPAA2_SEC_ERR("No Memory for auth key");
+				rte_free(session->cipher_key.data);
+				rte_free(priv);
+				return -ENOMEM;
+			}
+			session->auth_key.length = auth_xform->key.length;
+			memcpy(session->auth_key.data, auth_xform->key.data,
+					auth_xform->key.length);
+			session->auth_alg = auth_xform->algo;
+		} else {
+			session->auth_key.data = NULL;
+			session->auth_key.length = 0;
+			session->auth_alg = RTE_CRYPTO_AUTH_NULL;
+		}
+		authdata.key = (size_t)session->auth_key.data;
+		authdata.keylen = session->auth_key.length;
+		authdata.key_enc_flags = 0;
+		authdata.key_type = RTA_DATA_IMM;
+
+		switch (session->auth_alg) {
+		case RTE_CRYPTO_AUTH_SNOW3G_UIA2:
+			authdata.algtype = PDCP_AUTH_TYPE_SNOW;
+			break;
+		case RTE_CRYPTO_AUTH_ZUC_EIA3:
+			authdata.algtype = PDCP_AUTH_TYPE_ZUC;
+			break;
+		case RTE_CRYPTO_AUTH_AES_CMAC:
+			authdata.algtype = PDCP_AUTH_TYPE_AES;
+			break;
+		case RTE_CRYPTO_AUTH_NULL:
+			authdata.algtype = PDCP_AUTH_TYPE_NULL;
+			break;
+		default:
+			DPAA2_SEC_ERR("Crypto: Unsupported auth alg %u",
+				      session->auth_alg);
+			goto out;
+		}
+
+		if (session->dir == DIR_ENC)
+			bufsize = cnstr_shdsc_pdcp_c_plane_encap(
+					priv->flc_desc[0].desc, 1, 0,
+					pdcp_xform->hfn,
+					pdcp_xform->bearer,
+					pdcp_xform->pkt_dir,
+					pdcp_xform->hfn_threshold,
+					&cipherdata, &authdata,
+					0);
+		else if (session->dir == DIR_DEC)
+			bufsize = cnstr_shdsc_pdcp_c_plane_decap(
+					priv->flc_desc[0].desc, 1, 0,
+					pdcp_xform->hfn,
+					pdcp_xform->bearer,
+					pdcp_xform->pkt_dir,
+					pdcp_xform->hfn_threshold,
+					&cipherdata, &authdata,
+					0);
+	} else {
+		if (session->dir == DIR_ENC)
+			bufsize = cnstr_shdsc_pdcp_u_plane_encap(
+					priv->flc_desc[0].desc, 1, 0,
+					pdcp_xform->sn_size,
+					pdcp_xform->hfn,
+					pdcp_xform->bearer,
+					pdcp_xform->pkt_dir,
+					pdcp_xform->hfn_threshold,
+					&cipherdata, 0);
+		else if (session->dir == DIR_DEC)
+			bufsize = cnstr_shdsc_pdcp_u_plane_decap(
+					priv->flc_desc[0].desc, 1, 0,
+					pdcp_xform->sn_size,
+					pdcp_xform->hfn,
+					pdcp_xform->bearer,
+					pdcp_xform->pkt_dir,
+					pdcp_xform->hfn_threshold,
+					&cipherdata, 0);
+	}
+
+	if (bufsize < 0) {
+		DPAA2_SEC_ERR("Crypto: Invalid buffer length");
+		goto out;
+	}
+
+	/* Enable the stashing control bit */
+	DPAA2_SET_FLC_RSC(flc);
+	flc->word2_rflc_31_0 = lower_32_bits(
+			(size_t)&(((struct dpaa2_sec_qp *)
+			dev->data->queue_pairs[0])->rx_vq) | 0x14);
+	flc->word3_rflc_63_32 = upper_32_bits(
+			(size_t)&(((struct dpaa2_sec_qp *)
+			dev->data->queue_pairs[0])->rx_vq));
+
+	flc->word1_sdl = (uint8_t)bufsize;
+
+	/* Set EWS bit i.e. enable write-safe */
+	DPAA2_SET_FLC_EWS(flc);
+	/* Set BS = 1 i.e reuse input buffers as output buffers */
+	DPAA2_SET_FLC_REUSE_BS(flc);
+	/* Set FF = 10; reuse input buffers if they provide sufficient space */
+	DPAA2_SET_FLC_REUSE_FF(flc);
+
+	session->ctxt = priv;
+
+	return 0;
+out:
+	rte_free(session->auth_key.data);
+	rte_free(session->cipher_key.data);
+	rte_free(priv);
+	return -1;
+}
+
 static int
 dpaa2_sec_security_session_create(void *dev,
 				  struct rte_security_session_conf *conf,
@@ -2563,6 +2792,10 @@ dpaa2_sec_security_session_create(void *dev,
 		break;
 	case RTE_SECURITY_PROTOCOL_MACSEC:
 		return -ENOTSUP;
+	case RTE_SECURITY_PROTOCOL_PDCP:
+		ret = dpaa2_sec_set_pdcp_session(cdev, conf,
+				sess_private_data);
+		break;
 	default:
 		return -EINVAL;
 	}
diff --git a/drivers/crypto/dpaa2_sec/dpaa2_sec_priv.h b/drivers/crypto/dpaa2_sec/dpaa2_sec_priv.h
index d015be1e9..907374346 100644
--- a/drivers/crypto/dpaa2_sec/dpaa2_sec_priv.h
+++ b/drivers/crypto/dpaa2_sec/dpaa2_sec_priv.h
@@ -390,6 +390,162 @@ static const struct rte_cryptodev_capabilities dpaa2_sec_capabilities[] = {
 	RTE_CRYPTODEV_END_OF_CAPABILITIES_LIST()
 };
 
+static const struct rte_cryptodev_capabilities dpaa2_pdcp_capabilities[] = {
+	{	/* SNOW 3G (UIA2) */
+		.op = RTE_CRYPTO_OP_TYPE_SYMMETRIC,
+		{.sym = {
+			.xform_type = RTE_CRYPTO_SYM_XFORM_AUTH,
+			{.auth = {
+				.algo = RTE_CRYPTO_AUTH_SNOW3G_UIA2,
+				.block_size = 16,
+				.key_size = {
+					.min = 16,
+					.max = 16,
+					.increment = 0
+				},
+				.digest_size = {
+					.min = 4,
+					.max = 4,
+					.increment = 0
+				},
+				.iv_size = {
+					.min = 16,
+					.max = 16,
+					.increment = 0
+				}
+			}, }
+		}, }
+	},
+	{	/* SNOW 3G (UEA2) */
+		.op = RTE_CRYPTO_OP_TYPE_SYMMETRIC,
+		{.sym = {
+			.xform_type = RTE_CRYPTO_SYM_XFORM_CIPHER,
+			{.cipher = {
+				.algo = RTE_CRYPTO_CIPHER_SNOW3G_UEA2,
+				.block_size = 16,
+				.key_size = {
+					.min = 16,
+					.max = 16,
+					.increment = 0
+				},
+				.iv_size = {
+					.min = 16,
+					.max = 16,
+					.increment = 0
+				}
+			}, }
+		}, }
+	},
+	{	/* AES CTR */
+		.op = RTE_CRYPTO_OP_TYPE_SYMMETRIC,
+		{.sym = {
+			.xform_type = RTE_CRYPTO_SYM_XFORM_CIPHER,
+			{.cipher = {
+				.algo = RTE_CRYPTO_CIPHER_AES_CTR,
+				.block_size = 16,
+				.key_size = {
+					.min = 16,
+					.max = 32,
+					.increment = 8
+				},
+				.iv_size = {
+					.min = 16,
+					.max = 16,
+					.increment = 0
+				}
+			}, }
+		}, }
+	},
+	{	/* NULL (AUTH) */
+		.op = RTE_CRYPTO_OP_TYPE_SYMMETRIC,
+		{.sym = {
+			.xform_type = RTE_CRYPTO_SYM_XFORM_AUTH,
+			{.auth = {
+				.algo = RTE_CRYPTO_AUTH_NULL,
+				.block_size = 1,
+				.key_size = {
+					.min = 0,
+					.max = 0,
+					.increment = 0
+				},
+				.digest_size = {
+					.min = 0,
+					.max = 0,
+					.increment = 0
+				},
+				.iv_size = { 0 }
+			}, },
+		}, },
+	},
+	{	/* NULL (CIPHER) */
+		.op = RTE_CRYPTO_OP_TYPE_SYMMETRIC,
+		{.sym = {
+			.xform_type = RTE_CRYPTO_SYM_XFORM_CIPHER,
+			{.cipher = {
+				.algo = RTE_CRYPTO_CIPHER_NULL,
+				.block_size = 1,
+				.key_size = {
+					.min = 0,
+					.max = 0,
+					.increment = 0
+				},
+				.iv_size = {
+					.min = 0,
+					.max = 0,
+					.increment = 0
+				}
+			}, },
+		}, }
+	},
+	{	/* ZUC (EEA3) */
+		.op = RTE_CRYPTO_OP_TYPE_SYMMETRIC,
+		{.sym = {
+			.xform_type = RTE_CRYPTO_SYM_XFORM_CIPHER,
+			{.cipher = {
+				.algo = RTE_CRYPTO_CIPHER_ZUC_EEA3,
+				.block_size = 16,
+				.key_size = {
+					.min = 16,
+					.max = 16,
+					.increment = 0
+				},
+				.iv_size = {
+					.min = 16,
+					.max = 16,
+					.increment = 0
+				}
+			}, }
+		}, }
+	},
+	{	/* ZUC (EIA3) */
+		.op = RTE_CRYPTO_OP_TYPE_SYMMETRIC,
+		{.sym = {
+			.xform_type = RTE_CRYPTO_SYM_XFORM_AUTH,
+			{.auth = {
+				.algo = RTE_CRYPTO_AUTH_ZUC_EIA3,
+				.block_size = 16,
+				.key_size = {
+					.min = 16,
+					.max = 16,
+					.increment = 0
+				},
+				.digest_size = {
+					.min = 4,
+					.max = 4,
+					.increment = 0
+				},
+				.iv_size = {
+					.min = 16,
+					.max = 16,
+					.increment = 0
+				}
+			}, }
+		}, }
+	},
+
+	RTE_CRYPTODEV_END_OF_CAPABILITIES_LIST()
+};
+
 static const struct rte_security_capability dpaa2_sec_security_cap[] = {
 	{ /* IPsec Lookaside Protocol offload ESP Transport Egress */
 		.action = RTE_SECURITY_ACTION_TYPE_LOOKASIDE_PROTOCOL,
@@ -413,6 +569,22 @@ static const struct rte_security_capability dpaa2_sec_security_cap[] = {
 		},
 		.crypto_capabilities = dpaa2_sec_capabilities
 	},
+	{ /* PDCP Lookaside Protocol offload Data */
+		.action = RTE_SECURITY_ACTION_TYPE_LOOKASIDE_PROTOCOL,
+		.protocol = RTE_SECURITY_PROTOCOL_PDCP,
+		.pdcp = {
+			.domain = RTE_SECURITY_PDCP_MODE_DATA,
+		},
+		.crypto_capabilities = dpaa2_pdcp_capabilities
+	},
+	{ /* PDCP Lookaside Protocol offload Control */
+		.action = RTE_SECURITY_ACTION_TYPE_LOOKASIDE_PROTOCOL,
+		.protocol = RTE_SECURITY_PROTOCOL_PDCP,
+		.pdcp = {
+			.domain = RTE_SECURITY_PDCP_MODE_CONTROL,
+		},
+		.crypto_capabilities = dpaa2_pdcp_capabilities
+	},
 	{
 		.action = RTE_SECURITY_ACTION_TYPE_NONE
 	}
-- 
2.17.1

^ permalink raw reply	[flat|nested] 41+ messages in thread

* Re: [dpdk-dev] [PATCH 1/3] security: support pdcp protocol
  2018-10-05 12:05     ` Akhil Goyal
@ 2018-10-07  9:02       ` Joseph, Anoob
  2018-10-08  9:49         ` Akhil Goyal
  0 siblings, 1 reply; 41+ messages in thread
From: Joseph, Anoob @ 2018-10-07  9:02 UTC (permalink / raw)
  To: Akhil Goyal
  Cc: dev, Declan Doherty, Pablo de Lara, Radu Nicolau, Jerin Jacob,
	Narayana Prasad, Verma, Shally, Vidya Sagar Velumuri

Hi Akhil,

Please see inline.

Thanks,
Anoob
On 05-10-2018 17:35, Akhil Goyal wrote:
> External Email
>
> On 9/6/2018 9:45 AM, Joseph, Anoob wrote:
>
>> Hi Akhil,
>
> Hi Anoob,
>
> Thanks for the comments.
>
>> Please see inline.
>> Thanks,
>> Anoob
>> On 28-08-2018 18:31, akhil.goyal@nxp.com wrote:
>>> External Email
>>> From: Akhil Goyal <akhil.goyal@nxp.com>
>>> Signed-off-by: Hemant Agrawal <hemant.agrawal@nxp.com>
>>> Signed-off-by: Akhil Goyal <akhil.goyal@nxp.com>
>>> ---
>>>    doc/guides/prog_guide/rte_security.rst | 90 
>>> ++++++++++++++++++++++++--
>>>    lib/librte_security/rte_security.c     |  4 ++
>>>    lib/librte_security/rte_security.h     | 62 ++++++++++++++++++
>>>    3 files changed, 149 insertions(+), 7 deletions(-)
>>> diff --git a/doc/guides/prog_guide/rte_security.rst 
>>> b/doc/guides/prog_guide/rte_security.rst
>>> index 0812abe77..412fff016 100644
>>> --- a/doc/guides/prog_guide/rte_security.rst
>>> +++ b/doc/guides/prog_guide/rte_security.rst
>>> @@ -10,8 +10,8 @@ The security library provides a framework for 
>>> management and provisioning
>>>    of security protocol operations offloaded to hardware based 
>>> devices. The
>>>    library defines generic APIs to create and free security sessions 
>>> which can
>>>    support full protocol offload as well as inline crypto operation 
>>> with
>>> -NIC or crypto devices. The framework currently only supports the 
>>> IPSec protocol
>>> -and associated operations, other protocols will be added in future.
>>> +NIC or crypto devices. The framework currently only supports the 
>>> IPSec and PDCP
>>> +protocol and associated operations, other protocols will be added 
>>> in future.
>>>    Design Principles
>>>    -----------------
>>> @@ -253,6 +253,46 @@ for any protocol header addition.
>>>            +--------|--------+
>>>                     V
>>> +PDCP Flow Diagram
>>> +~~~~~~~~~~~~~~~~~
>>> +
>>> +.. code-block:: c
>>> +
>>> +        Transmitting PDCP Entity          Receiving PDCP Entity
>>> +                  |                                   ^
>>> +                  | +-----------|-----------+
>>> +                  V                       | In order delivery and |
>>> +        +---------|----------+            | Duplicate detection   |
>>> +        | Sequence Numbering |            |  (Data Plane only)    |
>>> +        +---------|----------+ +-----------|-----------+
>>> +                  |                                   |
>>> +        +---------|----------+ +-----------|----------+
>>> +        | Header Compression*|            | Header Decompression*|
>>> +        | (Data-Plane only)  |            |   (Data Plane only)  |
>>> +        +---------|----------+ +-----------|----------+
>>> +                  |                                   |
>>> +        +---------|-----------+ +-----------|----------+
>>> +        | Integrity Protection|           |Integrity Verification|
>>> +        | (Control Plane only)|           | (Control Plane only) |
>>> +        +---------|-----------+ +-----------|----------+
>>> +        +---------|-----------+ +----------|----------+
>>> +        |     Ciphering       |            | Deciphering     |
>>> +        +---------|-----------+ +----------|----------+
>>> +        +---------|-----------+ +----------|----------+
>>> +        |   Add PDCP header   |            | Remove PDCP Header  |
>>> +        +---------|-----------+ +----------|----------+
>>> +                  |                                   |
>>> +                  +----------------->>----------------+
>>> +
>> [Anoob] Which PDCP specification revision is this based on? In the 5G
>> specification, even data-plane may undergo integrity protection.
>
> This patchset is based on LTE-PDCP - 3GPP TS 36.323 v15.1.0 (2018-09).
> 5G changes are not added in this patchset. It will be added in future.
>
>>> +.. note::
>>> +
>>> +    * Header Compression and decompression are not supported 
>>> currently.
>>> +
>>> +Just like IPSec, in case of PDCP also header addition/deletion, 
>>> cipher/
>>> +de-cipher, integrity protection/verification is done based on the 
>>> action
>>> +type chosen.
>>> +
>>>    Device Features and Capabilities
>>>    ---------------------------------
>>> @@ -271,7 +311,7 @@ structure in the *DPDK API Reference*.
>>>    Each driver (crypto or ethernet) defines its own private array of 
>>> capabilities
>>>    for the operations it supports. Below is an example of the 
>>> capabilities for a
>>> -PMD which supports the IPSec protocol.
>>> +PMD which supports the IPSec and PDCP protocol.
>>>    .. code-block:: c
>>> @@ -298,6 +338,22 @@ PMD which supports the IPSec protocol.
>>>                    },
>>>                    .crypto_capabilities = pmd_capabilities
>>>            },
>>> +        { /* PDCP Lookaside Protocol offload Data Plane */
>>> +                .action = RTE_SECURITY_ACTION_TYPE_LOOKASIDE_PROTOCOL,
>>> +                .protocol = RTE_SECURITY_PROTOCOL_PDCP,
>>> +                .pdcp = {
>>> +                        .domain = RTE_SECURITY_PDCP_MODE_DATA,
>>> +                },
>>> +                .crypto_capabilities = pmd_capabilities
>>> +        },
>>> +        { /* PDCP Lookaside Protocol offload Control */
>>> +                .action = RTE_SECURITY_ACTION_TYPE_LOOKASIDE_PROTOCOL,
>>> +                .protocol = RTE_SECURITY_PROTOCOL_PDCP,
>>> +                .pdcp = {
>>> +                        .domain = RTE_SECURITY_PDCP_MODE_CONTROL,
>>> +                },
>>> +                .crypto_capabilities = pmd_capabilities
>>> +        },
>>>            {
>>>                    .action = RTE_SECURITY_ACTION_TYPE_NONE
>>>            }
>>> @@ -429,6 +485,7 @@ Security Session configuration structure is 
>>> defined as ``rte_security_session_co
>>>            union {
>>>                    struct rte_security_ipsec_xform ipsec;
>>>                    struct rte_security_macsec_xform macsec;
>>> +                struct rte_security_pdcp_xform pdcp;
>>>            };
>>>            /**< Configuration parameters for security session */
>>>            struct rte_crypto_sym_xform *crypto_xform;
>>> @@ -463,15 +520,17 @@ The ``rte_security_session_protocol`` is 
>>> defined as
>>>    .. code-block:: c
>>>        enum rte_security_session_protocol {
>>> -        RTE_SECURITY_PROTOCOL_IPSEC,
>>> +        RTE_SECURITY_PROTOCOL_IPSEC = 1,
>>>            /**< IPsec Protocol */
>>>            RTE_SECURITY_PROTOCOL_MACSEC,
>>>            /**< MACSec Protocol */
>>> +        RTE_SECURITY_PROTOCOL_PDCP,
>>> +        /**< PDCP Protocol */
>>>        };
>>> -Currently the library defines configuration parameters for IPSec 
>>> only. For other
>>> -protocols like MACSec, structures and enums are defined as place 
>>> holders which
>>> -will be updated in the future.
>>> +Currently the library defines configuration parameters for IPSec 
>>> and PDCP only.
>>> +For other protocols like MACSec, structures and enums are defined 
>>> as place holders
>>> +which will be updated in the future.
>>>    IPsec related configuration parameters are defined in 
>>> ``rte_security_ipsec_xform``
>>> @@ -494,6 +553,23 @@ IPsec related configuration parameters are 
>>> defined in ``rte_security_ipsec_xform
>>>            /**< Tunnel parameters, NULL for transport mode */
>>>        };
>>> +PDCP related configuration parameters are defined in 
>>> ``rte_security_pdcp_xform``
>>> +
>>> +.. code-block:: c
>>> +
>>> +    struct rte_security_pdcp_xform {
>>> +        int8_t bearer; /**< PDCP bearer ID */
>>> +        enum rte_security_pdcp_domain domain;
>>> +        /** < PDCP mode of operation: Control or data */
>>> +        enum rte_security_pdcp_direction pkt_dir;
>>> +        /**< PDCP Frame Direction 0:UL 1:DL */
>>> +        enum rte_security_pdcp_sn_size sn_size;
>>> +        /**< Sequence number size, 5/7/12/15 */
>>> +        int8_t hfn_ovd; /**< Overwrite HFN per operation */
>>> +        uint32_t hfn;  /**< Hyper Frame Number */
>>> +        uint32_t hfn_threshold;        /**< HFN Threashold for key 
>>> renegotiation */
>>> +    };
>>> +
>> [Anoob] PDCP packet ordering should be both a capability and a setting.
>> HFN will be incremented overtime and starts at 0. So why is it part of
>> the xform?
>
> The Security accelerators may assume packet in order. Latest PDCP TS
> suggest to do de-Ciphering before re-Ordering the Rx PDCP PDUs. In this
> situation, the accelerator may use wrong HFN value. The PDCP application
> can provide the appropriate HFN value along with PDU to the security
> accelerator.
>
So what is the expectation with regards to ordering? Would PDCP know the 
order or is it unaware of the order?
If implementation of this Spec knows the order of packets(which is 
implied by the "In order delivery and Duplicate detection
Sequence Numbering" statement in the PDCP flow diagram), then there 
should be no need to override the
HFN. If the implementation does not know the order of packets, then the 
flow diagram should be corrected.
Also, is implementation expected to support ordered delivery and 
duplicate detection. Perhaps it should be
a capability or 2.

>> Also the hfn_ovd is per operation. So why is it part of xform? Is it a
>> boolean value? If so, where does the HFN for each operation come from?
>
> The HFN Override is a boolean. If this is set, the Accelerator shall use
> the HFN value provided by the PDCP Application to construct the IV for
> deciphering instead of deriving it from the state variables. I will
> remove this from the patch as of now, we need to define an appropriate
> way to pass the per operation HFN for each packet.
>
>>>    Security API
>>>    ~~~~~~~~~~~~
>>> diff --git a/lib/librte_security/rte_security.c 
>>> b/lib/librte_security/rte_security.c
>>> index 1954960a5..c6355de95 100644
>>> --- a/lib/librte_security/rte_security.c
>>> +++ b/lib/librte_security/rte_security.c
>>> @@ -131,6 +131,10 @@ rte_security_capability_get(struct 
>>> rte_security_ctx *instance,
>>> capability->ipsec.direction ==
>>> idx->ipsec.direction)
>>>                                           return capability;
>>> +                       } else if (idx->protocol == 
>>> RTE_SECURITY_PROTOCOL_PDCP) {
>>> +                               if (capability->pdcp.domain ==
>>> + idx->pdcp.domain)
>>> +                                       return capability;
>>>                           }
>>>                   }
>>>           }
>>> diff --git a/lib/librte_security/rte_security.h 
>>> b/lib/librte_security/rte_security.h
>>> index b0d1b97ee..e625bc656 100644
>>> --- a/lib/librte_security/rte_security.h
>>> +++ b/lib/librte_security/rte_security.h
>>> @@ -206,6 +206,52 @@ struct rte_security_macsec_xform {
>>>           int dummy;
>>>    };
>>> +/**
>>> + * PDCP Mode of session
>>> + */
>>> +enum rte_security_pdcp_domain {
>>> +       RTE_SECURITY_PDCP_MODE_CONTROL, /**< PDCP control plane */
>>> +       RTE_SECURITY_PDCP_MODE_DATA,    /**< PDCP data plane */
>>> +};
>>> +
>>> +/** PDCP Frame direction */
>>> +enum rte_security_pdcp_direction {
>>> +       RTE_SECURITY_PDCP_UPLINK,       /**< Uplink */
>>> +       RTE_SECURITY_PDCP_DOWNLINK,     /**< Downlink */
>>> +};
>>> +
>>> +/**
>>> + * PDCP Sequence Number Size selectors
>>> + * @PDCP_SN_SIZE_5: 5bit sequence number
>>> + * @PDCP_SN_SIZE_7: 7bit sequence number
>>> + * @PDCP_SN_SIZE_12: 12bit sequence number
>>> + * @PDCP_SN_SIZE_15: 15bit sequence number
>>> + */
>>> +enum rte_security_pdcp_sn_size {
>>> +       RTE_SECURITY_PDCP_SN_SIZE_5 = 5,
>>> +       RTE_SECURITY_PDCP_SN_SIZE_7 = 7,
>>> +       RTE_SECURITY_PDCP_SN_SIZE_12 = 12,
>>> +       RTE_SECURITY_PDCP_SN_SIZE_15 = 15
>>> +};
>> [Anoob] SN size 18 is also possible
> Will add this.
>
>
> -Akhil

^ permalink raw reply	[flat|nested] 41+ messages in thread

* Re: [dpdk-dev] [PATCH 1/3] security: support pdcp protocol
  2018-10-07  9:02       ` Joseph, Anoob
@ 2018-10-08  9:49         ` Akhil Goyal
  2018-10-09 11:38           ` Joseph, Anoob
  0 siblings, 1 reply; 41+ messages in thread
From: Akhil Goyal @ 2018-10-08  9:49 UTC (permalink / raw)
  To: Joseph, Anoob
  Cc: dev, Declan Doherty, Pablo de Lara, Radu Nicolau, Jerin Jacob,
	Narayana Prasad, Verma, Shally, Vidya Sagar Velumuri

Hi Anoob,
>>>> @@ -494,6 +553,23 @@ IPsec related configuration parameters are 
>>>> defined in ``rte_security_ipsec_xform
>>>>            /**< Tunnel parameters, NULL for transport mode */
>>>>        };
>>>> +PDCP related configuration parameters are defined in 
>>>> ``rte_security_pdcp_xform``
>>>> +
>>>> +.. code-block:: c
>>>> +
>>>> +    struct rte_security_pdcp_xform {
>>>> +        int8_t bearer; /**< PDCP bearer ID */
>>>> +        enum rte_security_pdcp_domain domain;
>>>> +        /** < PDCP mode of operation: Control or data */
>>>> +        enum rte_security_pdcp_direction pkt_dir;
>>>> +        /**< PDCP Frame Direction 0:UL 1:DL */
>>>> +        enum rte_security_pdcp_sn_size sn_size;
>>>> +        /**< Sequence number size, 5/7/12/15 */
>>>> +        int8_t hfn_ovd; /**< Overwrite HFN per operation */
>>>> +        uint32_t hfn;  /**< Hyper Frame Number */
>>>> +        uint32_t hfn_threshold;        /**< HFN Threashold for key 
>>>> renegotiation */
>>>> +    };
>>>> +
>>> [Anoob] PDCP packet ordering should be both a capability and a setting.
>>> HFN will be incremented overtime and starts at 0. So why is it part of
>>> the xform?
>>
>> The Security accelerators may assume packet in order. Latest PDCP TS
>> suggest to do de-Ciphering before re-Ordering the Rx PDCP PDUs. In this
>> situation, the accelerator may use wrong HFN value. The PDCP application
>> can provide the appropriate HFN value along with PDU to the security
>> accelerator.
>>
> So what is the expectation with regards to ordering? Would PDCP know 
> the order or is it unaware of the order?
> If implementation of this Spec knows the order of packets(which is 
> implied by the "In order delivery and Duplicate detection
> Sequence Numbering" statement in the PDCP flow diagram), then there 
> should be no need to override the
> HFN. If the implementation does not know the order of packets, then 
> the flow diagram should be corrected.
> Also, is implementation expected to support ordered delivery and 
> duplicate detection. Perhaps it should be
> a capability or 2.
This patchset is basically talking about full protocol offload with look 
aside accelerators.
And when we are talking about full protocol offload, all protocol 
related stuff like ordering, headers etc.
needs to be handled by the HW/driver.
So the expectation is driver/HW should be able to perform in order 
delivery and detect duplicates.
If somebody have support for PDCP in the hardware, we can add 
capabilities as per the specific requirements.
In v2/v3 I have removed the hfn_override. Will add it later when it will 
be supported.


Thanks,
Akhil

^ permalink raw reply	[flat|nested] 41+ messages in thread

* Re: [dpdk-dev] [PATCH 1/3] security: support pdcp protocol
  2018-10-08  9:49         ` Akhil Goyal
@ 2018-10-09 11:38           ` Joseph, Anoob
  2018-10-15 13:03             ` Akhil Goyal
  0 siblings, 1 reply; 41+ messages in thread
From: Joseph, Anoob @ 2018-10-09 11:38 UTC (permalink / raw)
  To: Akhil Goyal
  Cc: dev, Declan Doherty, Pablo de Lara, Radu Nicolau, Jerin Jacob,
	Narayana Prasad, Verma, Shally, Vidya Sagar Velumuri

Hi Akhil,

Please see inline.

Thanks,
Anoob
On 08-10-2018 15:19, Akhil Goyal wrote:
> External Email
>
> Hi Anoob,
>>>>> @@ -494,6 +553,23 @@ IPsec related configuration parameters are
>>>>> defined in ``rte_security_ipsec_xform
>>>>>            /**< Tunnel parameters, NULL for transport mode */
>>>>>        };
>>>>> +PDCP related configuration parameters are defined in
>>>>> ``rte_security_pdcp_xform``
>>>>> +
>>>>> +.. code-block:: c
>>>>> +
>>>>> +    struct rte_security_pdcp_xform {
>>>>> +        int8_t bearer; /**< PDCP bearer ID */
>>>>> +        enum rte_security_pdcp_domain domain;
>>>>> +        /** < PDCP mode of operation: Control or data */
>>>>> +        enum rte_security_pdcp_direction pkt_dir;
>>>>> +        /**< PDCP Frame Direction 0:UL 1:DL */
>>>>> +        enum rte_security_pdcp_sn_size sn_size;
>>>>> +        /**< Sequence number size, 5/7/12/15 */
>>>>> +        int8_t hfn_ovd; /**< Overwrite HFN per operation */
>>>>> +        uint32_t hfn;  /**< Hyper Frame Number */
>>>>> +        uint32_t hfn_threshold;        /**< HFN Threashold for key
>>>>> renegotiation */
>>>>> +    };
>>>>> +
>>>> [Anoob] PDCP packet ordering should be both a capability and a 
>>>> setting.
>>>> HFN will be incremented overtime and starts at 0. So why is it part of
>>>> the xform?
>>>
>>> The Security accelerators may assume packet in order. Latest PDCP TS
>>> suggest to do de-Ciphering before re-Ordering the Rx PDCP PDUs. In this
>>> situation, the accelerator may use wrong HFN value. The PDCP 
>>> application
>>> can provide the appropriate HFN value along with PDU to the security
>>> accelerator.
>>>
>> So what is the expectation with regards to ordering? Would PDCP know
>> the order or is it unaware of the order?
>> If implementation of this Spec knows the order of packets(which is
>> implied by the "In order delivery and Duplicate detection
>> Sequence Numbering" statement in the PDCP flow diagram), then there
>> should be no need to override the
>> HFN. If the implementation does not know the order of packets, then
>> the flow diagram should be corrected.
>> Also, is implementation expected to support ordered delivery and
>> duplicate detection. Perhaps it should be
>> a capability or 2.
> This patchset is basically talking about full protocol offload with look
> aside accelerators.
> And when we are talking about full protocol offload, all protocol
> related stuff like ordering, headers etc.
> needs to be handled by the HW/driver.
> So the expectation is driver/HW should be able to perform in order
> delivery and detect duplicates.
How will errors in these situations be reported to the application - if 
packets are not in order or if a duplicate is detected - how should 
driver report it?
Is the driver/HW expected to correct the order OR is the behaviour 
limited to detection of out-of-order? In order to correct the order, the 
driver/HW will need to accumulate packets. Is that really the 
expectation of this specification
> If somebody have support for PDCP in the hardware, we can add
> capabilities as per the specific requirements.
> In v2/v3 I have removed the hfn_override. Will add it later when it will
> be supported.
>
>
> Thanks,
> Akhil

^ permalink raw reply	[flat|nested] 41+ messages in thread

* [dpdk-dev] [PATCH v4 0/3] security: support for pdcp
  2018-10-05 13:53   ` [dpdk-dev] [PATCH v3 0/3] security: support for pdcp akhil.goyal
                       ` (2 preceding siblings ...)
  2018-10-05 13:53     ` [dpdk-dev] [PATCH v3 3/3] crypto/dpaa2_sec: support pdcp offload akhil.goyal
@ 2018-10-15 12:53     ` Akhil Goyal
  2018-10-15 12:53       ` [dpdk-dev] [PATCH v4 1/3] security: support pdcp protocol Akhil Goyal
                         ` (3 more replies)
  3 siblings, 4 replies; 41+ messages in thread
From: Akhil Goyal @ 2018-10-15 12:53 UTC (permalink / raw)
  To: dev
  Cc: pablo.de.lara.guarch, radu.nicolau, jerin.jacob,
	narayanaprasad.athreya, Shally.Verma, Anoob.Joseph,
	Vidya.Velumuri, Hemant Agrawal, Akhil Goyal

From: Akhil Goyal <akhil.goyal@nxp.com>

Security library currently only has support for IPSec protocol.
This patchset defines structures for pdcp protocol in rte_security
and provide a sample driver implementation for lookaside protocol
offload to support PDCP.

changes in v4:
- added capability and setting for packet ordering and duplicate
detection.
- some fixes in driver.

changes in v3:
removed checkpatch warnings.

changes in v2:
- removed hfn override. Will be added later when it is supported
- added seq number size = 18bits
- coding style issues corrected in pdcp.h
- updated documentation for specifying the 3GPP specification reference
- removed some duplicate code in dpaa2_sec_dpseci.c


Akhil Goyal (3):
  security: support pdcp protocol
  crypto/dpaa2_sec: add sample pdcp descriptor apis
  crypto/dpaa2_sec: support pdcp offload

 doc/guides/prog_guide/rte_security.rst      |  107 +-
 drivers/crypto/dpaa2_sec/dpaa2_sec_dpseci.c |  257 ++
 drivers/crypto/dpaa2_sec/dpaa2_sec_priv.h   |  208 +-
 drivers/crypto/dpaa2_sec/hw/desc.h          |    2 +-
 drivers/crypto/dpaa2_sec/hw/desc/pdcp.h     | 2796 +++++++++++++++++++
 lib/librte_security/rte_security.c          |    4 +
 lib/librte_security/rte_security.h          |   91 +
 7 files changed, 3449 insertions(+), 16 deletions(-)
 create mode 100644 drivers/crypto/dpaa2_sec/hw/desc/pdcp.h

-- 
2.17.1

^ permalink raw reply	[flat|nested] 41+ messages in thread

* [dpdk-dev] [PATCH v4 1/3] security: support pdcp protocol
  2018-10-15 12:53     ` [dpdk-dev] [PATCH v4 0/3] security: support for pdcp Akhil Goyal
@ 2018-10-15 12:53       ` Akhil Goyal
  2018-10-16  6:40         ` Joseph
  2018-10-15 12:53       ` [dpdk-dev] [PATCH v4 2/3] crypto/dpaa2_sec: add sample pdcp descriptor apis Akhil Goyal
                         ` (2 subsequent siblings)
  3 siblings, 1 reply; 41+ messages in thread
From: Akhil Goyal @ 2018-10-15 12:53 UTC (permalink / raw)
  To: dev
  Cc: pablo.de.lara.guarch, radu.nicolau, jerin.jacob,
	narayanaprasad.athreya, Shally.Verma, Anoob.Joseph,
	Vidya.Velumuri, Hemant Agrawal, Akhil Goyal

From: Akhil Goyal <akhil.goyal@nxp.com>

Packet Data Convergence Protocol (PDCP) is added in rte_security
for 3GPP TS 36.323 for LTE.

The patchset provide the structure definitions for configuring the
PDCP sessions and relevant documentation is added.

Signed-off-by: Hemant Agrawal <hemant.agrawal@nxp.com>
Signed-off-by: Akhil Goyal <akhil.goyal@nxp.com>
---
 doc/guides/prog_guide/rte_security.rst | 107 +++++++++++++++++++++++--
 lib/librte_security/rte_security.c     |   4 +
 lib/librte_security/rte_security.h     |  91 +++++++++++++++++++++
 3 files changed, 195 insertions(+), 7 deletions(-)

diff --git a/doc/guides/prog_guide/rte_security.rst b/doc/guides/prog_guide/rte_security.rst
index 0812abe77..f09e7c8bb 100644
--- a/doc/guides/prog_guide/rte_security.rst
+++ b/doc/guides/prog_guide/rte_security.rst
@@ -10,8 +10,8 @@ The security library provides a framework for management and provisioning
 of security protocol operations offloaded to hardware based devices. The
 library defines generic APIs to create and free security sessions which can
 support full protocol offload as well as inline crypto operation with
-NIC or crypto devices. The framework currently only supports the IPSec protocol
-and associated operations, other protocols will be added in future.
+NIC or crypto devices. The framework currently only supports the IPSec and PDCP
+protocol and associated operations, other protocols will be added in future.
 
 Design Principles
 -----------------
@@ -253,6 +253,49 @@ for any protocol header addition.
         +--------|--------+
                  V
 
+PDCP Flow Diagram
+~~~~~~~~~~~~~~~~~
+
+Based on 3GPP TS 36.323 Evolved Universal Terrestrial Radio Access (E-UTRA);
+Packet Data Convergence Protocol (PDCP) specification
+
+.. code-block:: c
+
+        Transmitting PDCP Entity          Receiving PDCP Entity
+                  |                                   ^
+                  |                       +-----------|-----------+
+                  V                       | In order delivery and |
+        +---------|----------+            | Duplicate detection   |
+        | Sequence Numbering |            |  (Data Plane only)    |
+        +---------|----------+            +-----------|-----------+
+                  |                                   |
+        +---------|----------+            +-----------|----------+
+        | Header Compression*|            | Header Decompression*|
+        | (Data-Plane only)  |            |   (Data Plane only)  |
+        +---------|----------+            +-----------|----------+
+                  |                                   |
+        +---------|-----------+           +-----------|----------+
+        | Integrity Protection|           |Integrity Verification|
+        | (Control Plane only)|           | (Control Plane only) |
+        +---------|-----------+           +-----------|----------+
+        +---------|-----------+            +----------|----------+
+        |     Ciphering       |            |     Deciphering     |
+        +---------|-----------+            +----------|----------+
+        +---------|-----------+            +----------|----------+
+        |   Add PDCP header   |            | Remove PDCP Header  |
+        +---------|-----------+            +----------|----------+
+                  |                                   |
+                  +----------------->>----------------+
+
+
+.. note::
+
+    * Header Compression and decompression are not supported currently.
+
+Just like IPSec, in case of PDCP also header addition/deletion, cipher/
+de-cipher, integrity protection/verification is done based on the action
+type chosen.
+
 Device Features and Capabilities
 ---------------------------------
 
@@ -271,7 +314,7 @@ structure in the *DPDK API Reference*.
 
 Each driver (crypto or ethernet) defines its own private array of capabilities
 for the operations it supports. Below is an example of the capabilities for a
-PMD which supports the IPSec protocol.
+PMD which supports the IPSec and PDCP protocol.
 
 .. code-block:: c
 
@@ -298,6 +341,24 @@ PMD which supports the IPSec protocol.
                 },
                 .crypto_capabilities = pmd_capabilities
         },
+        { /* PDCP Lookaside Protocol offload Data Plane */
+                .action = RTE_SECURITY_ACTION_TYPE_LOOKASIDE_PROTOCOL,
+                .protocol = RTE_SECURITY_PROTOCOL_PDCP,
+                .pdcp = {
+                        .domain = RTE_SECURITY_PDCP_MODE_DATA,
+                        .capa_flags = 0
+                },
+                .crypto_capabilities = pmd_capabilities
+        },
+        { /* PDCP Lookaside Protocol offload Control */
+                .action = RTE_SECURITY_ACTION_TYPE_LOOKASIDE_PROTOCOL,
+                .protocol = RTE_SECURITY_PROTOCOL_PDCP,
+                .pdcp = {
+                        .domain = RTE_SECURITY_PDCP_MODE_CONTROL,
+                        .capa_flags = 0
+                },
+                .crypto_capabilities = pmd_capabilities
+        },
         {
                 .action = RTE_SECURITY_ACTION_TYPE_NONE
         }
@@ -429,6 +490,7 @@ Security Session configuration structure is defined as ``rte_security_session_co
         union {
                 struct rte_security_ipsec_xform ipsec;
                 struct rte_security_macsec_xform macsec;
+                struct rte_security_pdcp_xform pdcp;
         };
         /**< Configuration parameters for security session */
         struct rte_crypto_sym_xform *crypto_xform;
@@ -463,15 +525,17 @@ The ``rte_security_session_protocol`` is defined as
 .. code-block:: c
 
     enum rte_security_session_protocol {
-        RTE_SECURITY_PROTOCOL_IPSEC,
+        RTE_SECURITY_PROTOCOL_IPSEC = 1,
         /**< IPsec Protocol */
         RTE_SECURITY_PROTOCOL_MACSEC,
         /**< MACSec Protocol */
+        RTE_SECURITY_PROTOCOL_PDCP,
+        /**< PDCP Protocol */
     };
 
-Currently the library defines configuration parameters for IPSec only. For other
-protocols like MACSec, structures and enums are defined as place holders which
-will be updated in the future.
+Currently the library defines configuration parameters for IPSec and PDCP only.
+For other protocols like MACSec, structures and enums are defined as place holders
+which will be updated in the future.
 
 IPsec related configuration parameters are defined in ``rte_security_ipsec_xform``
 
@@ -494,6 +558,35 @@ IPsec related configuration parameters are defined in ``rte_security_ipsec_xform
         /**< Tunnel parameters, NULL for transport mode */
     };
 
+PDCP related configuration parameters are defined in ``rte_security_pdcp_xform``
+
+.. code-block:: c
+
+    struct rte_security_pdcp_xform {
+        int8_t bearer;	/**< PDCP bearer ID */
+        /**< PDCP mode of operation: Control or data */
+        uint8_t en_ordering;
+        /**< Enable in order delivery, this field shall be set only if
+         * driver/HW is capable. See RTE_SECURITY_PDCP_ORDERING_CAP.
+         */
+        uint8_t remove_duplicates;
+        /**< Notify driver/HW to detect and remove duplicate packets.
+         * This field should be set only when driver/hw is capable.
+         * See RTE_SECURITY_PDCP_DUP_DETECT_CAP.
+         */
+        enum rte_security_pdcp_domain domain;
+        /**< PDCP Frame Direction 0:UL 1:DL */
+        enum rte_security_pdcp_direction pkt_dir;
+        /**< Sequence number size, 5/7/12/15/18 */
+        enum rte_security_pdcp_sn_size sn_size;
+        /**< Starting Hyper Frame Number to be used together with the SN
+         * from the PDCP frames
+         */
+        uint32_t hfn;
+        /**< HFN Threashold for key renegotiation */
+        uint32_t hfn_threshold;
+    };
+
 
 Security API
 ~~~~~~~~~~~~
diff --git a/lib/librte_security/rte_security.c b/lib/librte_security/rte_security.c
index 1954960a5..c6355de95 100644
--- a/lib/librte_security/rte_security.c
+++ b/lib/librte_security/rte_security.c
@@ -131,6 +131,10 @@ rte_security_capability_get(struct rte_security_ctx *instance,
 					capability->ipsec.direction ==
 							idx->ipsec.direction)
 					return capability;
+			} else if (idx->protocol == RTE_SECURITY_PROTOCOL_PDCP) {
+				if (capability->pdcp.domain ==
+							idx->pdcp.domain)
+					return capability;
 			}
 		}
 	}
diff --git a/lib/librte_security/rte_security.h b/lib/librte_security/rte_security.h
index b0d1b97ee..1d20530f4 100644
--- a/lib/librte_security/rte_security.h
+++ b/lib/librte_security/rte_security.h
@@ -206,6 +206,66 @@ struct rte_security_macsec_xform {
 	int dummy;
 };
 
+/**
+ * PDCP Mode of session
+ */
+enum rte_security_pdcp_domain {
+	RTE_SECURITY_PDCP_MODE_CONTROL,	/**< PDCP control plane */
+	RTE_SECURITY_PDCP_MODE_DATA,	/**< PDCP data plane */
+};
+
+/** PDCP Frame direction */
+enum rte_security_pdcp_direction {
+	RTE_SECURITY_PDCP_UPLINK,	/**< Uplink */
+	RTE_SECURITY_PDCP_DOWNLINK,	/**< Downlink */
+};
+
+/**
+ * PDCP Sequence Number Size selectors
+ * @PDCP_SN_SIZE_5: 5bit sequence number
+ * @PDCP_SN_SIZE_7: 7bit sequence number
+ * @PDCP_SN_SIZE_12: 12bit sequence number
+ * @PDCP_SN_SIZE_15: 15bit sequence number
+ * @PDCP_SN_SIZE_18: 18bit sequence number
+ */
+enum rte_security_pdcp_sn_size {
+	RTE_SECURITY_PDCP_SN_SIZE_5 = 5,
+	RTE_SECURITY_PDCP_SN_SIZE_7 = 7,
+	RTE_SECURITY_PDCP_SN_SIZE_12 = 12,
+	RTE_SECURITY_PDCP_SN_SIZE_15 = 15,
+	RTE_SECURITY_PDCP_SN_SIZE_18 = 18
+};
+
+/**
+ * PDCP security association configuration data.
+ *
+ * This structure contains data required to create a PDCP security session.
+ */
+struct rte_security_pdcp_xform {
+	int8_t bearer;	/**< PDCP bearer ID */
+	/**< PDCP mode of operation: Control or data */
+	uint8_t en_ordering;
+	/**< Enable in order delivery, this field shall be set only if
+	 * driver/HW is capable. See RTE_SECURITY_PDCP_ORDERING_CAP.
+	 */
+	uint8_t remove_duplicates;
+	/**< Notify driver/HW to detect and remove duplicate packets.
+	 * This field should be set only when driver/hw is capable.
+	 * See RTE_SECURITY_PDCP_DUP_DETECT_CAP.
+	 */
+	enum rte_security_pdcp_domain domain;
+	/**< PDCP Frame Direction 0:UL 1:DL */
+	enum rte_security_pdcp_direction pkt_dir;
+	/**< Sequence number size, 5/7/12/15/18 */
+	enum rte_security_pdcp_sn_size sn_size;
+	/**< Starting Hyper Frame Number to be used together with the SN
+	 * from the PDCP frames
+	 */
+	uint32_t hfn;
+	/**< HFN Threshold for key renegotiation */
+	uint32_t hfn_threshold;
+};
+
 /**
  * Security session action type.
  */
@@ -232,6 +292,8 @@ enum rte_security_session_protocol {
 	/**< IPsec Protocol */
 	RTE_SECURITY_PROTOCOL_MACSEC,
 	/**< MACSec Protocol */
+	RTE_SECURITY_PROTOCOL_PDCP,
+	/**< PDCP Protocol */
 };
 
 /**
@@ -246,6 +308,7 @@ struct rte_security_session_conf {
 	union {
 		struct rte_security_ipsec_xform ipsec;
 		struct rte_security_macsec_xform macsec;
+		struct rte_security_pdcp_xform pdcp;
 	};
 	/**< Configuration parameters for security session */
 	struct rte_crypto_sym_xform *crypto_xform;
@@ -413,6 +476,10 @@ struct rte_security_ipsec_stats {
 
 };
 
+struct rte_security_pdcp_stats {
+	uint64_t reserved;
+};
+
 struct rte_security_stats {
 	enum rte_security_session_protocol protocol;
 	/**< Security protocol to be configured */
@@ -421,6 +488,7 @@ struct rte_security_stats {
 	union {
 		struct rte_security_macsec_stats macsec;
 		struct rte_security_ipsec_stats ipsec;
+		struct rte_security_pdcp_stats pdcp;
 	};
 };
 
@@ -465,6 +533,13 @@ struct rte_security_capability {
 			int dummy;
 		} macsec;
 		/**< MACsec capability */
+		struct {
+			enum rte_security_pdcp_domain domain;
+			/** < PDCP mode of operation: Control or data */
+			uint32_t capa_flags;
+			/** < Capabilitity flags, see RTE_SECURITY_PDCP_* */
+		} pdcp;
+		/**< PDCP capability */
 	};
 
 	const struct rte_cryptodev_capabilities *crypto_capabilities;
@@ -474,6 +549,19 @@ struct rte_security_capability {
 	/**< Device offload flags */
 };
 
+/**< Underlying Hardware/driver which support PDCP may or may not support
+ * packet ordering. Set RTE_SECURITY_PDCP_ORDERING_CAP if it support.
+ * If it is not set, driver/HW assumes packets received are in order
+ * and it will be application's responsibility to maintain ordering.
+ */
+#define RTE_SECURITY_PDCP_ORDERING_CAP		0x00000001
+
+/**< Underlying Hardware/driver which support PDCP may or may not detect
+ * duplicate packet. Set RTE_SECURITY_PDCP_DUP_DETECT_CAP if it support.
+ * If it is not set, driver/HW assumes there is no duplicate packet received.
+ */
+#define RTE_SECURITY_PDCP_DUP_DETECT_CAP	0x00000002
+
 #define RTE_SECURITY_TX_OLOAD_NEED_MDATA	0x00000001
 /**< HW needs metadata update, see rte_security_set_pkt_metadata().
  */
@@ -506,6 +594,9 @@ struct rte_security_capability_idx {
 			enum rte_security_ipsec_sa_mode mode;
 			enum rte_security_ipsec_sa_direction direction;
 		} ipsec;
+		struct {
+			enum rte_security_pdcp_domain domain;
+		} pdcp;
 	};
 };
 
-- 
2.17.1

^ permalink raw reply	[flat|nested] 41+ messages in thread

* [dpdk-dev] [PATCH v4 2/3] crypto/dpaa2_sec: add sample pdcp descriptor apis
  2018-10-15 12:53     ` [dpdk-dev] [PATCH v4 0/3] security: support for pdcp Akhil Goyal
  2018-10-15 12:53       ` [dpdk-dev] [PATCH v4 1/3] security: support pdcp protocol Akhil Goyal
@ 2018-10-15 12:53       ` Akhil Goyal
  2018-10-15 12:53       ` [dpdk-dev] [PATCH v4 3/3] crypto/dpaa2_sec: support pdcp offload Akhil Goyal
  2018-10-16 10:38       ` [dpdk-dev] [PATCH v5 0/3] security: support for pdcp Akhil Goyal
  3 siblings, 0 replies; 41+ messages in thread
From: Akhil Goyal @ 2018-10-15 12:53 UTC (permalink / raw)
  To: dev
  Cc: pablo.de.lara.guarch, radu.nicolau, jerin.jacob,
	narayanaprasad.athreya, Shally.Verma, Anoob.Joseph,
	Vidya.Velumuri, Hemant Agrawal, Akhil Goyal

From: Akhil Goyal <akhil.goyal@nxp.com>

DPAA2 SEC platform can support look aside protocol
offload for PDCP protocol.

The relevant APIs for configuring the hardware for PDCP
is added for various modes and crypto algorithms.

Signed-off-by: Hemant Agrawal <hemant.agrawal@nxp.com>
Signed-off-by: Horia Geanta Neag <horia.geanta@nxp.com>
Signed-off-by: Alex Porosanu <alexandru.porosanu@nxp.com>
Signed-off-by: Akhil Goyal <akhil.goyal@nxp.com>
---
 drivers/crypto/dpaa2_sec/hw/desc.h      |    2 +-
 drivers/crypto/dpaa2_sec/hw/desc/pdcp.h | 2796 +++++++++++++++++++++++
 2 files changed, 2797 insertions(+), 1 deletion(-)
 create mode 100644 drivers/crypto/dpaa2_sec/hw/desc/pdcp.h

diff --git a/drivers/crypto/dpaa2_sec/hw/desc.h b/drivers/crypto/dpaa2_sec/hw/desc.h
index ca94ea3ff..5d99dd8af 100644
--- a/drivers/crypto/dpaa2_sec/hw/desc.h
+++ b/drivers/crypto/dpaa2_sec/hw/desc.h
@@ -868,7 +868,7 @@
 #define OP_PCL_LTE_MIXED_AUTH_SHIFT	0
 #define OP_PCL_LTE_MIXED_AUTH_MASK	(3 << OP_PCL_LTE_MIXED_AUTH_SHIFT)
 #define OP_PCL_LTE_MIXED_ENC_SHIFT	8
-#define OP_PCL_LTE_MIXED_ENC_MASK	(3 < OP_PCL_LTE_MIXED_ENC_SHIFT)
+#define OP_PCL_LTE_MIXED_ENC_MASK	(3 << OP_PCL_LTE_MIXED_ENC_SHIFT)
 #define OP_PCL_LTE_MIXED_AUTH_NULL	(OP_PCL_LTE_NULL << \
 					 OP_PCL_LTE_MIXED_AUTH_SHIFT)
 #define OP_PCL_LTE_MIXED_AUTH_SNOW	(OP_PCL_LTE_SNOW << \
diff --git a/drivers/crypto/dpaa2_sec/hw/desc/pdcp.h b/drivers/crypto/dpaa2_sec/hw/desc/pdcp.h
new file mode 100644
index 000000000..719ef605f
--- /dev/null
+++ b/drivers/crypto/dpaa2_sec/hw/desc/pdcp.h
@@ -0,0 +1,2796 @@
+/*
+ * Copyright 2008-2013 Freescale Semiconductor, Inc.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause or GPL-2.0+
+ */
+
+#ifndef __DESC_PDCP_H__
+#define __DESC_PDCP_H__
+
+#include "hw/rta.h"
+#include "common.h"
+
+/**
+ * DOC: PDCP Shared Descriptor Constructors
+ *
+ * Shared descriptors for PDCP protocol.
+ */
+
+/**
+ * PDCP_NULL_MAX_FRAME_LEN - The maximum frame frame length that is supported by
+ *                           PDCP NULL protocol.
+ */
+#define PDCP_NULL_MAX_FRAME_LEN		0x00002FFF
+
+/**
+ * PDCP_MAC_I_LEN - The length of the MAC-I for PDCP protocol operation
+ */
+#define PDCP_MAC_I_LEN			0x00000004
+
+/**
+ * PDCP_MAX_FRAME_LEN_STATUS - The status returned in FD status/command field in
+ *                             case the input frame is larger than
+ *                             PDCP_NULL_MAX_FRAME_LEN.
+ */
+#define PDCP_MAX_FRAME_LEN_STATUS	0xF1
+
+/**
+ * PDCP_C_PLANE_SN_MASK - This mask is used in the PDCP descriptors for
+ *                        extracting the sequence number (SN) from the PDCP
+ *                        Control Plane header. For PDCP Control Plane, the SN
+ *                        is constant (5 bits) as opposed to PDCP Data Plane
+ *                        (7/12/15 bits).
+ */
+#define PDCP_C_PLANE_SN_MASK		0x1F000000
+#define PDCP_C_PLANE_SN_MASK_BE		0x0000001F
+
+/**
+ * PDCP_U_PLANE_15BIT_SN_MASK - This mask is used in the PDCP descriptors for
+ *                              extracting the sequence number (SN) from the
+ *                              PDCP User Plane header. For PDCP Control Plane,
+ *                              the SN is constant (5 bits) as opposed to PDCP
+ *                              Data Plane (7/12/15 bits).
+ */
+#define PDCP_U_PLANE_15BIT_SN_MASK	0xFF7F0000
+#define PDCP_U_PLANE_15BIT_SN_MASK_BE	0x00007FFF
+
+/**
+ * PDCP_BEARER_MASK - This mask is used masking out the bearer for PDCP
+ *                    processing with SNOW f9 in LTE.
+ *
+ * The value on which this mask is applied is formatted as below:
+ *     Count-C (32 bit) | Bearer (5 bit) | Direction (1 bit) | 0 (26 bits)
+ *
+ * Applying this mask is done for creating the upper 64 bits of the IV needed
+ * for SNOW f9.
+ *
+ * The lower 32 bits of the mask are used for masking the direction for AES
+ * CMAC IV.
+ */
+#define PDCP_BEARER_MASK		0x00000004FFFFFFFFull
+#define PDCP_BEARER_MASK_BE		0xFFFFFFFF04000000ull
+
+/**
+ * PDCP_DIR_MASK - This mask is used masking out the direction for PDCP
+ *                 processing with SNOW f9 in LTE.
+ *
+ * The value on which this mask is applied is formatted as below:
+ *     Bearer (5 bit) | Direction (1 bit) | 0 (26 bits)
+ *
+ * Applying this mask is done for creating the lower 32 bits of the IV needed
+ * for SNOW f9.
+ *
+ * The upper 32 bits of the mask are used for masking the direction for AES
+ * CMAC IV.
+ */
+#define PDCP_DIR_MASK			0x00000000000000F8ull
+#define PDCP_DIR_MASK_BE			0xF800000000000000ull
+
+/**
+ * PDCP_NULL_INT_MAC_I_VAL - The value of the PDCP PDU MAC-I in case NULL
+ *                           integrity is used.
+ */
+
+#define PDCP_NULL_INT_MAC_I_VAL		0x00000000
+
+/**
+ * PDCP_NULL_INT_ICV_CHECK_FAILED_STATUS - The status used to report ICV check
+ *                                         failed in case of NULL integrity
+ *                                         Control Plane processing.
+ */
+#define PDCP_NULL_INT_ICV_CHECK_FAILED_STATUS	0x0A
+/**
+ * PDCP_DPOVRD_HFN_OV_EN - Value to be used in the FD status/cmd field to
+ *                         indicate the HFN override mechanism is active for the
+ *                         frame.
+ */
+#define PDCP_DPOVRD_HFN_OV_EN		0x80000000
+
+/**
+ * PDCP_P4080REV2_HFN_OV_BUFLEN - The length in bytes of the supplementary space
+ *                                that must be provided by the user at the
+ *                                beginning of the input frame buffer for
+ *                                P4080 REV 2.
+ *
+ * The format of the frame buffer is the following:
+ *
+ *  |<---PDCP_P4080REV2_HFN_OV_BUFLEN-->|
+ * //===================================||============||==============\\
+ * || PDCP_DPOVRD_HFN_OV_EN | HFN value || PDCP Header|| PDCP Payload ||
+ * \\===================================||============||==============//
+ *
+ * If HFN override mechanism is not desired, then the MSB of the first 4 bytes
+ * must be set to 0b.
+ */
+#define PDCP_P4080REV2_HFN_OV_BUFLEN	4
+
+/**
+ * enum cipher_type_pdcp - Type selectors for cipher types in PDCP protocol OP
+ *                         instructions.
+ * @PDCP_CIPHER_TYPE_NULL: NULL
+ * @PDCP_CIPHER_TYPE_SNOW: SNOW F8
+ * @PDCP_CIPHER_TYPE_AES: AES
+ * @PDCP_CIPHER_TYPE_ZUC: ZUCE
+ * @PDCP_CIPHER_TYPE_INVALID: invalid option
+ */
+enum cipher_type_pdcp {
+	PDCP_CIPHER_TYPE_NULL,
+	PDCP_CIPHER_TYPE_SNOW,
+	PDCP_CIPHER_TYPE_AES,
+	PDCP_CIPHER_TYPE_ZUC,
+	PDCP_CIPHER_TYPE_INVALID
+};
+
+/**
+ * enum auth_type_pdcp - Type selectors for integrity types in PDCP protocol OP
+ *                       instructions.
+ * @PDCP_AUTH_TYPE_NULL: NULL
+ * @PDCP_AUTH_TYPE_SNOW: SNOW F9
+ * @PDCP_AUTH_TYPE_AES: AES CMAC
+ * @PDCP_AUTH_TYPE_ZUC: ZUCA
+ * @PDCP_AUTH_TYPE_INVALID: invalid option
+ */
+enum auth_type_pdcp {
+	PDCP_AUTH_TYPE_NULL,
+	PDCP_AUTH_TYPE_SNOW,
+	PDCP_AUTH_TYPE_AES,
+	PDCP_AUTH_TYPE_ZUC,
+	PDCP_AUTH_TYPE_INVALID
+};
+
+/**
+ * enum pdcp_dir - Type selectors for direction for PDCP protocol
+ * @PDCP_DIR_UPLINK: uplink direction
+ * @PDCP_DIR_DOWNLINK: downlink direction
+ * @PDCP_DIR_INVALID: invalid option
+ */
+enum pdcp_dir {
+	PDCP_DIR_UPLINK = 0,
+	PDCP_DIR_DOWNLINK = 1,
+	PDCP_DIR_INVALID
+};
+
+/**
+ * enum pdcp_plane - PDCP domain selectors
+ * @PDCP_CONTROL_PLANE: Control Plane
+ * @PDCP_DATA_PLANE: Data Plane
+ * @PDCP_SHORT_MAC: Short MAC
+ */
+enum pdcp_plane {
+	PDCP_CONTROL_PLANE,
+	PDCP_DATA_PLANE,
+	PDCP_SHORT_MAC
+};
+
+/**
+ * enum pdcp_sn_size - Sequence Number Size selectors for PDCP protocol
+ * @PDCP_SN_SIZE_5: 5bit sequence number
+ * @PDCP_SN_SIZE_7: 7bit sequence number
+ * @PDCP_SN_SIZE_12: 12bit sequence number
+ * @PDCP_SN_SIZE_15: 15bit sequence number
+ * @PDCP_SN_SIZE_18: 18bit sequence number
+ */
+enum pdcp_sn_size {
+	PDCP_SN_SIZE_5 = 5,
+	PDCP_SN_SIZE_7 = 7,
+	PDCP_SN_SIZE_12 = 12,
+	PDCP_SN_SIZE_15 = 15
+};
+
+/*
+ * PDCP Control Plane Protocol Data Blocks
+ */
+#define PDCP_C_PLANE_PDB_HFN_SHIFT		5
+#define PDCP_C_PLANE_PDB_BEARER_SHIFT		27
+#define PDCP_C_PLANE_PDB_DIR_SHIFT		26
+#define PDCP_C_PLANE_PDB_HFN_THR_SHIFT		5
+
+#define PDCP_U_PLANE_PDB_OPT_SHORT_SN		0x2
+#define PDCP_U_PLANE_PDB_OPT_15B_SN		0x4
+#define PDCP_U_PLANE_PDB_SHORT_SN_HFN_SHIFT	7
+#define PDCP_U_PLANE_PDB_LONG_SN_HFN_SHIFT	12
+#define PDCP_U_PLANE_PDB_15BIT_SN_HFN_SHIFT	15
+#define PDCP_U_PLANE_PDB_BEARER_SHIFT		27
+#define PDCP_U_PLANE_PDB_DIR_SHIFT		26
+#define PDCP_U_PLANE_PDB_SHORT_SN_HFN_THR_SHIFT	7
+#define PDCP_U_PLANE_PDB_LONG_SN_HFN_THR_SHIFT	12
+#define PDCP_U_PLANE_PDB_15BIT_SN_HFN_THR_SHIFT	15
+
+struct pdcp_pdb {
+	union {
+		uint32_t opt;
+		uint32_t rsvd;
+	} opt_res;
+	uint32_t hfn_res;	/* HyperFrame number,(27, 25 or 21 bits),
+				 * left aligned & right-padded with zeros.
+				 */
+	uint32_t bearer_dir_res;/* Bearer(5 bits), packet direction (1 bit),
+				 * left aligned & right-padded with zeros.
+				 */
+	uint32_t hfn_thr_res;	/* HyperFrame number threshold (27, 25 or 21
+				 * bits), left aligned & right-padded with
+				 * zeros.
+				 */
+};
+
+/*
+ * PDCP internal PDB types
+ */
+enum pdb_type_e {
+	PDCP_PDB_TYPE_NO_PDB,
+	PDCP_PDB_TYPE_FULL_PDB,
+	PDCP_PDB_TYPE_REDUCED_PDB,
+	PDCP_PDB_TYPE_INVALID
+};
+
+/*
+ * Function for appending the portion of a PDCP Control Plane shared descriptor
+ * which performs NULL encryption and integrity (i.e. copies the input frame
+ * to the output frame, appending 32 bits of zeros at the end (MAC-I for
+ * NULL integrity).
+ */
+static inline int
+pdcp_insert_cplane_null_op(struct program *p,
+			   bool swap __maybe_unused,
+			   struct alginfo *cipherdata __maybe_unused,
+			   struct alginfo *authdata __maybe_unused,
+			   unsigned int dir,
+			   unsigned char era_2_sw_hfn_ovrd __maybe_unused)
+{
+	LABEL(local_offset);
+	REFERENCE(move_cmd_read_descbuf);
+	REFERENCE(move_cmd_write_descbuf);
+
+	if (rta_sec_era > RTA_SEC_ERA_2) {
+		MATHB(p, SEQINSZ, ADD, ZERO, VSEQINSZ, 4, 0);
+		if (dir == OP_TYPE_ENCAP_PROTOCOL)
+			MATHB(p, SEQINSZ, ADD, PDCP_MAC_I_LEN, VSEQOUTSZ, 4,
+			      IMMED2);
+		else
+			MATHB(p, SEQINSZ, SUB, PDCP_MAC_I_LEN, VSEQOUTSZ, 4,
+			      IMMED2);
+	} else {
+		MATHB(p, SEQINSZ, ADD, ONE, VSEQINSZ, 4, 0);
+		MATHB(p, VSEQINSZ, SUB, ONE, VSEQINSZ, 4, 0);
+
+		if (dir == OP_TYPE_ENCAP_PROTOCOL) {
+			MATHB(p, SEQINSZ, ADD, PDCP_MAC_I_LEN, VSEQOUTSZ, 4,
+			      IMMED2);
+			MATHB(p, VSEQINSZ, SUB, ONE, MATH0, 4, 0);
+		} else {
+			MATHB(p, VSEQINSZ, SUB, PDCP_MAC_I_LEN, VSEQINSZ, 4,
+			      IMMED2);
+			MATHB(p, SEQINSZ, SUB, PDCP_MAC_I_LEN, VSEQOUTSZ, 4,
+			      IMMED2);
+			MATHB(p, VSEQOUTSZ, SUB, ONE, MATH0, 4, 0);
+		}
+
+		MATHB(p, MATH0, ADD, ONE, MATH0, 4, 0);
+
+		/*
+		 * Since MOVELEN is available only starting with
+		 * SEC ERA 3, use poor man's MOVELEN: create a MOVE
+		 * command dynamically by writing the length from M1 by
+		 * OR-ing the command in the M1 register and MOVE the
+		 * result into the descriptor buffer. Care must be taken
+		 * wrt. the location of the command because of SEC
+		 * pipelining. The actual MOVEs are written at the end
+		 * of the descriptor due to calculations needed on the
+		 * offset in the descriptor for the MOVE command.
+		 */
+		move_cmd_read_descbuf = MOVE(p, DESCBUF, 0, MATH0, 0, 6,
+					     IMMED);
+		move_cmd_write_descbuf = MOVE(p, MATH0, 0, DESCBUF, 0, 8,
+					      WAITCOMP | IMMED);
+	}
+	MATHB(p, VSEQINSZ, SUB, PDCP_NULL_MAX_FRAME_LEN, NONE, 4,
+	      IMMED2);
+	JUMP(p, PDCP_MAX_FRAME_LEN_STATUS, HALT_STATUS, ALL_FALSE, MATH_N);
+
+	if (rta_sec_era > RTA_SEC_ERA_2) {
+		if (dir == OP_TYPE_ENCAP_PROTOCOL)
+			MATHB(p, VSEQINSZ, ADD, ZERO, MATH0, 4, 0);
+		else
+			MATHB(p, VSEQOUTSZ, ADD, ZERO, MATH0, 4, 0);
+	}
+	SEQFIFOSTORE(p, MSG, 0, 0, VLF);
+	SEQFIFOLOAD(p, MSG1, 0, VLF | LAST1 | FLUSH1);
+
+	if (rta_sec_era > RTA_SEC_ERA_2) {
+		MOVE(p, AB1, 0, OFIFO, 0, MATH0, 0);
+	} else {
+		SET_LABEL(p, local_offset);
+
+		/* Shut off automatic Info FIFO entries */
+		LOAD(p, 0, DCTRL, LDOFF_DISABLE_AUTO_NFIFO, 0, IMMED);
+		/* Placeholder for MOVE command with length from M1 register */
+		MOVE(p, IFIFOAB1, 0, OFIFO, 0, 0, IMMED);
+		/* Enable automatic Info FIFO entries */
+		LOAD(p, 0, DCTRL, LDOFF_ENABLE_AUTO_NFIFO, 0, IMMED);
+	}
+
+	if (dir == OP_TYPE_ENCAP_PROTOCOL) {
+		MATHB(p, MATH1, XOR, MATH1, MATH0, 8, 0);
+		MOVE(p, MATH0, 0, OFIFO, 0, 4, IMMED);
+	}
+
+	if (rta_sec_era < RTA_SEC_ERA_3) {
+		PATCH_MOVE(p, move_cmd_read_descbuf, local_offset);
+		PATCH_MOVE(p, move_cmd_write_descbuf, local_offset);
+	}
+
+	return 0;
+}
+
+static inline int
+insert_copy_frame_op(struct program *p,
+		     struct alginfo *cipherdata __maybe_unused,
+		     unsigned int dir __maybe_unused)
+{
+	LABEL(local_offset);
+	REFERENCE(move_cmd_read_descbuf);
+	REFERENCE(move_cmd_write_descbuf);
+
+	if (rta_sec_era > RTA_SEC_ERA_2) {
+		MATHB(p, SEQINSZ, ADD, ZERO, VSEQINSZ,  4, 0);
+		MATHB(p, SEQINSZ, ADD, ZERO, VSEQOUTSZ,  4, 0);
+	} else {
+		MATHB(p, SEQINSZ, ADD, ONE, VSEQINSZ,  4, 0);
+		MATHB(p, VSEQINSZ, SUB, ONE, VSEQINSZ,  4, 0);
+		MATHB(p, SEQINSZ, ADD, ONE, VSEQOUTSZ,  4, 0);
+		MATHB(p, VSEQOUTSZ, SUB, ONE, VSEQOUTSZ,  4, 0);
+		MATHB(p, VSEQINSZ, SUB, ONE, MATH0,  4, 0);
+		MATHB(p, MATH0, ADD, ONE, MATH0,  4, 0);
+
+		/*
+		 * Since MOVELEN is available only starting with
+		 * SEC ERA 3, use poor man's MOVELEN: create a MOVE
+		 * command dynamically by writing the length from M1 by
+		 * OR-ing the command in the M1 register and MOVE the
+		 * result into the descriptor buffer. Care must be taken
+		 * wrt. the location of the command because of SEC
+		 * pipelining. The actual MOVEs are written at the end
+		 * of the descriptor due to calculations needed on the
+		 * offset in the descriptor for the MOVE command.
+		 */
+		move_cmd_read_descbuf = MOVE(p, DESCBUF, 0, MATH0, 0, 6,
+					     IMMED);
+		move_cmd_write_descbuf = MOVE(p, MATH0, 0, DESCBUF, 0, 8,
+					      WAITCOMP | IMMED);
+	}
+	MATHB(p, SEQINSZ, SUB, PDCP_NULL_MAX_FRAME_LEN, NONE,  4,
+	      IFB | IMMED2);
+	JUMP(p, PDCP_MAX_FRAME_LEN_STATUS, HALT_STATUS, ALL_FALSE, MATH_N);
+
+	if (rta_sec_era > RTA_SEC_ERA_2)
+		MATHB(p, VSEQINSZ, ADD, ZERO, MATH0,  4, 0);
+
+	SEQFIFOLOAD(p, MSG1, 0, VLF | LAST1 | FLUSH1);
+	if (rta_sec_era > RTA_SEC_ERA_2) {
+		MOVE(p, AB1, 0, OFIFO, 0, MATH0, 0);
+	} else {
+		SET_LABEL(p, local_offset);
+
+		/* Shut off automatic Info FIFO entries */
+		LOAD(p, 0, DCTRL, LDOFF_DISABLE_AUTO_NFIFO, 0, IMMED);
+
+		/* Placeholder for MOVE command with length from M0 register */
+		MOVE(p, IFIFOAB1, 0, OFIFO, 0, 0, IMMED);
+
+		/* Enable automatic Info FIFO entries */
+		LOAD(p, 0, DCTRL, LDOFF_ENABLE_AUTO_NFIFO, 0, IMMED);
+	}
+
+	SEQFIFOSTORE(p, MSG, 0, 0, VLF);
+
+	if (rta_sec_era < RTA_SEC_ERA_3) {
+		PATCH_MOVE(p, move_cmd_read_descbuf, local_offset);
+		PATCH_MOVE(p, move_cmd_write_descbuf, local_offset);
+	}
+	return 0;
+}
+
+static inline int
+pdcp_insert_cplane_int_only_op(struct program *p,
+			       bool swap __maybe_unused,
+			       struct alginfo *cipherdata __maybe_unused,
+			       struct alginfo *authdata, unsigned int dir,
+			       unsigned char era_2_sw_hfn_ovrd)
+{
+	LABEL(local_offset);
+	REFERENCE(move_cmd_read_descbuf);
+	REFERENCE(move_cmd_write_descbuf);
+
+	switch (authdata->algtype) {
+	case PDCP_AUTH_TYPE_SNOW:
+		/* Insert Auth Key */
+		KEY(p, KEY2, authdata->key_enc_flags, authdata->key,
+		    authdata->keylen, INLINE_KEY(authdata));
+		SEQLOAD(p, MATH0, 7, 1, 0);
+		JUMP(p, 1, LOCAL_JUMP, ALL_TRUE, CALM);
+
+		if (rta_sec_era > RTA_SEC_ERA_2 ||
+		    (rta_sec_era == RTA_SEC_ERA_2 &&
+				   era_2_sw_hfn_ovrd == 0)) {
+			SEQINPTR(p, 0, 1, RTO);
+		} else {
+			SEQINPTR(p, 0, 5, RTO);
+			SEQFIFOLOAD(p, SKIP, 4, 0);
+		}
+
+		if (swap == false) {
+			MATHB(p, MATH0, AND, PDCP_C_PLANE_SN_MASK, MATH1,  8,
+			      IFB | IMMED2);
+			MATHB(p, MATH1, SHLD, MATH1, MATH1,  8, 0);
+
+			MOVEB(p, DESCBUF, 8, MATH2, 0, 8, WAITCOMP | IMMED);
+
+			MATHB(p, MATH2, AND, PDCP_BEARER_MASK, MATH2, 8,
+			      IMMED2);
+			MOVEB(p, DESCBUF, 0x0C, MATH3, 0, 4, WAITCOMP | IMMED);
+			MATHB(p, MATH3, AND, PDCP_DIR_MASK, MATH3, 8, IMMED2);
+			MATHB(p, MATH1, OR, MATH2, MATH2, 8, 0);
+			MOVEB(p, MATH2, 0, CONTEXT2, 0, 0x0C, WAITCOMP | IMMED);
+		} else {
+			MATHB(p, MATH0, AND, PDCP_C_PLANE_SN_MASK_BE, MATH1,  8,
+			      IFB | IMMED2);
+			MATHB(p, MATH1, SHLD, MATH1, MATH1,  8, 0);
+
+			MOVE(p, DESCBUF, 8, MATH2, 0, 8, WAITCOMP | IMMED);
+			MATHB(p, MATH2, AND, PDCP_BEARER_MASK_BE, MATH2, 8,
+			      IMMED2);
+
+			MOVE(p, DESCBUF, 0x0C, MATH3, 0, 4, WAITCOMP | IMMED);
+			MATHB(p, MATH3, AND, PDCP_DIR_MASK_BE, MATH3, 8,
+			      IMMED2);
+			MATHB(p, MATH1, OR, MATH2, MATH2, 8, 0);
+			MOVE(p, MATH2, 0, CONTEXT2, 0, 0x0C, WAITCOMP | IMMED);
+		}
+
+		if (dir == OP_TYPE_DECAP_PROTOCOL) {
+			MATHB(p, SEQINSZ, SUB, PDCP_MAC_I_LEN, MATH1, 4,
+			      IMMED2);
+		} else {
+			if (rta_sec_era > RTA_SEC_ERA_2) {
+				MATHB(p, SEQINSZ, SUB, ZERO, MATH1, 4,
+				      0);
+			} else {
+				MATHB(p, SEQINSZ, ADD, ONE, MATH1, 4,
+				      0);
+				MATHB(p, MATH1, SUB, ONE, MATH1, 4,
+				      0);
+			}
+		}
+
+		if (rta_sec_era > RTA_SEC_ERA_2) {
+			MATHB(p, MATH1, SUB, ZERO, VSEQINSZ, 4, 0);
+			MATHB(p, MATH1, SUB, ZERO, VSEQOUTSZ, 4, 0);
+		} else {
+			MATHB(p, ZERO, ADD, MATH1, VSEQINSZ, 4, 0);
+			MATHB(p, ZERO, ADD, MATH1, VSEQOUTSZ, 4, 0);
+
+			/*
+			 * Since MOVELEN is available only starting with
+			 * SEC ERA 3, use poor man's MOVELEN: create a MOVE
+			 * command dynamically by writing the length from M1 by
+			 * OR-ing the command in the M1 register and MOVE the
+			 * result into the descriptor buffer. Care must be taken
+			 * wrt. the location of the command because of SEC
+			 * pipelining. The actual MOVEs are written at the end
+			 * of the descriptor due to calculations needed on the
+			 * offset in the descriptor for the MOVE command.
+			 */
+			move_cmd_read_descbuf = MOVE(p, DESCBUF, 0, MATH1, 0, 6,
+						     IMMED);
+			move_cmd_write_descbuf = MOVE(p, MATH1, 0, DESCBUF, 0,
+						      8, WAITCOMP | IMMED);
+		}
+
+		SEQFIFOSTORE(p, MSG, 0, 0, VLF);
+		ALG_OPERATION(p, OP_ALG_ALGSEL_SNOW_F9, OP_ALG_AAI_F9,
+			      OP_ALG_AS_INITFINAL,
+			      dir == OP_TYPE_ENCAP_PROTOCOL ?
+				     ICV_CHECK_DISABLE : ICV_CHECK_ENABLE,
+			      DIR_ENC);
+
+		if (rta_sec_era > RTA_SEC_ERA_2) {
+			SEQFIFOLOAD(p, MSGINSNOOP, 0,
+				    VLF | LAST1 | LAST2 | FLUSH1);
+			MOVE(p, AB1, 0, OFIFO, 0, MATH1, 0);
+		} else {
+			SEQFIFOLOAD(p, MSGINSNOOP, 0,
+				    VLF | LAST1 | LAST2 | FLUSH1);
+			SET_LABEL(p, local_offset);
+
+			/* Shut off automatic Info FIFO entries */
+			LOAD(p, 0, DCTRL, LDOFF_DISABLE_AUTO_NFIFO, 0, IMMED);
+			/*
+			 * Placeholder for MOVE command with length from M1
+			 * register
+			 */
+			MOVE(p, IFIFOAB1, 0, OFIFO, 0, 0, IMMED);
+			/* Enable automatic Info FIFO entries */
+			LOAD(p, 0, DCTRL, LDOFF_ENABLE_AUTO_NFIFO, 0, IMMED);
+		}
+
+		if (dir == OP_TYPE_DECAP_PROTOCOL)
+			SEQFIFOLOAD(p, ICV2, 4, LAST2);
+		else
+			SEQSTORE(p, CONTEXT2, 0, 4, 0);
+
+		break;
+
+	case PDCP_AUTH_TYPE_AES:
+		/* Insert Auth Key */
+		KEY(p, KEY1, authdata->key_enc_flags, authdata->key,
+		    authdata->keylen, INLINE_KEY(authdata));
+		SEQLOAD(p, MATH0, 7, 1, 0);
+		JUMP(p, 1, LOCAL_JUMP, ALL_TRUE, CALM);
+		if (rta_sec_era > RTA_SEC_ERA_2 ||
+		    (rta_sec_era == RTA_SEC_ERA_2 &&
+		     era_2_sw_hfn_ovrd == 0)) {
+			SEQINPTR(p, 0, 1, RTO);
+		} else {
+			SEQINPTR(p, 0, 5, RTO);
+			SEQFIFOLOAD(p, SKIP, 4, 0);
+		}
+
+		if (swap == false) {
+			MATHB(p, MATH0, AND, PDCP_C_PLANE_SN_MASK, MATH1, 8,
+			      IFB | IMMED2);
+			MATHB(p, MATH1, SHLD, MATH1, MATH1, 8, 0);
+
+			MOVEB(p, DESCBUF, 8, MATH2, 0, 8, WAITCOMP | IMMED);
+			MATHB(p, MATH1, OR, MATH2, MATH2, 8, 0);
+			MOVEB(p, MATH2, 0, IFIFOAB1, 0, 8, IMMED);
+		} else {
+			MATHB(p, MATH0, AND, PDCP_C_PLANE_SN_MASK_BE, MATH1, 8,
+			      IFB | IMMED2);
+			MATHB(p, MATH1, SHLD, MATH1, MATH1, 8, 0);
+
+			MOVE(p, DESCBUF, 8, MATH2, 0, 8, WAITCOMP | IMMED);
+			MATHB(p, MATH1, OR, MATH2, MATH2, 8, 0);
+			MOVE(p, MATH2, 0, IFIFOAB1, 0, 8, IMMED);
+		}
+
+		if (dir == OP_TYPE_DECAP_PROTOCOL) {
+			MATHB(p, SEQINSZ, SUB, PDCP_MAC_I_LEN, MATH1, 4,
+			      IMMED2);
+		} else {
+			if (rta_sec_era > RTA_SEC_ERA_2) {
+				MATHB(p, SEQINSZ, SUB, ZERO, MATH1, 4,
+				      0);
+			} else {
+				MATHB(p, SEQINSZ, ADD, ONE, MATH1, 4,
+				      0);
+				MATHB(p, MATH1, SUB, ONE, MATH1, 4,
+				      0);
+			}
+		}
+
+		if (rta_sec_era > RTA_SEC_ERA_2) {
+			MATHB(p, MATH1, SUB, ZERO, VSEQINSZ, 4, 0);
+			MATHB(p, MATH1, SUB, ZERO, VSEQOUTSZ, 4, 0);
+		} else {
+			MATHB(p, ZERO, ADD, MATH1, VSEQINSZ, 4, 0);
+			MATHB(p, ZERO, ADD, MATH1, VSEQOUTSZ, 4, 0);
+
+			/*
+			 * Since MOVELEN is available only starting with
+			 * SEC ERA 3, use poor man's MOVELEN: create a MOVE
+			 * command dynamically by writing the length from M1 by
+			 * OR-ing the command in the M1 register and MOVE the
+			 * result into the descriptor buffer. Care must be taken
+			 * wrt. the location of the command because of SEC
+			 * pipelining. The actual MOVEs are written at the end
+			 * of the descriptor due to calculations needed on the
+			 * offset in the descriptor for the MOVE command.
+			 */
+			move_cmd_read_descbuf = MOVE(p, DESCBUF, 0, MATH1, 0, 6,
+						     IMMED);
+			move_cmd_write_descbuf = MOVE(p, MATH1, 0, DESCBUF, 0,
+						      8, WAITCOMP | IMMED);
+		}
+		SEQFIFOSTORE(p, MSG, 0, 0, VLF);
+		ALG_OPERATION(p, OP_ALG_ALGSEL_AES,
+			      OP_ALG_AAI_CMAC,
+			      OP_ALG_AS_INITFINAL,
+			      dir == OP_TYPE_ENCAP_PROTOCOL ?
+				     ICV_CHECK_DISABLE : ICV_CHECK_ENABLE,
+			      DIR_ENC);
+
+		if (rta_sec_era > RTA_SEC_ERA_2) {
+			MOVE(p, AB2, 0, OFIFO, 0, MATH1, 0);
+			SEQFIFOLOAD(p, MSGINSNOOP, 0,
+				    VLF | LAST1 | LAST2 | FLUSH1);
+		} else {
+			SEQFIFOLOAD(p, MSGINSNOOP, 0,
+				    VLF | LAST1 | LAST2 | FLUSH1);
+			SET_LABEL(p, local_offset);
+
+			/* Shut off automatic Info FIFO entries */
+			LOAD(p, 0, DCTRL, LDOFF_DISABLE_AUTO_NFIFO, 0, IMMED);
+
+			/*
+			 * Placeholder for MOVE command with length from
+			 * M1 register
+			 */
+			MOVE(p, IFIFOAB2, 0, OFIFO, 0, 0, IMMED);
+
+			/* Enable automatic Info FIFO entries */
+			LOAD(p, 0, DCTRL, LDOFF_ENABLE_AUTO_NFIFO, 0, IMMED);
+		}
+
+		if (dir == OP_TYPE_DECAP_PROTOCOL)
+			SEQFIFOLOAD(p, ICV1, 4, LAST1 | FLUSH1);
+		else
+			SEQSTORE(p, CONTEXT1, 0, 4, 0);
+
+		break;
+
+	case PDCP_AUTH_TYPE_ZUC:
+		if (rta_sec_era < RTA_SEC_ERA_5) {
+			pr_err("Invalid era for selected algorithm\n");
+			return -ENOTSUP;
+		}
+		/* Insert Auth Key */
+		KEY(p, KEY2, authdata->key_enc_flags, authdata->key,
+		    authdata->keylen, INLINE_KEY(authdata));
+		SEQLOAD(p, MATH0, 7, 1, 0);
+		JUMP(p, 1, LOCAL_JUMP, ALL_TRUE, CALM);
+		SEQINPTR(p, 0, 1, RTO);
+		if (swap == false) {
+			MATHB(p, MATH0, AND, PDCP_C_PLANE_SN_MASK, MATH1, 8,
+			      IFB | IMMED2);
+			MATHB(p, MATH1, SHLD, MATH1, MATH1, 8, 0);
+
+			MOVEB(p, DESCBUF, 8, MATH2, 0, 8, WAITCOMP | IMMED);
+			MATHB(p, MATH1, OR, MATH2, MATH2, 8, 0);
+			MOVEB(p, MATH2, 0, CONTEXT2, 0, 8, IMMED);
+
+		} else {
+			MATHB(p, MATH0, AND, PDCP_C_PLANE_SN_MASK_BE, MATH1, 8,
+			      IFB | IMMED2);
+			MATHB(p, MATH1, SHLD, MATH1, MATH1, 8, 0);
+
+			MOVE(p, DESCBUF, 8, MATH2, 0, 8, WAITCOMP | IMMED);
+			MATHB(p, MATH1, OR, MATH2, MATH2, 8, 0);
+			MOVE(p, MATH2, 0, CONTEXT2, 0, 8, IMMED);
+		}
+		if (dir == OP_TYPE_DECAP_PROTOCOL)
+			MATHB(p, SEQINSZ, SUB, PDCP_MAC_I_LEN, MATH1, 4,
+			      IMMED2);
+		else
+			MATHB(p, SEQINSZ, SUB, ZERO, MATH1, 4, 0);
+
+		MATHB(p, MATH1, SUB, ZERO, VSEQINSZ, 4, 0);
+		MATHB(p, MATH1, SUB, ZERO, VSEQOUTSZ, 4, 0);
+		SEQFIFOSTORE(p, MSG, 0, 0, VLF);
+		ALG_OPERATION(p, OP_ALG_ALGSEL_ZUCA,
+			      OP_ALG_AAI_F9,
+			      OP_ALG_AS_INITFINAL,
+			      dir == OP_TYPE_ENCAP_PROTOCOL ?
+				     ICV_CHECK_DISABLE : ICV_CHECK_ENABLE,
+			      DIR_ENC);
+		SEQFIFOLOAD(p, MSGINSNOOP, 0, VLF | LAST1 | LAST2 | FLUSH1);
+		MOVE(p, AB1, 0, OFIFO, 0, MATH1, 0);
+
+		if (dir == OP_TYPE_DECAP_PROTOCOL)
+			SEQFIFOLOAD(p, ICV2, 4, LAST2);
+		else
+			SEQSTORE(p, CONTEXT2, 0, 4, 0);
+
+		break;
+
+	default:
+		pr_err("%s: Invalid integrity algorithm selected: %d\n",
+		       "pdcp_insert_cplane_int_only_op", authdata->algtype);
+		return -EINVAL;
+	}
+
+	if (rta_sec_era < RTA_SEC_ERA_3) {
+		PATCH_MOVE(p, move_cmd_read_descbuf, local_offset);
+		PATCH_MOVE(p, move_cmd_write_descbuf, local_offset);
+	}
+
+	return 0;
+}
+
+static inline int
+pdcp_insert_cplane_enc_only_op(struct program *p,
+			       bool swap __maybe_unused,
+			       struct alginfo *cipherdata,
+			       struct alginfo *authdata __maybe_unused,
+			       unsigned int dir,
+			       unsigned char era_2_sw_hfn_ovrd __maybe_unused)
+{
+	/* Insert Cipher Key */
+	KEY(p, KEY1, cipherdata->key_enc_flags, cipherdata->key,
+	    cipherdata->keylen, INLINE_KEY(cipherdata));
+
+	if (rta_sec_era >= RTA_SEC_ERA_8) {
+		PROTOCOL(p, dir, OP_PCLID_LTE_PDCP_CTRL_MIXED,
+				(uint16_t)cipherdata->algtype << 8);
+		return 0;
+	}
+
+	SEQLOAD(p, MATH0, 7, 1, 0);
+	JUMP(p, 1, LOCAL_JUMP, ALL_TRUE, CALM);
+	if (swap == false)
+		MATHB(p, MATH0, AND, PDCP_C_PLANE_SN_MASK, MATH1, 8,
+			IFB | IMMED2);
+	else
+		MATHB(p, MATH0, AND, PDCP_C_PLANE_SN_MASK_BE, MATH1, 8,
+			IFB | IMMED2);
+	SEQSTORE(p, MATH0, 7, 1, 0);
+	MATHB(p, MATH1, SHLD, MATH1, MATH1, 8, 0);
+	MOVE(p, DESCBUF, 8, MATH2, 0, 8, WAITCOMP | IMMED);
+	MATHB(p, MATH1, OR, MATH2, MATH2, 8, 0);
+
+	switch (cipherdata->algtype) {
+	case PDCP_CIPHER_TYPE_SNOW:
+		MOVE(p, MATH2, 0, CONTEXT1, 0, 8, WAITCOMP | IMMED);
+
+		if (rta_sec_era > RTA_SEC_ERA_2) {
+			MATHB(p, SEQINSZ, SUB, ZERO, VSEQINSZ, 4, 0);
+		} else {
+			MATHB(p, SEQINSZ, SUB, ONE, MATH1, 4, 0);
+			MATHB(p, MATH1, ADD, ONE, VSEQINSZ, 4, 0);
+		}
+
+		if (dir == OP_TYPE_ENCAP_PROTOCOL)
+			MATHB(p, SEQINSZ, ADD, PDCP_MAC_I_LEN, VSEQOUTSZ, 4,
+			      IMMED2);
+		else
+			MATHB(p, SEQINSZ, SUB, PDCP_MAC_I_LEN, VSEQOUTSZ, 4,
+			      IMMED2);
+		SEQFIFOSTORE(p, MSG, 0, 0, VLF | CONT);
+		ALG_OPERATION(p, OP_ALG_ALGSEL_SNOW_F8,
+			      OP_ALG_AAI_F8,
+			      OP_ALG_AS_INITFINAL, ICV_CHECK_DISABLE,
+			      dir == OP_TYPE_ENCAP_PROTOCOL ?
+					DIR_ENC : DIR_DEC);
+		break;
+
+	case PDCP_CIPHER_TYPE_AES:
+		MOVE(p, MATH2, 0, CONTEXT1, 0x10, 0x10, WAITCOMP | IMMED);
+
+		if (rta_sec_era > RTA_SEC_ERA_2) {
+			MATHB(p, SEQINSZ, SUB, ZERO, VSEQINSZ, 4, 0);
+		} else {
+			MATHB(p, SEQINSZ, SUB, ONE, MATH1, 4, 0);
+			MATHB(p, MATH1, ADD, ONE, VSEQINSZ, 4, 0);
+		}
+
+		if (dir == OP_TYPE_ENCAP_PROTOCOL)
+			MATHB(p, SEQINSZ, ADD, PDCP_MAC_I_LEN, VSEQOUTSZ, 4,
+			      IMMED2);
+		else
+			MATHB(p, SEQINSZ, SUB, PDCP_MAC_I_LEN, VSEQOUTSZ, 4,
+			      IMMED2);
+
+		SEQFIFOSTORE(p, MSG, 0, 0, VLF | CONT);
+		ALG_OPERATION(p, OP_ALG_ALGSEL_AES,
+			      OP_ALG_AAI_CTR,
+			      OP_ALG_AS_INITFINAL,
+			      ICV_CHECK_DISABLE,
+			      dir == OP_TYPE_ENCAP_PROTOCOL ?
+					DIR_ENC : DIR_DEC);
+		break;
+
+	case PDCP_CIPHER_TYPE_ZUC:
+		if (rta_sec_era < RTA_SEC_ERA_5) {
+			pr_err("Invalid era for selected algorithm\n");
+			return -ENOTSUP;
+		}
+
+		MOVE(p, MATH2, 0, CONTEXT1, 0, 0x08, IMMED);
+		MOVE(p, MATH2, 0, CONTEXT1, 0x08, 0x08, WAITCOMP | IMMED);
+		MATHB(p, SEQINSZ, SUB, ZERO, VSEQINSZ, 4, 0);
+		if (dir == OP_TYPE_ENCAP_PROTOCOL)
+			MATHB(p, SEQINSZ, ADD, PDCP_MAC_I_LEN, VSEQOUTSZ, 4,
+			      IMMED2);
+		else
+			MATHB(p, SEQINSZ, SUB, PDCP_MAC_I_LEN, VSEQOUTSZ, 4,
+			      IMMED2);
+
+		SEQFIFOSTORE(p, MSG, 0, 0, VLF | CONT);
+		ALG_OPERATION(p, OP_ALG_ALGSEL_ZUCE,
+			      OP_ALG_AAI_F8,
+			      OP_ALG_AS_INITFINAL,
+			      ICV_CHECK_DISABLE,
+			      dir == OP_TYPE_ENCAP_PROTOCOL ?
+					DIR_ENC : DIR_DEC);
+		break;
+
+	default:
+		pr_err("%s: Invalid encrypt algorithm selected: %d\n",
+		       "pdcp_insert_cplane_enc_only_op", cipherdata->algtype);
+		return -EINVAL;
+	}
+
+	if (dir == OP_TYPE_ENCAP_PROTOCOL) {
+		SEQFIFOLOAD(p, MSG1, 0, VLF);
+		FIFOLOAD(p, MSG1, PDCP_NULL_INT_MAC_I_VAL, 4,
+			 LAST1 | FLUSH1 | IMMED);
+	} else {
+		SEQFIFOLOAD(p, MSG1, 0, VLF | LAST1 | FLUSH1);
+		MOVE(p, OFIFO, 0, MATH1, 4, PDCP_MAC_I_LEN, WAITCOMP | IMMED);
+		MATHB(p, MATH1, XOR, PDCP_NULL_INT_MAC_I_VAL, NONE, 4, IMMED2);
+		JUMP(p, PDCP_NULL_INT_ICV_CHECK_FAILED_STATUS,
+		     HALT_STATUS, ALL_FALSE, MATH_Z);
+	}
+
+	return 0;
+}
+
+static inline int
+pdcp_insert_cplane_acc_op(struct program *p,
+			  bool swap __maybe_unused,
+			  struct alginfo *cipherdata,
+			  struct alginfo *authdata,
+			  unsigned int dir,
+			  unsigned char era_2_hfn_ovrd __maybe_unused)
+{
+	/* Insert Auth Key */
+	KEY(p, KEY2, authdata->key_enc_flags, authdata->key, authdata->keylen,
+	    INLINE_KEY(authdata));
+
+	/* Insert Cipher Key */
+	KEY(p, KEY1, cipherdata->key_enc_flags, cipherdata->key,
+	    cipherdata->keylen, INLINE_KEY(cipherdata));
+	PROTOCOL(p, dir, OP_PCLID_LTE_PDCP_CTRL, (uint16_t)cipherdata->algtype);
+
+	return 0;
+}
+
+static inline int
+pdcp_insert_cplane_snow_aes_op(struct program *p,
+			       bool swap __maybe_unused,
+			       struct alginfo *cipherdata,
+			       struct alginfo *authdata,
+			       unsigned int dir,
+			       unsigned char era_2_sw_hfn_ovrd)
+{
+	LABEL(back_to_sd_offset);
+	LABEL(end_desc);
+	LABEL(local_offset);
+	LABEL(jump_to_beginning);
+	LABEL(fifo_load_mac_i_offset);
+	REFERENCE(seqin_ptr_read);
+	REFERENCE(seqin_ptr_write);
+	REFERENCE(seq_out_read);
+	REFERENCE(jump_back_to_sd_cmd);
+	REFERENCE(move_mac_i_to_desc_buf);
+
+	if (rta_sec_era >= RTA_SEC_ERA_8) {
+		KEY(p, KEY1, cipherdata->key_enc_flags, cipherdata->key,
+				cipherdata->keylen, INLINE_KEY(cipherdata));
+		KEY(p, KEY2, authdata->key_enc_flags, authdata->key,
+				authdata->keylen, INLINE_KEY(authdata));
+
+		PROTOCOL(p, dir, OP_PCLID_LTE_PDCP_CTRL_MIXED,
+			 ((uint16_t)cipherdata->algtype << 8) |
+			 (uint16_t)authdata->algtype);
+
+		return 0;
+	}
+
+	SEQLOAD(p, MATH0, 7, 1, 0);
+	JUMP(p, 1, LOCAL_JUMP, ALL_TRUE, CALM);
+	if (swap == false)
+		MATHB(p, MATH0, AND, PDCP_C_PLANE_SN_MASK, MATH1, 8,
+			IFB | IMMED2);
+	else
+		MATHB(p, MATH0, AND, PDCP_C_PLANE_SN_MASK_BE, MATH1, 8,
+			IFB | IMMED2);
+	MATHB(p, MATH1, SHLD, MATH1, MATH1, 8, 0);
+	MOVE(p, DESCBUF, 4, MATH2, 0, 0x08, WAITCOMP | IMMED);
+	MATHB(p, MATH1, OR, MATH2, MATH2, 8, 0);
+	SEQSTORE(p, MATH0, 7, 1, 0);
+	if (dir == OP_TYPE_ENCAP_PROTOCOL) {
+		if (rta_sec_era > RTA_SEC_ERA_2 ||
+		    (rta_sec_era == RTA_SEC_ERA_2 &&
+				   era_2_sw_hfn_ovrd == 0)) {
+			SEQINPTR(p, 0, 1, RTO);
+		} else {
+			SEQINPTR(p, 0, 5, RTO);
+			SEQFIFOLOAD(p, SKIP, 4, 0);
+		}
+		KEY(p, KEY1, authdata->key_enc_flags, authdata->key,
+		    authdata->keylen, INLINE_KEY(authdata));
+		MOVE(p, MATH2, 0, IFIFOAB1, 0, 0x08, IMMED);
+
+		if (rta_sec_era > RTA_SEC_ERA_2) {
+			MATHB(p, SEQINSZ, SUB, ZERO, VSEQINSZ, 4, 0);
+			MATHB(p, SEQINSZ, SUB, ZERO, MATH1, 4, 0);
+			MATHB(p, VSEQINSZ, ADD, PDCP_MAC_I_LEN - 1, VSEQOUTSZ,
+			      4, IMMED2);
+		} else {
+			MATHB(p, SEQINSZ, SUB, MATH3, VSEQINSZ, 4, 0);
+			MATHB(p, VSEQINSZ, ADD, PDCP_MAC_I_LEN - 1, VSEQOUTSZ,
+			      4, IMMED2);
+			/*
+			 * Note: Although the calculations below might seem a
+			 * little off, the logic is the following:
+			 *
+			 * - SEQ IN PTR RTO below needs the full length of the
+			 *   frame; in case of P4080_REV_2_HFN_OV_WORKAROUND,
+			 *   this means the length of the frame to be processed
+			 *   + 4 bytes (the HFN override flag and value).
+			 *   The length of the frame to be processed minus 1
+			 *   byte is in the VSIL register (because
+			 *   VSIL = SIL + 3, due to 1 byte, the header being
+			 *   already written by the SEQ STORE above). So for
+			 *   calculating the length to use in RTO, I add one
+			 *   to the VSIL value in order to obtain the total
+			 *   frame length. This helps in case of P4080 which
+			 *   can have the value 0 as an operand in a MATH
+			 *   command only as SRC1 When the HFN override
+			 *   workaround is not enabled, the length of the
+			 *   frame is given by the SIL register; the
+			 *   calculation is similar to the one in the SEC 4.2
+			 *   and SEC 5.3 cases.
+			 */
+			if (era_2_sw_hfn_ovrd)
+				MATHB(p, VSEQOUTSZ, ADD, ONE, MATH1, 4,
+				      0);
+			else
+				MATHB(p, SEQINSZ, ADD, MATH3, MATH1, 4,
+				      0);
+		}
+		/*
+		 * Placeholder for filling the length in
+		 * SEQIN PTR RTO below
+		 */
+		seqin_ptr_read = MOVE(p, DESCBUF, 0, MATH1, 0, 6, IMMED);
+		seqin_ptr_write = MOVE(p, MATH1, 0, DESCBUF, 0, 8,
+				       WAITCOMP | IMMED);
+		ALG_OPERATION(p, OP_ALG_ALGSEL_AES,
+			      OP_ALG_AAI_CMAC,
+			      OP_ALG_AS_INITFINAL,
+			      ICV_CHECK_DISABLE,
+			      DIR_DEC);
+		SEQFIFOLOAD(p, MSG1, 0, VLF | LAST1 | FLUSH1);
+		MOVE(p, CONTEXT1, 0, MATH3, 0, 4, WAITCOMP | IMMED);
+		if (rta_sec_era <= RTA_SEC_ERA_3)
+			LOAD(p, CLRW_CLR_C1KEY |
+			     CLRW_CLR_C1CTX |
+			     CLRW_CLR_C1ICV |
+			     CLRW_CLR_C1DATAS |
+			     CLRW_CLR_C1MODE,
+			     CLRW, 0, 4, IMMED);
+		else
+			LOAD(p, CLRW_RESET_CLS1_CHA |
+			     CLRW_CLR_C1KEY |
+			     CLRW_CLR_C1CTX |
+			     CLRW_CLR_C1ICV |
+			     CLRW_CLR_C1DATAS |
+			     CLRW_CLR_C1MODE,
+			     CLRW, 0, 4, IMMED);
+
+		if (rta_sec_era <= RTA_SEC_ERA_3)
+			LOAD(p, CCTRL_RESET_CHA_ALL, CCTRL, 0, 4, IMMED);
+
+		KEY(p, KEY1, cipherdata->key_enc_flags, cipherdata->key,
+		    cipherdata->keylen, INLINE_KEY(cipherdata));
+		SET_LABEL(p, local_offset);
+		MOVE(p, MATH2, 0, CONTEXT1, 0, 8, IMMED);
+		SEQINPTR(p, 0, 0, RTO);
+
+		if (rta_sec_era == RTA_SEC_ERA_2 && era_2_sw_hfn_ovrd) {
+			SEQFIFOLOAD(p, SKIP, 5, 0);
+			MATHB(p, SEQINSZ, ADD, ONE, SEQINSZ, 4, 0);
+		}
+
+		MATHB(p, SEQINSZ, SUB, ONE, VSEQINSZ, 4, 0);
+		ALG_OPERATION(p, OP_ALG_ALGSEL_SNOW_F8,
+			      OP_ALG_AAI_F8,
+			      OP_ALG_AS_INITFINAL,
+			      ICV_CHECK_DISABLE,
+			      DIR_ENC);
+		SEQFIFOSTORE(p, MSG, 0, 0, VLF);
+
+		if (rta_sec_era > RTA_SEC_ERA_2 ||
+		    (rta_sec_era == RTA_SEC_ERA_2 &&
+				   era_2_sw_hfn_ovrd == 0))
+			SEQFIFOLOAD(p, SKIP, 1, 0);
+
+		SEQFIFOLOAD(p, MSG1, 0, VLF);
+		MOVE(p, MATH3, 0, IFIFOAB1, 0, 4, LAST1 | FLUSH1 | IMMED);
+		PATCH_MOVE(p, seqin_ptr_read, local_offset);
+		PATCH_MOVE(p, seqin_ptr_write, local_offset);
+	} else {
+		MOVE(p, MATH2, 0, CONTEXT1, 0, 8, IMMED);
+
+		if (rta_sec_era >= RTA_SEC_ERA_5)
+			MOVE(p, CONTEXT1, 0, CONTEXT2, 0, 8, IMMED);
+
+		if (rta_sec_era > RTA_SEC_ERA_2)
+			MATHB(p, SEQINSZ, SUB, ZERO, VSEQINSZ, 4, 0);
+		else
+			MATHB(p, SEQINSZ, SUB, MATH3, VSEQINSZ, 4, 0);
+
+		MATHB(p, SEQINSZ, SUB, PDCP_MAC_I_LEN, VSEQOUTSZ, 4, IMMED2);
+/*
+ * TODO: To be changed when proper support is added in RTA (can't load a
+ * command that is also written by RTA (or patch it for that matter).
+ * Change when proper RTA support is added.
+ */
+		if (p->ps)
+			WORD(p, 0x168B0004);
+		else
+			WORD(p, 0x16880404);
+
+		jump_back_to_sd_cmd = JUMP(p, 0, LOCAL_JUMP, ALL_TRUE, 0);
+		/*
+		 * Placeholder for command reading  the SEQ OUT command in
+		 * JD. Done for rereading the decrypted data and performing
+		 * the integrity check
+		 */
+/*
+ * TODO: RTA currently doesn't support patching of length of a MOVE command
+ * Thus, it is inserted as a raw word, as per PS setting.
+ */
+		if (p->ps)
+			seq_out_read = MOVE(p, DESCBUF, 0, MATH1, 0, 20,
+					    WAITCOMP | IMMED);
+		else
+			seq_out_read = MOVE(p, DESCBUF, 0, MATH1, 0, 16,
+					    WAITCOMP | IMMED);
+
+		MATHB(p, MATH1, XOR, CMD_SEQ_IN_PTR ^ CMD_SEQ_OUT_PTR, MATH1, 4,
+		      IMMED2);
+		/* Placeholder for overwriting the SEQ IN  with SEQ OUT */
+/*
+ * TODO: RTA currently doesn't support patching of length of a MOVE command
+ * Thus, it is inserted as a raw word, as per PS setting.
+ */
+		if (p->ps)
+			MOVE(p, MATH1, 0, DESCBUF, 0, 24, IMMED);
+		else
+			MOVE(p, MATH1, 0, DESCBUF, 0, 20, IMMED);
+
+		KEY(p, KEY1, cipherdata->key_enc_flags, cipherdata->key,
+		    cipherdata->keylen, INLINE_KEY(cipherdata));
+
+		if (rta_sec_era >= RTA_SEC_ERA_4)
+			MOVE(p, CONTEXT1, 0, CONTEXT2, 0, 8, IMMED);
+		else
+			MOVE(p, CONTEXT1, 0, MATH3, 0, 8, IMMED);
+
+		ALG_OPERATION(p, OP_ALG_ALGSEL_SNOW_F8,
+			      OP_ALG_AAI_F8,
+			      OP_ALG_AS_INITFINAL,
+			      ICV_CHECK_DISABLE,
+			      DIR_DEC);
+		SEQFIFOSTORE(p, MSG, 0, 0, VLF | CONT);
+		SEQFIFOLOAD(p, MSG1, 0, VLF | LAST1 | FLUSH1);
+
+		if (rta_sec_era <= RTA_SEC_ERA_3)
+			move_mac_i_to_desc_buf = MOVE(p, OFIFO, 0, DESCBUF, 0,
+						      4, WAITCOMP | IMMED);
+		else
+			MOVE(p, OFIFO, 0, MATH3, 0, 4, IMMED);
+
+		if (rta_sec_era <= RTA_SEC_ERA_3)
+			LOAD(p, CCTRL_RESET_CHA_ALL, CCTRL, 0, 4, IMMED);
+		else
+			LOAD(p, CLRW_RESET_CLS1_CHA |
+			     CLRW_CLR_C1KEY |
+			     CLRW_CLR_C1CTX |
+			     CLRW_CLR_C1ICV |
+			     CLRW_CLR_C1DATAS |
+			     CLRW_CLR_C1MODE,
+			     CLRW, 0, 4, IMMED);
+
+		KEY(p, KEY1, authdata->key_enc_flags, authdata->key,
+		    authdata->keylen, INLINE_KEY(authdata));
+		/*
+		 * Placeholder for jump in SD for executing the new SEQ IN PTR
+		 * command (which is actually the old SEQ OUT PTR command
+		 * copied over from JD.
+		 */
+		SET_LABEL(p, jump_to_beginning);
+		JUMP(p, 1 - jump_to_beginning, LOCAL_JUMP, ALL_TRUE, 0);
+		SET_LABEL(p, back_to_sd_offset);
+		ALG_OPERATION(p, OP_ALG_ALGSEL_AES,
+			      OP_ALG_AAI_CMAC,
+			      OP_ALG_AS_INITFINAL,
+			      ICV_CHECK_ENABLE,
+			      DIR_DEC);
+
+		/* Read the # of bytes written in the output buffer + 1 (HDR) */
+		MATHB(p, VSEQOUTSZ, ADD, ONE, VSEQINSZ, 4, 0);
+
+		if (rta_sec_era <= RTA_SEC_ERA_3)
+			MOVE(p, MATH3, 0, IFIFOAB1, 0, 8, IMMED);
+		else
+			MOVE(p, CONTEXT2, 0, IFIFOAB1, 0, 8, IMMED);
+
+		if (rta_sec_era == RTA_SEC_ERA_2 && era_2_sw_hfn_ovrd)
+			SEQFIFOLOAD(p, SKIP, 4, 0);
+
+		SEQFIFOLOAD(p, MSG1, 0, VLF | LAST1 | FLUSH1);
+
+		if (rta_sec_era >= RTA_SEC_ERA_4) {
+			LOAD(p, NFIFOENTRY_STYPE_ALTSOURCE |
+			     NFIFOENTRY_DEST_CLASS1 |
+			     NFIFOENTRY_DTYPE_ICV |
+			     NFIFOENTRY_LC1 |
+			     NFIFOENTRY_FC1 | 4, NFIFO_SZL, 0, 4, IMMED);
+			MOVE(p, MATH3, 0, ALTSOURCE, 0, 4, IMMED);
+		} else {
+			SET_LABEL(p, fifo_load_mac_i_offset);
+			FIFOLOAD(p, ICV1, fifo_load_mac_i_offset, 4,
+				 LAST1 | FLUSH1 | IMMED);
+		}
+
+		SET_LABEL(p, end_desc);
+
+		if (!p->ps) {
+			PATCH_MOVE(p, seq_out_read, end_desc + 1);
+			PATCH_JUMP(p, jump_back_to_sd_cmd,
+				   back_to_sd_offset + jump_back_to_sd_cmd - 5);
+
+			if (rta_sec_era <= RTA_SEC_ERA_3)
+				PATCH_MOVE(p, move_mac_i_to_desc_buf,
+					   fifo_load_mac_i_offset + 1);
+		} else {
+			PATCH_MOVE(p, seq_out_read, end_desc + 2);
+			PATCH_JUMP(p, jump_back_to_sd_cmd,
+				   back_to_sd_offset + jump_back_to_sd_cmd - 5);
+
+			if (rta_sec_era <= RTA_SEC_ERA_3)
+				PATCH_MOVE(p, move_mac_i_to_desc_buf,
+					   fifo_load_mac_i_offset + 1);
+		}
+	}
+
+	return 0;
+}
+
+static inline int
+pdcp_insert_cplane_aes_snow_op(struct program *p,
+			       bool swap __maybe_unused,
+			       struct alginfo *cipherdata,
+			       struct alginfo *authdata,
+			       unsigned int dir,
+			       unsigned char era_2_sw_hfn_ovrd __maybe_unused)
+{
+	KEY(p, KEY1, cipherdata->key_enc_flags, cipherdata->key,
+	    cipherdata->keylen, INLINE_KEY(cipherdata));
+	KEY(p, KEY2, authdata->key_enc_flags, authdata->key, authdata->keylen,
+	    INLINE_KEY(authdata));
+
+	if (rta_sec_era >= RTA_SEC_ERA_8) {
+		PROTOCOL(p, dir, OP_PCLID_LTE_PDCP_CTRL_MIXED,
+			 ((uint16_t)cipherdata->algtype << 8) |
+			 (uint16_t)authdata->algtype);
+
+		return 0;
+	}
+
+	if (dir == OP_TYPE_ENCAP_PROTOCOL)
+		MATHB(p, SEQINSZ, SUB, ONE, VSEQINSZ, 4, 0);
+
+	SEQLOAD(p, MATH0, 7, 1, 0);
+	JUMP(p, 1, LOCAL_JUMP, ALL_TRUE, CALM);
+	MOVE(p, MATH0, 7, IFIFOAB2, 0, 1, IMMED);
+	if (swap == false)
+		MATHB(p, MATH0, AND, PDCP_C_PLANE_SN_MASK, MATH1, 8,
+			IFB | IMMED2);
+	else
+		MATHB(p, MATH0, AND, PDCP_C_PLANE_SN_MASK_BE, MATH1, 8,
+			IFB | IMMED2);
+
+	SEQSTORE(p, MATH0, 7, 1, 0);
+	MATHB(p, MATH1, SHLD, MATH1, MATH1, 8, 0);
+	MOVE(p, DESCBUF, 4, MATH2, 0, 8, WAITCOMP | IMMED);
+	MATHB(p, MATH1, OR, MATH2, MATH1, 8, 0);
+	MOVE(p, MATH1, 0, CONTEXT1, 16, 8, IMMED);
+	MOVE(p, MATH1, 0, CONTEXT2, 0, 4, IMMED);
+	if (swap == false) {
+		MATHB(p, MATH1, AND, lower_32_bits(PDCP_BEARER_MASK), MATH2, 4,
+			IMMED2);
+		MATHB(p, MATH1, AND, upper_32_bits(PDCP_DIR_MASK), MATH3, 4,
+			IMMED2);
+	} else {
+		MATHB(p, MATH1, AND, lower_32_bits(PDCP_BEARER_MASK_BE), MATH2,
+			4, IMMED2);
+		MATHB(p, MATH1, AND, upper_32_bits(PDCP_DIR_MASK_BE), MATH3,
+			4, IMMED2);
+	}
+	MATHB(p, MATH3, SHLD, MATH3, MATH3, 8, 0);
+	MOVE(p, MATH2, 4, OFIFO, 0, 12, IMMED);
+	MOVE(p, OFIFO, 0, CONTEXT2, 4, 12, IMMED);
+	if (dir == OP_TYPE_ENCAP_PROTOCOL) {
+		MATHB(p, SEQINSZ, ADD, PDCP_MAC_I_LEN, VSEQOUTSZ, 4, IMMED2);
+	} else {
+		MATHB(p, SEQINSZ, SUB, PDCP_MAC_I_LEN, MATH1, 4, IMMED2);
+
+		MATHB(p, ZERO, ADD, MATH1, VSEQOUTSZ, 4, 0);
+		MATHB(p, ZERO, ADD, MATH1, VSEQINSZ, 4, 0);
+	}
+
+	if (dir == OP_TYPE_ENCAP_PROTOCOL)
+		SEQFIFOSTORE(p, MSG, 0, 0, VLF);
+	else
+		SEQFIFOSTORE(p, MSG, 0, 0, VLF | CONT);
+
+	ALG_OPERATION(p, OP_ALG_ALGSEL_SNOW_F9,
+		      OP_ALG_AAI_F9,
+		      OP_ALG_AS_INITFINAL,
+		      dir == OP_TYPE_ENCAP_PROTOCOL ?
+			     ICV_CHECK_DISABLE : ICV_CHECK_ENABLE,
+		      DIR_DEC);
+	ALG_OPERATION(p, OP_ALG_ALGSEL_AES,
+		      OP_ALG_AAI_CTR,
+		      OP_ALG_AS_INITFINAL,
+		      ICV_CHECK_DISABLE,
+		      dir == OP_TYPE_ENCAP_PROTOCOL ? DIR_ENC : DIR_DEC);
+
+	if (dir == OP_TYPE_ENCAP_PROTOCOL) {
+		SEQFIFOLOAD(p, MSGINSNOOP, 0, VLF | LAST2);
+		MOVE(p, CONTEXT2, 0, IFIFOAB1, 0, 4, LAST1 | FLUSH1 | IMMED);
+	} else {
+		SEQFIFOLOAD(p, MSGOUTSNOOP, 0, VLF | LAST2);
+		SEQFIFOLOAD(p, MSG1, 4, LAST1 | FLUSH1);
+		JUMP(p, 1, LOCAL_JUMP, ALL_TRUE, CLASS1 | NOP | NIFP);
+
+		if (rta_sec_era >= RTA_SEC_ERA_6)
+			LOAD(p, 0, DCTRL, 0, LDLEN_RST_CHA_OFIFO_PTR, IMMED);
+
+		MOVE(p, OFIFO, 0, MATH0, 0, 4, WAITCOMP | IMMED);
+
+		NFIFOADD(p, IFIFO, ICV2, 4, LAST2);
+
+		if (rta_sec_era <= RTA_SEC_ERA_2) {
+			/* Shut off automatic Info FIFO entries */
+			LOAD(p, 0, DCTRL, LDOFF_DISABLE_AUTO_NFIFO, 0, IMMED);
+			MOVE(p, MATH0, 0, IFIFOAB2, 0, 4, WAITCOMP | IMMED);
+		} else {
+			MOVE(p, MATH0, 0, IFIFO, 0, 4, WAITCOMP | IMMED);
+		}
+	}
+
+	return 0;
+}
+
+static inline int
+pdcp_insert_cplane_snow_zuc_op(struct program *p,
+			       bool swap __maybe_unused,
+			       struct alginfo *cipherdata,
+			       struct alginfo *authdata,
+			       unsigned int dir,
+			       unsigned char era_2_sw_hfn_ovrd __maybe_unused)
+{
+	LABEL(keyjump);
+	REFERENCE(pkeyjump);
+
+	if (rta_sec_era < RTA_SEC_ERA_5) {
+		pr_err("Invalid era for selected algorithm\n");
+		return -ENOTSUP;
+	}
+
+	pkeyjump = JUMP(p, keyjump, LOCAL_JUMP, ALL_TRUE, SHRD | SELF | BOTH);
+	KEY(p, KEY1, cipherdata->key_enc_flags, cipherdata->key,
+	    cipherdata->keylen, INLINE_KEY(cipherdata));
+	KEY(p, KEY2, authdata->key_enc_flags, authdata->key, authdata->keylen,
+	    INLINE_KEY(authdata));
+
+	SET_LABEL(p, keyjump);
+
+	if (rta_sec_era >= RTA_SEC_ERA_8) {
+		PROTOCOL(p, dir, OP_PCLID_LTE_PDCP_CTRL_MIXED,
+			 ((uint16_t)cipherdata->algtype << 8) |
+			 (uint16_t)authdata->algtype);
+		return 0;
+	}
+
+	SEQLOAD(p, MATH0, 7, 1, 0);
+	JUMP(p, 1, LOCAL_JUMP, ALL_TRUE, CALM);
+	MOVE(p, MATH0, 7, IFIFOAB2, 0, 1, IMMED);
+	if (swap == false)
+		MATHB(p, MATH0, AND, PDCP_C_PLANE_SN_MASK, MATH1, 8,
+			IFB | IMMED2);
+	else
+		MATHB(p, MATH0, AND, PDCP_C_PLANE_SN_MASK, MATH1, 8,
+			IFB | IMMED2);
+
+	MATHB(p, MATH1, SHLD, MATH1, MATH1, 8, 0);
+	MOVE(p, DESCBUF, 4, MATH2, 0, 8, WAITCOMP | IMMED);
+	MATHB(p, MATH1, OR, MATH2, MATH2, 8, 0);
+	MOVE(p, MATH2, 0, CONTEXT1, 0, 8, IMMED);
+	MOVE(p, MATH2, 0, CONTEXT2, 0, 8, WAITCOMP | IMMED);
+
+	if (dir == OP_TYPE_ENCAP_PROTOCOL)
+		MATHB(p, SEQINSZ, ADD, PDCP_MAC_I_LEN, VSEQOUTSZ, 4, IMMED2);
+	else
+		MATHB(p, SEQINSZ, SUB, PDCP_MAC_I_LEN, VSEQOUTSZ, 4, IMMED2);
+
+	MATHB(p, SEQINSZ, SUB, ZERO, VSEQINSZ, 4, 0);
+	SEQSTORE(p, MATH0, 7, 1, 0);
+
+	if (dir == OP_TYPE_ENCAP_PROTOCOL) {
+		SEQFIFOSTORE(p, MSG, 0, 0, VLF);
+		SEQFIFOLOAD(p, MSGINSNOOP, 0, VLF | LAST2);
+	} else {
+		SEQFIFOSTORE(p, MSG, 0, 0, VLF | CONT);
+		SEQFIFOLOAD(p, MSGOUTSNOOP, 0, VLF | LAST1 | FLUSH1);
+	}
+
+	ALG_OPERATION(p, OP_ALG_ALGSEL_ZUCA,
+		      OP_ALG_AAI_F9,
+		      OP_ALG_AS_INITFINAL,
+		      dir == OP_TYPE_ENCAP_PROTOCOL ?
+			     ICV_CHECK_DISABLE : ICV_CHECK_ENABLE,
+		      DIR_ENC);
+
+	ALG_OPERATION(p, OP_ALG_ALGSEL_SNOW_F8,
+		      OP_ALG_AAI_F8,
+		      OP_ALG_AS_INITFINAL,
+		      ICV_CHECK_DISABLE,
+		      dir == OP_TYPE_ENCAP_PROTOCOL ? DIR_ENC : DIR_DEC);
+	if (dir == OP_TYPE_ENCAP_PROTOCOL) {
+		MOVE(p, CONTEXT2, 0, IFIFOAB1, 0, 4, LAST1 | FLUSH1 | IMMED);
+	} else {
+		/* Save ICV */
+		MOVE(p, OFIFO, 0, MATH0, 0, 4, IMMED);
+		LOAD(p, NFIFOENTRY_STYPE_ALTSOURCE |
+		     NFIFOENTRY_DEST_CLASS2 |
+		     NFIFOENTRY_DTYPE_ICV |
+		     NFIFOENTRY_LC2 | 4, NFIFO_SZL, 0, 4, IMMED);
+		MOVE(p, MATH0, 0, ALTSOURCE, 0, 4, WAITCOMP | IMMED);
+	}
+
+	/* Reset ZUCA mode and done interrupt */
+	LOAD(p, CLRW_CLR_C2MODE, CLRW, 0, 4, IMMED);
+	LOAD(p, CIRQ_ZADI, ICTRL, 0, 4, IMMED);
+
+	PATCH_JUMP(p, pkeyjump, keyjump);
+	return 0;
+}
+
+static inline int
+pdcp_insert_cplane_aes_zuc_op(struct program *p,
+			      bool swap __maybe_unused,
+			      struct alginfo *cipherdata,
+			      struct alginfo *authdata,
+			      unsigned int dir,
+			      unsigned char era_2_sw_hfn_ovrd __maybe_unused)
+{
+	LABEL(keyjump);
+	REFERENCE(pkeyjump);
+
+	if (rta_sec_era < RTA_SEC_ERA_5) {
+		pr_err("Invalid era for selected algorithm\n");
+		return -ENOTSUP;
+	}
+
+	pkeyjump = JUMP(p, keyjump, LOCAL_JUMP, ALL_TRUE, SHRD | SELF | BOTH);
+	KEY(p, KEY1, cipherdata->key_enc_flags, cipherdata->key,
+	    cipherdata->keylen, INLINE_KEY(cipherdata));
+	KEY(p, KEY2, authdata->key_enc_flags, authdata->key, authdata->keylen,
+	    INLINE_KEY(authdata));
+
+	if (rta_sec_era >= RTA_SEC_ERA_8) {
+		PROTOCOL(p, dir, OP_PCLID_LTE_PDCP_CTRL_MIXED,
+			 ((uint16_t)cipherdata->algtype << 8) |
+			 (uint16_t)authdata->algtype);
+
+		return 0;
+	}
+
+	SET_LABEL(p, keyjump);
+	SEQLOAD(p, MATH0, 7, 1, 0);
+	JUMP(p, 1, LOCAL_JUMP, ALL_TRUE, CALM);
+	MOVE(p, MATH0, 7, IFIFOAB2, 0, 1, IMMED);
+	if (swap == false)
+		MATHB(p, MATH0, AND, PDCP_C_PLANE_SN_MASK, MATH1, 8,
+			IFB | IMMED2);
+	else
+		MATHB(p, MATH0, AND, PDCP_C_PLANE_SN_MASK, MATH1, 8,
+			IFB | IMMED2);
+
+	MATHB(p, MATH1, SHLD, MATH1, MATH1, 8, 0);
+	MOVE(p, DESCBUF, 4, MATH2, 0, 8, WAITCOMP | IMMED);
+	MATHB(p, MATH1, OR, MATH2, MATH2, 8, 0);
+	MOVE(p, MATH2, 0, CONTEXT1, 16, 8, IMMED);
+	MOVE(p, MATH2, 0, CONTEXT2, 0, 8, WAITCOMP | IMMED);
+
+	if (dir == OP_TYPE_ENCAP_PROTOCOL)
+		MATHB(p, SEQINSZ, ADD, PDCP_MAC_I_LEN, VSEQOUTSZ, 4, IMMED2);
+	else
+		MATHB(p, SEQINSZ, SUB, PDCP_MAC_I_LEN, VSEQOUTSZ, 4, IMMED2);
+
+	MATHB(p, SEQINSZ, SUB, ZERO, VSEQINSZ, 4, 0);
+	SEQSTORE(p, MATH0, 7, 1, 0);
+
+	if (dir == OP_TYPE_ENCAP_PROTOCOL) {
+		SEQFIFOSTORE(p, MSG, 0, 0, VLF);
+		SEQFIFOLOAD(p, MSGINSNOOP, 0, VLF | LAST2);
+	} else {
+		SEQFIFOSTORE(p, MSG, 0, 0, VLF | CONT);
+		SEQFIFOLOAD(p, MSGOUTSNOOP, 0, VLF | LAST1 | FLUSH1);
+	}
+
+	ALG_OPERATION(p, OP_ALG_ALGSEL_ZUCA,
+		      OP_ALG_AAI_F9,
+		      OP_ALG_AS_INITFINAL,
+		      dir == OP_TYPE_ENCAP_PROTOCOL ?
+			     ICV_CHECK_DISABLE : ICV_CHECK_ENABLE,
+		      DIR_ENC);
+
+	ALG_OPERATION(p, OP_ALG_ALGSEL_AES,
+		      OP_ALG_AAI_CTR,
+		      OP_ALG_AS_INITFINAL,
+		      ICV_CHECK_DISABLE,
+		      dir == OP_TYPE_ENCAP_PROTOCOL ? DIR_ENC : DIR_DEC);
+
+	if (dir == OP_TYPE_ENCAP_PROTOCOL) {
+		MOVE(p, CONTEXT2, 0, IFIFOAB1, 0, 4, LAST1 | FLUSH1 | IMMED);
+	} else {
+		/* Save ICV */
+		MOVE(p, OFIFO, 0, MATH0, 0, 4, IMMED);
+
+		LOAD(p, NFIFOENTRY_STYPE_ALTSOURCE |
+		     NFIFOENTRY_DEST_CLASS2 |
+		     NFIFOENTRY_DTYPE_ICV |
+		     NFIFOENTRY_LC2 | 4, NFIFO_SZL, 0, 4, IMMED);
+		MOVE(p, MATH0, 0, ALTSOURCE, 0, 4, WAITCOMP | IMMED);
+	}
+
+	/* Reset ZUCA mode and done interrupt */
+	LOAD(p, CLRW_CLR_C2MODE, CLRW, 0, 4, IMMED);
+	LOAD(p, CIRQ_ZADI, ICTRL, 0, 4, IMMED);
+
+	PATCH_JUMP(p, pkeyjump, keyjump);
+
+	return 0;
+}
+
+static inline int
+pdcp_insert_cplane_zuc_snow_op(struct program *p,
+			       bool swap __maybe_unused,
+			       struct alginfo *cipherdata,
+			       struct alginfo *authdata,
+			       unsigned int dir,
+			       unsigned char era_2_sw_hfn_ovrd __maybe_unused)
+{
+	LABEL(keyjump);
+	REFERENCE(pkeyjump);
+
+	if (rta_sec_era < RTA_SEC_ERA_5) {
+		pr_err("Invalid era for selected algorithm\n");
+		return -ENOTSUP;
+	}
+
+	pkeyjump = JUMP(p, keyjump, LOCAL_JUMP, ALL_TRUE, SHRD | SELF | BOTH);
+	KEY(p, KEY1, cipherdata->key_enc_flags, cipherdata->key,
+	    cipherdata->keylen, INLINE_KEY(cipherdata));
+	KEY(p, KEY2, authdata->key_enc_flags, authdata->key, authdata->keylen,
+	    INLINE_KEY(authdata));
+
+	if (rta_sec_era >= RTA_SEC_ERA_8) {
+		PROTOCOL(p, dir, OP_PCLID_LTE_PDCP_CTRL_MIXED,
+			 ((uint16_t)cipherdata->algtype << 8) |
+			 (uint16_t)authdata->algtype);
+
+		return 0;
+	}
+
+	SET_LABEL(p, keyjump);
+	SEQLOAD(p, MATH0, 7, 1, 0);
+	JUMP(p, 1, LOCAL_JUMP, ALL_TRUE, CALM);
+	MOVE(p, MATH0, 7, IFIFOAB2, 0, 1, IMMED);
+	if (swap == false)
+		MATHB(p, MATH0, AND, PDCP_C_PLANE_SN_MASK, MATH1, 8,
+			IFB | IMMED2);
+	else
+		MATHB(p, MATH0, AND, PDCP_C_PLANE_SN_MASK, MATH1, 8,
+			IFB | IMMED2);
+
+	MATHB(p, MATH1, SHLD, MATH1, MATH1, 8, 0);
+	MOVE(p, DESCBUF, 4, MATH2, 0, 8, WAITCOMP | IMMED);
+	MATHB(p, MATH1, OR, MATH2, MATH1, 8, 0);
+	MOVE(p, MATH1, 0, CONTEXT1, 0, 8, IMMED);
+	MOVE(p, MATH1, 0, CONTEXT2, 0, 4, IMMED);
+	if (swap == false) {
+		MATHB(p, MATH1, AND, lower_32_bits(PDCP_BEARER_MASK), MATH2,
+			4, IMMED2);
+		MATHB(p, MATH1, AND, upper_32_bits(PDCP_DIR_MASK), MATH3,
+			4, IMMED2);
+	} else {
+		MATHB(p, MATH1, AND, lower_32_bits(PDCP_BEARER_MASK_BE), MATH2,
+			4, IMMED2);
+		MATHB(p, MATH1, AND, upper_32_bits(PDCP_DIR_MASK_BE), MATH3,
+			4, IMMED2);
+	}
+	MATHB(p, MATH3, SHLD, MATH3, MATH3, 8, 0);
+	MOVE(p, MATH2, 4, OFIFO, 0, 12, IMMED);
+	MOVE(p, OFIFO, 0, CONTEXT2, 4, 12, IMMED);
+
+	if (dir == OP_TYPE_ENCAP_PROTOCOL) {
+		MATHB(p, SEQINSZ, ADD, PDCP_MAC_I_LEN, VSEQOUTSZ, 4, IMMED2);
+		MATHB(p, SEQINSZ, SUB, ZERO, VSEQINSZ, 4, 0);
+	} else {
+		MATHB(p, SEQINSZ, SUB, PDCP_MAC_I_LEN, VSEQOUTSZ, 4, IMMED2);
+		MATHB(p, VSEQOUTSZ, SUB, ZERO, VSEQINSZ, 4, 0);
+	}
+
+	SEQSTORE(p, MATH0, 7, 1, 0);
+
+	if (dir == OP_TYPE_ENCAP_PROTOCOL) {
+		SEQFIFOSTORE(p, MSG, 0, 0, VLF);
+		SEQFIFOLOAD(p, MSGINSNOOP, 0, VLF | LAST2);
+	} else {
+		SEQFIFOSTORE(p, MSG, 0, 0, VLF | CONT);
+		SEQFIFOLOAD(p, MSGOUTSNOOP, 0, VLF | LAST2);
+	}
+
+	ALG_OPERATION(p, OP_ALG_ALGSEL_SNOW_F9,
+		      OP_ALG_AAI_F9,
+		      OP_ALG_AS_INITFINAL,
+		      dir == OP_TYPE_ENCAP_PROTOCOL ?
+			     ICV_CHECK_DISABLE : ICV_CHECK_ENABLE,
+		      DIR_DEC);
+
+	ALG_OPERATION(p, OP_ALG_ALGSEL_ZUCE,
+		      OP_ALG_AAI_F8,
+		      OP_ALG_AS_INITFINAL,
+		      ICV_CHECK_DISABLE,
+		      dir == OP_TYPE_ENCAP_PROTOCOL ? DIR_ENC : DIR_DEC);
+
+	if (dir == OP_TYPE_ENCAP_PROTOCOL) {
+		MOVE(p, CONTEXT2, 0, IFIFOAB1, 0, 4, LAST1 | FLUSH1 | IMMED);
+	} else {
+		SEQFIFOLOAD(p, MSG1, 4, LAST1 | FLUSH1);
+		JUMP(p, 1, LOCAL_JUMP, ALL_TRUE, CLASS1 | NOP | NIFP);
+
+		if (rta_sec_era >= RTA_SEC_ERA_6)
+			/*
+			 * For SEC ERA 6, there's a problem with the OFIFO
+			 * pointer, and thus it needs to be reset here before
+			 * moving to M0.
+			 */
+			LOAD(p, 0, DCTRL, 0, LDLEN_RST_CHA_OFIFO_PTR, IMMED);
+
+		/* Put ICV to M0 before sending it to C2 for comparison. */
+		MOVE(p, OFIFO, 0, MATH0, 0, 4, WAITCOMP | IMMED);
+
+		LOAD(p, NFIFOENTRY_STYPE_ALTSOURCE |
+		     NFIFOENTRY_DEST_CLASS2 |
+		     NFIFOENTRY_DTYPE_ICV |
+		     NFIFOENTRY_LC2 | 4, NFIFO_SZL, 0, 4, IMMED);
+		MOVE(p, MATH0, 0, ALTSOURCE, 0, 4, IMMED);
+	}
+
+	PATCH_JUMP(p, pkeyjump, keyjump);
+	return 0;
+}
+
+static inline int
+pdcp_insert_cplane_zuc_aes_op(struct program *p,
+			      bool swap __maybe_unused,
+			      struct alginfo *cipherdata,
+			      struct alginfo *authdata,
+			      unsigned int dir,
+			      unsigned char era_2_sw_hfn_ovrd __maybe_unused)
+{
+	if (rta_sec_era < RTA_SEC_ERA_5) {
+		pr_err("Invalid era for selected algorithm\n");
+		return -ENOTSUP;
+	}
+
+	if (rta_sec_era >= RTA_SEC_ERA_8) {
+		KEY(p, KEY1, cipherdata->key_enc_flags, cipherdata->key,
+				cipherdata->keylen, INLINE_KEY(cipherdata));
+		KEY(p, KEY2, authdata->key_enc_flags, authdata->key,
+				authdata->keylen, INLINE_KEY(authdata));
+
+		PROTOCOL(p, dir, OP_PCLID_LTE_PDCP_CTRL_MIXED,
+			 ((uint16_t)cipherdata->algtype << 8) |
+			 (uint16_t)authdata->algtype);
+		return 0;
+	}
+
+	SEQLOAD(p, MATH0, 7, 1, 0);
+	JUMP(p, 1, LOCAL_JUMP, ALL_TRUE, CALM);
+	if (swap == false)
+		MATHB(p, MATH0, AND, PDCP_C_PLANE_SN_MASK, MATH1, 8,
+			IFB | IMMED2);
+	else
+		MATHB(p, MATH0, AND, PDCP_C_PLANE_SN_MASK, MATH1, 8,
+			IFB | IMMED2);
+
+	MATHB(p, MATH1, SHLD, MATH1, MATH1, 8, 0);
+	MOVE(p, DESCBUF, 4, MATH2, 0, 0x08, WAITCOMP | IMMED);
+	MATHB(p, MATH1, OR, MATH2, MATH2, 8, 0);
+	SEQSTORE(p, MATH0, 7, 1, 0);
+	if (dir == OP_TYPE_ENCAP_PROTOCOL) {
+		KEY(p, KEY1, authdata->key_enc_flags, authdata->key,
+		    authdata->keylen, INLINE_KEY(authdata));
+		MOVE(p, MATH2, 0, IFIFOAB1, 0, 0x08, IMMED);
+		MOVE(p, MATH0, 7, IFIFOAB1, 0, 1, IMMED);
+
+		MATHB(p, SEQINSZ, SUB, ZERO, VSEQINSZ, 4, 0);
+		MATHB(p, VSEQINSZ, ADD, PDCP_MAC_I_LEN, VSEQOUTSZ, 4, IMMED2);
+
+		ALG_OPERATION(p, OP_ALG_ALGSEL_AES,
+			      OP_ALG_AAI_CMAC,
+			      OP_ALG_AS_INITFINAL,
+			      ICV_CHECK_DISABLE,
+			      DIR_DEC);
+		SEQFIFOLOAD(p, MSG1, 0, VLF | LAST1 | FLUSH1);
+		MOVE(p, CONTEXT1, 0, MATH3, 0, 4, WAITCOMP | IMMED);
+		LOAD(p, CLRW_RESET_CLS1_CHA |
+		     CLRW_CLR_C1KEY |
+		     CLRW_CLR_C1CTX |
+		     CLRW_CLR_C1ICV |
+		     CLRW_CLR_C1DATAS |
+		     CLRW_CLR_C1MODE,
+		     CLRW, 0, 4, IMMED);
+
+		KEY(p, KEY1, cipherdata->key_enc_flags, cipherdata->key,
+		    cipherdata->keylen, INLINE_KEY(cipherdata));
+
+		MOVE(p, MATH2, 0, CONTEXT1, 0, 8, IMMED);
+		SEQINPTR(p, 0, PDCP_NULL_MAX_FRAME_LEN, RTO);
+
+		ALG_OPERATION(p, OP_ALG_ALGSEL_ZUCE,
+			      OP_ALG_AAI_F8,
+			      OP_ALG_AS_INITFINAL,
+			      ICV_CHECK_DISABLE,
+			      DIR_ENC);
+		SEQFIFOSTORE(p, MSG, 0, 0, VLF);
+
+		SEQFIFOLOAD(p, SKIP, 1, 0);
+
+		SEQFIFOLOAD(p, MSG1, 0, VLF);
+		MOVE(p, MATH3, 0, IFIFOAB1, 0, 4, LAST1 | FLUSH1 | IMMED);
+	} else {
+		MOVE(p, MATH2, 0, CONTEXT1, 0, 8, IMMED);
+
+		MOVE(p, CONTEXT1, 0, CONTEXT2, 0, 8, IMMED);
+
+		MATHB(p, SEQINSZ, SUB, ZERO, VSEQINSZ, 4, 0);
+
+		MATHB(p, SEQINSZ, SUB, PDCP_MAC_I_LEN, VSEQOUTSZ, 4, IMMED2);
+
+		KEY(p, KEY1, cipherdata->key_enc_flags, cipherdata->key,
+		    cipherdata->keylen, INLINE_KEY(cipherdata));
+
+		MOVE(p, CONTEXT1, 0, CONTEXT2, 0, 8, IMMED);
+
+		ALG_OPERATION(p, OP_ALG_ALGSEL_ZUCE,
+			      OP_ALG_AAI_F8,
+			      OP_ALG_AS_INITFINAL,
+			      ICV_CHECK_DISABLE,
+			      DIR_DEC);
+		SEQFIFOSTORE(p, MSG, 0, 0, VLF | CONT);
+		SEQFIFOLOAD(p, MSG1, 0, VLF | LAST1 | FLUSH1);
+
+		MOVE(p, OFIFO, 0, MATH3, 0, 4, IMMED);
+
+		LOAD(p, CLRW_RESET_CLS1_CHA |
+		     CLRW_CLR_C1KEY |
+		     CLRW_CLR_C1CTX |
+		     CLRW_CLR_C1ICV |
+		     CLRW_CLR_C1DATAS |
+		     CLRW_CLR_C1MODE,
+		     CLRW, 0, 4, IMMED);
+
+		KEY(p, KEY1, authdata->key_enc_flags, authdata->key,
+		    authdata->keylen, INLINE_KEY(authdata));
+
+		SEQINPTR(p, 0, 0, SOP);
+
+		ALG_OPERATION(p, OP_ALG_ALGSEL_AES,
+			      OP_ALG_AAI_CMAC,
+			      OP_ALG_AS_INITFINAL,
+			      ICV_CHECK_ENABLE,
+			      DIR_DEC);
+
+		MATHB(p, SEQINSZ, SUB, ZERO, VSEQINSZ, 4, 0);
+
+		MOVE(p, CONTEXT2, 0, IFIFOAB1, 0, 8, IMMED);
+
+		SEQFIFOLOAD(p, MSG1, 0, VLF | LAST1 | FLUSH1);
+
+		LOAD(p, NFIFOENTRY_STYPE_ALTSOURCE |
+		     NFIFOENTRY_DEST_CLASS1 |
+		     NFIFOENTRY_DTYPE_ICV |
+		     NFIFOENTRY_LC1 |
+		     NFIFOENTRY_FC1 | 4, NFIFO_SZL, 0, 4, IMMED);
+		MOVE(p, MATH3, 0, ALTSOURCE, 0, 4, IMMED);
+	}
+
+	return 0;
+}
+
+static inline int
+pdcp_insert_uplane_15bit_op(struct program *p,
+			    bool swap __maybe_unused,
+			    struct alginfo *cipherdata,
+			    unsigned int dir)
+{
+	int op;
+	/* Insert Cipher Key */
+	KEY(p, KEY1, cipherdata->key_enc_flags, cipherdata->key,
+	    cipherdata->keylen, INLINE_KEY(cipherdata));
+
+	if (rta_sec_era >= RTA_SEC_ERA_8) {
+		PROTOCOL(p, dir, OP_PCLID_LTE_PDCP_USER,
+			 (uint16_t)cipherdata->algtype);
+		return 0;
+	}
+
+	SEQLOAD(p, MATH0, 6, 2, 0);
+	JUMP(p, 1, LOCAL_JUMP, ALL_TRUE, CALM);
+	if (swap == false)
+		MATHB(p, MATH0, AND, PDCP_U_PLANE_15BIT_SN_MASK, MATH1, 8,
+		      IFB | IMMED2);
+	else
+		MATHB(p, MATH0, AND, PDCP_U_PLANE_15BIT_SN_MASK_BE, MATH1, 8,
+		      IFB | IMMED2);
+	SEQSTORE(p, MATH0, 6, 2, 0);
+	MATHB(p, MATH1, SHLD, MATH1, MATH1, 8, 0);
+	MOVE(p, DESCBUF, 8, MATH2, 0, 8, WAITCOMP | IMMED);
+	MATHB(p, MATH1, OR, MATH2, MATH2, 8, 0);
+
+	MATHB(p, SEQINSZ, SUB, MATH3, VSEQINSZ, 4, 0);
+	MATHB(p, SEQINSZ, SUB, MATH3, VSEQOUTSZ, 4, 0);
+
+	SEQFIFOSTORE(p, MSG, 0, 0, VLF);
+
+	op = dir == OP_TYPE_ENCAP_PROTOCOL ? DIR_ENC : DIR_DEC;
+	switch (cipherdata->algtype) {
+	case PDCP_CIPHER_TYPE_SNOW:
+		MOVE(p, MATH2, 0, CONTEXT1, 0, 8, WAITCOMP | IMMED);
+		ALG_OPERATION(p, OP_ALG_ALGSEL_SNOW_F8,
+			      OP_ALG_AAI_F8,
+			      OP_ALG_AS_INITFINAL,
+			      ICV_CHECK_DISABLE,
+			      op);
+		break;
+
+	case PDCP_CIPHER_TYPE_AES:
+		MOVE(p, MATH2, 0, CONTEXT1, 0x10, 0x10, WAITCOMP | IMMED);
+		ALG_OPERATION(p, OP_ALG_ALGSEL_AES,
+			      OP_ALG_AAI_CTR,
+			      OP_ALG_AS_INITFINAL,
+			      ICV_CHECK_DISABLE,
+			      op);
+		break;
+
+	case PDCP_CIPHER_TYPE_ZUC:
+		if (rta_sec_era < RTA_SEC_ERA_5) {
+			pr_err("Invalid era for selected algorithm\n");
+			return -ENOTSUP;
+		}
+		MOVE(p, MATH2, 0, CONTEXT1, 0, 0x08, IMMED);
+		MOVE(p, MATH2, 0, CONTEXT1, 0x08, 0x08, WAITCOMP | IMMED);
+
+		ALG_OPERATION(p, OP_ALG_ALGSEL_ZUCE,
+			      OP_ALG_AAI_F8,
+			      OP_ALG_AS_INITFINAL,
+			      ICV_CHECK_DISABLE,
+			      op);
+		break;
+
+	default:
+		pr_err("%s: Invalid encrypt algorithm selected: %d\n",
+		       "pdcp_insert_uplane_15bit_op", cipherdata->algtype);
+		return -EINVAL;
+	}
+
+	SEQFIFOLOAD(p, MSG1, 0, VLF | LAST1 | FLUSH1);
+
+	return 0;
+}
+
+/*
+ * Function for inserting the snippet of code responsible for creating
+ * the HFN override code via either DPOVRD or via the input frame.
+ */
+static inline int
+insert_hfn_ov_op(struct program *p,
+		 uint32_t shift,
+		 enum pdb_type_e pdb_type,
+		 unsigned char era_2_sw_hfn_ovrd)
+{
+	uint32_t imm = PDCP_DPOVRD_HFN_OV_EN;
+	uint16_t hfn_pdb_offset;
+
+	if (rta_sec_era == RTA_SEC_ERA_2 && !era_2_sw_hfn_ovrd)
+		return 0;
+
+	switch (pdb_type) {
+	case PDCP_PDB_TYPE_NO_PDB:
+		/*
+		 * If there is no PDB, then HFN override mechanism does not
+		 * make any sense, thus in this case the function will
+		 * return the pointer to the current position in the
+		 * descriptor buffer
+		 */
+		return 0;
+
+	case PDCP_PDB_TYPE_REDUCED_PDB:
+		hfn_pdb_offset = 4;
+		break;
+
+	case PDCP_PDB_TYPE_FULL_PDB:
+		hfn_pdb_offset = 8;
+		break;
+
+	default:
+		return -EINVAL;
+	}
+
+	if (rta_sec_era > RTA_SEC_ERA_2) {
+		MATHB(p, DPOVRD, AND, imm, NONE, 8, IFB | IMMED2);
+	} else {
+		SEQLOAD(p, MATH0, 4, 4, 0);
+		JUMP(p, 1, LOCAL_JUMP, ALL_TRUE, CALM);
+		MATHB(p, MATH0, AND, imm, NONE, 8, IFB | IMMED2);
+		SEQSTORE(p, MATH0, 4, 4, 0);
+	}
+
+	if (rta_sec_era >= RTA_SEC_ERA_8)
+		JUMP(p, 6, LOCAL_JUMP, ALL_TRUE, MATH_Z);
+	else
+		JUMP(p, 5, LOCAL_JUMP, ALL_TRUE, MATH_Z);
+
+	if (rta_sec_era > RTA_SEC_ERA_2)
+		MATHB(p, DPOVRD, LSHIFT, shift, MATH0, 4, IMMED2);
+	else
+		MATHB(p, MATH0, LSHIFT, shift, MATH0, 4, IMMED2);
+
+	MATHB(p, MATH0, SHLD, MATH0, MATH0, 8, 0);
+	MOVE(p, MATH0, 0, DESCBUF, hfn_pdb_offset, 4, IMMED);
+
+	if (rta_sec_era >= RTA_SEC_ERA_8)
+		/*
+		 * For ERA8, DPOVRD could be handled by the PROTOCOL command
+		 * itself. For now, this is not done. Thus, clear DPOVRD here
+		 * to alleviate any side-effects.
+		 */
+		MATHB(p, DPOVRD, AND, ZERO, DPOVRD, 4, STL);
+
+	return 0;
+}
+
+/*
+ * PDCP Control PDB creation function
+ */
+static inline enum pdb_type_e
+cnstr_pdcp_c_plane_pdb(struct program *p,
+		       uint32_t hfn,
+		       unsigned char bearer,
+		       unsigned char direction,
+		       uint32_t hfn_threshold,
+		       struct alginfo *cipherdata,
+		       struct alginfo *authdata)
+{
+	struct pdcp_pdb pdb;
+	enum pdb_type_e
+		pdb_mask[PDCP_CIPHER_TYPE_INVALID][PDCP_AUTH_TYPE_INVALID] = {
+			{	/* NULL */
+				PDCP_PDB_TYPE_NO_PDB,		/* NULL */
+				PDCP_PDB_TYPE_FULL_PDB,		/* SNOW f9 */
+				PDCP_PDB_TYPE_FULL_PDB,		/* AES CMAC */
+				PDCP_PDB_TYPE_FULL_PDB		/* ZUC-I */
+			},
+			{	/* SNOW f8 */
+				PDCP_PDB_TYPE_FULL_PDB,		/* NULL */
+				PDCP_PDB_TYPE_FULL_PDB,		/* SNOW f9 */
+				PDCP_PDB_TYPE_REDUCED_PDB,	/* AES CMAC */
+				PDCP_PDB_TYPE_REDUCED_PDB	/* ZUC-I */
+			},
+			{	/* AES CTR */
+				PDCP_PDB_TYPE_FULL_PDB,		/* NULL */
+				PDCP_PDB_TYPE_REDUCED_PDB,	/* SNOW f9 */
+				PDCP_PDB_TYPE_FULL_PDB,		/* AES CMAC */
+				PDCP_PDB_TYPE_REDUCED_PDB	/* ZUC-I */
+			},
+			{	/* ZUC-E */
+				PDCP_PDB_TYPE_FULL_PDB,		/* NULL */
+				PDCP_PDB_TYPE_REDUCED_PDB,	/* SNOW f9 */
+				PDCP_PDB_TYPE_REDUCED_PDB,	/* AES CMAC */
+				PDCP_PDB_TYPE_FULL_PDB		/* ZUC-I */
+			},
+	};
+
+	if (rta_sec_era >= RTA_SEC_ERA_8) {
+		memset(&pdb, 0x00, sizeof(struct pdcp_pdb));
+
+		/* This is a HW issue. Bit 2 should be set to zero,
+		 * but it does not work this way. Override here.
+		 */
+		pdb.opt_res.rsvd = 0x00000002;
+
+		/* Copy relevant information from user to PDB */
+		pdb.hfn_res = hfn << PDCP_C_PLANE_PDB_HFN_SHIFT;
+		pdb.bearer_dir_res = (uint32_t)
+				((bearer << PDCP_C_PLANE_PDB_BEARER_SHIFT) |
+				 (direction << PDCP_C_PLANE_PDB_DIR_SHIFT));
+		pdb.hfn_thr_res =
+				hfn_threshold << PDCP_C_PLANE_PDB_HFN_THR_SHIFT;
+
+		/* copy PDB in descriptor*/
+		__rta_out32(p, pdb.opt_res.opt);
+		__rta_out32(p, pdb.hfn_res);
+		__rta_out32(p, pdb.bearer_dir_res);
+		__rta_out32(p, pdb.hfn_thr_res);
+
+		return PDCP_PDB_TYPE_FULL_PDB;
+	}
+
+	switch (pdb_mask[cipherdata->algtype][authdata->algtype]) {
+	case PDCP_PDB_TYPE_NO_PDB:
+		break;
+
+	case PDCP_PDB_TYPE_REDUCED_PDB:
+		__rta_out32(p, (hfn << PDCP_C_PLANE_PDB_HFN_SHIFT));
+		__rta_out32(p,
+			    (uint32_t)((bearer <<
+					PDCP_C_PLANE_PDB_BEARER_SHIFT) |
+					(direction <<
+					 PDCP_C_PLANE_PDB_DIR_SHIFT)));
+		break;
+
+	case PDCP_PDB_TYPE_FULL_PDB:
+		memset(&pdb, 0x00, sizeof(struct pdcp_pdb));
+
+		/* This is a HW issue. Bit 2 should be set to zero,
+		 * but it does not work this way. Override here.
+		 */
+		pdb.opt_res.rsvd = 0x00000002;
+
+		/* Copy relevant information from user to PDB */
+		pdb.hfn_res = hfn << PDCP_C_PLANE_PDB_HFN_SHIFT;
+		pdb.bearer_dir_res = (uint32_t)
+			((bearer << PDCP_C_PLANE_PDB_BEARER_SHIFT) |
+			 (direction << PDCP_C_PLANE_PDB_DIR_SHIFT));
+		pdb.hfn_thr_res =
+			hfn_threshold << PDCP_C_PLANE_PDB_HFN_THR_SHIFT;
+
+		/* copy PDB in descriptor*/
+		__rta_out32(p, pdb.opt_res.opt);
+		__rta_out32(p, pdb.hfn_res);
+		__rta_out32(p, pdb.bearer_dir_res);
+		__rta_out32(p, pdb.hfn_thr_res);
+
+		break;
+
+	default:
+		return PDCP_PDB_TYPE_INVALID;
+	}
+
+	return pdb_mask[cipherdata->algtype][authdata->algtype];
+}
+
+/*
+ * PDCP UPlane PDB creation function
+ */
+static inline int
+cnstr_pdcp_u_plane_pdb(struct program *p,
+		       enum pdcp_sn_size sn_size,
+		       uint32_t hfn, unsigned short bearer,
+		       unsigned short direction,
+		       uint32_t hfn_threshold)
+{
+	struct pdcp_pdb pdb;
+	/* Read options from user */
+	/* Depending on sequence number length, the HFN and HFN threshold
+	 * have different lengths.
+	 */
+	memset(&pdb, 0x00, sizeof(struct pdcp_pdb));
+
+	switch (sn_size) {
+	case PDCP_SN_SIZE_7:
+		pdb.opt_res.opt |= PDCP_U_PLANE_PDB_OPT_SHORT_SN;
+		pdb.hfn_res = hfn << PDCP_U_PLANE_PDB_SHORT_SN_HFN_SHIFT;
+		pdb.hfn_thr_res =
+			hfn_threshold<<PDCP_U_PLANE_PDB_SHORT_SN_HFN_THR_SHIFT;
+		break;
+
+	case PDCP_SN_SIZE_12:
+		pdb.opt_res.opt &= (uint32_t)(~PDCP_U_PLANE_PDB_OPT_SHORT_SN);
+		pdb.hfn_res = hfn << PDCP_U_PLANE_PDB_LONG_SN_HFN_SHIFT;
+		pdb.hfn_thr_res =
+			hfn_threshold<<PDCP_U_PLANE_PDB_LONG_SN_HFN_THR_SHIFT;
+		break;
+
+	case PDCP_SN_SIZE_15:
+		pdb.opt_res.opt = (uint32_t)(PDCP_U_PLANE_PDB_OPT_15B_SN);
+		pdb.hfn_res = hfn << PDCP_U_PLANE_PDB_15BIT_SN_HFN_SHIFT;
+		pdb.hfn_thr_res =
+			hfn_threshold<<PDCP_U_PLANE_PDB_15BIT_SN_HFN_THR_SHIFT;
+		break;
+
+	default:
+		pr_err("Invalid Sequence Number Size setting in PDB\n");
+		return -EINVAL;
+	}
+
+	pdb.bearer_dir_res = (uint32_t)
+				((bearer << PDCP_U_PLANE_PDB_BEARER_SHIFT) |
+				 (direction << PDCP_U_PLANE_PDB_DIR_SHIFT));
+
+	/* copy PDB in descriptor*/
+	__rta_out32(p, pdb.opt_res.opt);
+	__rta_out32(p, pdb.hfn_res);
+	__rta_out32(p, pdb.bearer_dir_res);
+	__rta_out32(p, pdb.hfn_thr_res);
+
+	return 0;
+}
+/**
+ * cnstr_shdsc_pdcp_c_plane_encap - Function for creating a PDCP Control Plane
+ *                                  encapsulation descriptor.
+ * @descbuf: pointer to buffer for descriptor construction
+ * @ps: if 36/40bit addressing is desired, this parameter must be true
+ * @swap: must be true when core endianness doesn't match SEC endianness
+ * @hfn: starting Hyper Frame Number to be used together with the SN from the
+ *       PDCP frames.
+ * @bearer: radio bearer ID
+ * @direction: the direction of the PDCP frame (UL/DL)
+ * @hfn_threshold: HFN value that once reached triggers a warning from SEC that
+ *                 keys should be renegotiated at the earliest convenience.
+ * @cipherdata: pointer to block cipher transform definitions
+ *              Valid algorithm values are those from cipher_type_pdcp enum.
+ * @authdata: pointer to authentication transform definitions
+ *            Valid algorithm values are those from auth_type_pdcp enum.
+ * @era_2_sw_hfn_ovrd: if software HFN override mechanism is desired for
+ *                     this descriptor. Note: Can only be used for
+ *                     SEC ERA 2.
+ * Return: size of descriptor written in words or negative number on error.
+ *         Once the function returns, the value of this parameter can be used
+ *         for reclaiming the space that wasn't used for the descriptor.
+ *
+ * Note: descbuf must be large enough to contain a full 256 byte long
+ * descriptor; after the function returns, by subtracting the actual number of
+ * bytes used, the user can reuse the remaining buffer space for other purposes.
+ */
+static inline int
+cnstr_shdsc_pdcp_c_plane_encap(uint32_t *descbuf,
+			       bool ps,
+			       bool swap,
+			       uint32_t hfn,
+			       unsigned char bearer,
+			       unsigned char direction,
+			       uint32_t hfn_threshold,
+			       struct alginfo *cipherdata,
+			       struct alginfo *authdata,
+			       unsigned char era_2_sw_hfn_ovrd)
+{
+	static int
+		(*pdcp_cp_fp[PDCP_CIPHER_TYPE_INVALID][PDCP_AUTH_TYPE_INVALID])
+			(struct program*, bool swap, struct alginfo *,
+			 struct alginfo *, unsigned int,
+			unsigned char __maybe_unused) = {
+		{	/* NULL */
+			pdcp_insert_cplane_null_op,	/* NULL */
+			pdcp_insert_cplane_int_only_op,	/* SNOW f9 */
+			pdcp_insert_cplane_int_only_op,	/* AES CMAC */
+			pdcp_insert_cplane_int_only_op	/* ZUC-I */
+		},
+		{	/* SNOW f8 */
+			pdcp_insert_cplane_enc_only_op,	/* NULL */
+			pdcp_insert_cplane_acc_op,	/* SNOW f9 */
+			pdcp_insert_cplane_snow_aes_op,	/* AES CMAC */
+			pdcp_insert_cplane_snow_zuc_op	/* ZUC-I */
+		},
+		{	/* AES CTR */
+			pdcp_insert_cplane_enc_only_op,	/* NULL */
+			pdcp_insert_cplane_aes_snow_op,	/* SNOW f9 */
+			pdcp_insert_cplane_acc_op,	/* AES CMAC */
+			pdcp_insert_cplane_aes_zuc_op	/* ZUC-I */
+		},
+		{	/* ZUC-E */
+			pdcp_insert_cplane_enc_only_op,	/* NULL */
+			pdcp_insert_cplane_zuc_snow_op,	/* SNOW f9 */
+			pdcp_insert_cplane_zuc_aes_op,	/* AES CMAC */
+			pdcp_insert_cplane_acc_op	/* ZUC-I */
+		},
+	};
+	static enum rta_share_type
+		desc_share[PDCP_CIPHER_TYPE_INVALID][PDCP_AUTH_TYPE_INVALID] = {
+		{	/* NULL */
+			SHR_WAIT,	/* NULL */
+			SHR_ALWAYS,	/* SNOW f9 */
+			SHR_ALWAYS,	/* AES CMAC */
+			SHR_ALWAYS	/* ZUC-I */
+		},
+		{	/* SNOW f8 */
+			SHR_ALWAYS,	/* NULL */
+			SHR_ALWAYS,	/* SNOW f9 */
+			SHR_WAIT,	/* AES CMAC */
+			SHR_WAIT	/* ZUC-I */
+		},
+		{	/* AES CTR */
+			SHR_ALWAYS,	/* NULL */
+			SHR_ALWAYS,	/* SNOW f9 */
+			SHR_ALWAYS,	/* AES CMAC */
+			SHR_WAIT	/* ZUC-I */
+		},
+		{	/* ZUC-E */
+			SHR_ALWAYS,	/* NULL */
+			SHR_WAIT,	/* SNOW f9 */
+			SHR_WAIT,	/* AES CMAC */
+			SHR_ALWAYS	/* ZUC-I */
+		},
+	};
+	enum pdb_type_e pdb_type;
+	struct program prg;
+	struct program *p = &prg;
+	int err;
+	LABEL(pdb_end);
+
+	if (rta_sec_era != RTA_SEC_ERA_2 && era_2_sw_hfn_ovrd) {
+		pr_err("Cannot select SW HFN override for other era than 2");
+		return -EINVAL;
+	}
+
+	PROGRAM_CNTXT_INIT(p, descbuf, 0);
+	if (swap)
+		PROGRAM_SET_BSWAP(p);
+	if (ps)
+		PROGRAM_SET_36BIT_ADDR(p);
+
+	SHR_HDR(p, desc_share[cipherdata->algtype][authdata->algtype], 0, 0);
+
+	pdb_type = cnstr_pdcp_c_plane_pdb(p,
+			hfn,
+			bearer,
+			direction,
+			hfn_threshold,
+			cipherdata,
+			authdata);
+
+	SET_LABEL(p, pdb_end);
+
+	err = insert_hfn_ov_op(p, PDCP_SN_SIZE_5, pdb_type,
+			       era_2_sw_hfn_ovrd);
+	if (err)
+		return err;
+
+	err = pdcp_cp_fp[cipherdata->algtype][authdata->algtype](p,
+		swap,
+		cipherdata,
+		authdata,
+		OP_TYPE_ENCAP_PROTOCOL,
+		era_2_sw_hfn_ovrd);
+	if (err)
+		return err;
+
+	PATCH_HDR(p, 0, pdb_end);
+
+	return PROGRAM_FINALIZE(p);
+}
+
+/**
+ * cnstr_shdsc_pdcp_c_plane_decap - Function for creating a PDCP Control Plane
+ *                                  decapsulation descriptor.
+ * @descbuf: pointer to buffer for descriptor construction
+ * @ps: if 36/40bit addressing is desired, this parameter must be true
+ * @swap: must be true when core endianness doesn't match SEC endianness
+ * @hfn: starting Hyper Frame Number to be used together with the SN from the
+ *       PDCP frames.
+ * @bearer: radio bearer ID
+ * @direction: the direction of the PDCP frame (UL/DL)
+ * @hfn_threshold: HFN value that once reached triggers a warning from SEC that
+ *                 keys should be renegotiated at the earliest convenience.
+ * @cipherdata: pointer to block cipher transform definitions
+ *              Valid algorithm values are those from cipher_type_pdcp enum.
+ * @authdata: pointer to authentication transform definitions
+ *            Valid algorithm values are those from auth_type_pdcp enum.
+ * @era_2_sw_hfn_ovrd: if software HFN override mechanism is desired for
+ *                     this descriptor. Note: Can only be used for
+ *                     SEC ERA 2.
+ *
+ * Return: size of descriptor written in words or negative number on error.
+ *         Once the function returns, the value of this parameter can be used
+ *         for reclaiming the space that wasn't used for the descriptor.
+ *
+ * Note: descbuf must be large enough to contain a full 256 byte long
+ * descriptor; after the function returns, by subtracting the actual number of
+ * bytes used, the user can reuse the remaining buffer space for other purposes.
+ */
+static inline int
+cnstr_shdsc_pdcp_c_plane_decap(uint32_t *descbuf,
+			       bool ps,
+			       bool swap,
+			       uint32_t hfn,
+			       unsigned char bearer,
+			       unsigned char direction,
+			       uint32_t hfn_threshold,
+			       struct alginfo *cipherdata,
+			       struct alginfo *authdata,
+			       unsigned char era_2_sw_hfn_ovrd)
+{
+	static int
+		(*pdcp_cp_fp[PDCP_CIPHER_TYPE_INVALID][PDCP_AUTH_TYPE_INVALID])
+			(struct program*, bool swap, struct alginfo *,
+			 struct alginfo *, unsigned int, unsigned char) = {
+		{	/* NULL */
+			pdcp_insert_cplane_null_op,	/* NULL */
+			pdcp_insert_cplane_int_only_op,	/* SNOW f9 */
+			pdcp_insert_cplane_int_only_op,	/* AES CMAC */
+			pdcp_insert_cplane_int_only_op	/* ZUC-I */
+		},
+		{	/* SNOW f8 */
+			pdcp_insert_cplane_enc_only_op,	/* NULL */
+			pdcp_insert_cplane_acc_op,	/* SNOW f9 */
+			pdcp_insert_cplane_snow_aes_op,	/* AES CMAC */
+			pdcp_insert_cplane_snow_zuc_op	/* ZUC-I */
+		},
+		{	/* AES CTR */
+			pdcp_insert_cplane_enc_only_op,	/* NULL */
+			pdcp_insert_cplane_aes_snow_op,	/* SNOW f9 */
+			pdcp_insert_cplane_acc_op,	/* AES CMAC */
+			pdcp_insert_cplane_aes_zuc_op	/* ZUC-I */
+		},
+		{	/* ZUC-E */
+			pdcp_insert_cplane_enc_only_op,	/* NULL */
+			pdcp_insert_cplane_zuc_snow_op,	/* SNOW f9 */
+			pdcp_insert_cplane_zuc_aes_op,	/* AES CMAC */
+			pdcp_insert_cplane_acc_op	/* ZUC-I */
+		},
+	};
+	static enum rta_share_type
+		desc_share[PDCP_CIPHER_TYPE_INVALID][PDCP_AUTH_TYPE_INVALID] = {
+		{	/* NULL */
+			SHR_WAIT,	/* NULL */
+			SHR_ALWAYS,	/* SNOW f9 */
+			SHR_ALWAYS,	/* AES CMAC */
+			SHR_ALWAYS	/* ZUC-I */
+		},
+		{	/* SNOW f8 */
+			SHR_ALWAYS,	/* NULL */
+			SHR_ALWAYS,	/* SNOW f9 */
+			SHR_WAIT,	/* AES CMAC */
+			SHR_WAIT	/* ZUC-I */
+		},
+		{	/* AES CTR */
+			SHR_ALWAYS,	/* NULL */
+			SHR_ALWAYS,	/* SNOW f9 */
+			SHR_ALWAYS,	/* AES CMAC */
+			SHR_WAIT	/* ZUC-I */
+		},
+		{	/* ZUC-E */
+			SHR_ALWAYS,	/* NULL */
+			SHR_WAIT,	/* SNOW f9 */
+			SHR_WAIT,	/* AES CMAC */
+			SHR_ALWAYS	/* ZUC-I */
+		},
+	};
+	enum pdb_type_e pdb_type;
+	struct program prg;
+	struct program *p = &prg;
+	int err;
+	LABEL(pdb_end);
+
+	if (rta_sec_era != RTA_SEC_ERA_2 && era_2_sw_hfn_ovrd) {
+		pr_err("Cannot select SW HFN override for other era than 2");
+		return -EINVAL;
+	}
+
+	PROGRAM_CNTXT_INIT(p, descbuf, 0);
+	if (swap)
+		PROGRAM_SET_BSWAP(p);
+	if (ps)
+		PROGRAM_SET_36BIT_ADDR(p);
+
+	SHR_HDR(p, desc_share[cipherdata->algtype][authdata->algtype], 0, 0);
+
+	pdb_type = cnstr_pdcp_c_plane_pdb(p,
+			hfn,
+			bearer,
+			direction,
+			hfn_threshold,
+			cipherdata,
+			authdata);
+
+	SET_LABEL(p, pdb_end);
+
+	err = insert_hfn_ov_op(p, PDCP_SN_SIZE_5, pdb_type,
+			       era_2_sw_hfn_ovrd);
+	if (err)
+		return err;
+
+	err = pdcp_cp_fp[cipherdata->algtype][authdata->algtype](p,
+		swap,
+		cipherdata,
+		authdata,
+		OP_TYPE_DECAP_PROTOCOL,
+		era_2_sw_hfn_ovrd);
+	if (err)
+		return err;
+
+	PATCH_HDR(p, 0, pdb_end);
+
+	return PROGRAM_FINALIZE(p);
+}
+
+/**
+ * cnstr_shdsc_pdcp_u_plane_encap - Function for creating a PDCP User Plane
+ *                                  encapsulation descriptor.
+ * @descbuf: pointer to buffer for descriptor construction
+ * @ps: if 36/40bit addressing is desired, this parameter must be true
+ * @swap: must be true when core endianness doesn't match SEC endianness
+ * @sn_size: selects Sequence Number Size: 7/12/15 bits
+ * @hfn: starting Hyper Frame Number to be used together with the SN from the
+ *       PDCP frames.
+ * @bearer: radio bearer ID
+ * @direction: the direction of the PDCP frame (UL/DL)
+ * @hfn_threshold: HFN value that once reached triggers a warning from SEC that
+ *                 keys should be renegotiated at the earliest convenience.
+ * @cipherdata: pointer to block cipher transform definitions
+ *              Valid algorithm values are those from cipher_type_pdcp enum.
+ * @era_2_sw_hfn_ovrd: if software HFN override mechanism is desired for
+ *                     this descriptor. Note: Can only be used for
+ *                     SEC ERA 2.
+ *
+ * Return: size of descriptor written in words or negative number on error.
+ *         Once the function returns, the value of this parameter can be used
+ *         for reclaiming the space that wasn't used for the descriptor.
+ *
+ * Note: descbuf must be large enough to contain a full 256 byte long
+ * descriptor; after the function returns, by subtracting the actual number of
+ * bytes used, the user can reuse the remaining buffer space for other purposes.
+ */
+static inline int
+cnstr_shdsc_pdcp_u_plane_encap(uint32_t *descbuf,
+			       bool ps,
+			       bool swap,
+			       enum pdcp_sn_size sn_size,
+			       uint32_t hfn,
+			       unsigned short bearer,
+			       unsigned short direction,
+			       uint32_t hfn_threshold,
+			       struct alginfo *cipherdata,
+			       unsigned char era_2_sw_hfn_ovrd)
+{
+	struct program prg;
+	struct program *p = &prg;
+	int err;
+	LABEL(pdb_end);
+
+	if (rta_sec_era != RTA_SEC_ERA_2 && era_2_sw_hfn_ovrd) {
+		pr_err("Cannot select SW HFN ovrd for other era than 2");
+		return -EINVAL;
+	}
+
+	PROGRAM_CNTXT_INIT(p, descbuf, 0);
+	if (swap)
+		PROGRAM_SET_BSWAP(p);
+	if (ps)
+		PROGRAM_SET_36BIT_ADDR(p);
+
+	SHR_HDR(p, SHR_ALWAYS, 0, 0);
+	if (cnstr_pdcp_u_plane_pdb(p, sn_size, hfn, bearer, direction,
+				   hfn_threshold)) {
+		pr_err("Error creating PDCP UPlane PDB\n");
+		return -EINVAL;
+	}
+	SET_LABEL(p, pdb_end);
+
+	err = insert_hfn_ov_op(p, sn_size, PDCP_PDB_TYPE_FULL_PDB,
+			       era_2_sw_hfn_ovrd);
+	if (err)
+		return err;
+
+	switch (sn_size) {
+	case PDCP_SN_SIZE_7:
+	case PDCP_SN_SIZE_12:
+		switch (cipherdata->algtype) {
+		case PDCP_CIPHER_TYPE_ZUC:
+			if (rta_sec_era < RTA_SEC_ERA_5) {
+				pr_err("Invalid era for selected algorithm\n");
+				return -ENOTSUP;
+			}
+		case PDCP_CIPHER_TYPE_AES:
+		case PDCP_CIPHER_TYPE_SNOW:
+			/* Insert Cipher Key */
+			KEY(p, KEY1, cipherdata->key_enc_flags,
+			    (uint64_t)cipherdata->key, cipherdata->keylen,
+			    INLINE_KEY(cipherdata));
+			PROTOCOL(p, OP_TYPE_ENCAP_PROTOCOL,
+				 OP_PCLID_LTE_PDCP_USER,
+				 (uint16_t)cipherdata->algtype);
+			break;
+		case PDCP_CIPHER_TYPE_NULL:
+			insert_copy_frame_op(p,
+					     cipherdata,
+					     OP_TYPE_ENCAP_PROTOCOL);
+			break;
+		default:
+			pr_err("%s: Invalid encrypt algorithm selected: %d\n",
+			       "cnstr_pcl_shdsc_pdcp_u_plane_decap",
+			       cipherdata->algtype);
+			return -EINVAL;
+		}
+		break;
+
+	case PDCP_SN_SIZE_15:
+		switch (cipherdata->algtype) {
+		case PDCP_CIPHER_TYPE_NULL:
+			insert_copy_frame_op(p,
+					     cipherdata,
+					     OP_TYPE_ENCAP_PROTOCOL);
+			break;
+
+		default:
+			err = pdcp_insert_uplane_15bit_op(p, swap, cipherdata,
+				OP_TYPE_ENCAP_PROTOCOL);
+			if (err)
+				return err;
+			break;
+		}
+		break;
+
+	case PDCP_SN_SIZE_5:
+	default:
+		pr_err("Invalid SN size selected\n");
+		return -ENOTSUP;
+	}
+
+	PATCH_HDR(p, 0, pdb_end);
+	return PROGRAM_FINALIZE(p);
+}
+
+/**
+ * cnstr_shdsc_pdcp_u_plane_decap - Function for creating a PDCP User Plane
+ *                                  decapsulation descriptor.
+ * @descbuf: pointer to buffer for descriptor construction
+ * @ps: if 36/40bit addressing is desired, this parameter must be true
+ * @swap: must be true when core endianness doesn't match SEC endianness
+ * @sn_size: selects Sequence Number Size: 7/12/15 bits
+ * @hfn: starting Hyper Frame Number to be used together with the SN from the
+ *       PDCP frames.
+ * @bearer: radio bearer ID
+ * @direction: the direction of the PDCP frame (UL/DL)
+ * @hfn_threshold: HFN value that once reached triggers a warning from SEC that
+ *                 keys should be renegotiated at the earliest convenience.
+ * @cipherdata: pointer to block cipher transform definitions
+ *              Valid algorithm values are those from cipher_type_pdcp enum.
+ * @era_2_sw_hfn_ovrd: if software HFN override mechanism is desired for
+ *                     this descriptor. Note: Can only be used for
+ *                     SEC ERA 2.
+ *
+ * Return: size of descriptor written in words or negative number on error.
+ *         Once the function returns, the value of this parameter can be used
+ *         for reclaiming the space that wasn't used for the descriptor.
+ *
+ * Note: descbuf must be large enough to contain a full 256 byte long
+ * descriptor; after the function returns, by subtracting the actual number of
+ * bytes used, the user can reuse the remaining buffer space for other purposes.
+ */
+static inline int
+cnstr_shdsc_pdcp_u_plane_decap(uint32_t *descbuf,
+			       bool ps,
+			       bool swap,
+			       enum pdcp_sn_size sn_size,
+			       uint32_t hfn,
+			       unsigned short bearer,
+			       unsigned short direction,
+			       uint32_t hfn_threshold,
+			       struct alginfo *cipherdata,
+			       unsigned char era_2_sw_hfn_ovrd)
+{
+	struct program prg;
+	struct program *p = &prg;
+	int err;
+	LABEL(pdb_end);
+
+	if (rta_sec_era != RTA_SEC_ERA_2 && era_2_sw_hfn_ovrd) {
+		pr_err("Cannot select SW HFN override for other era than 2");
+		return -EINVAL;
+	}
+
+	PROGRAM_CNTXT_INIT(p, descbuf, 0);
+	if (swap)
+		PROGRAM_SET_BSWAP(p);
+	if (ps)
+		PROGRAM_SET_36BIT_ADDR(p);
+
+	SHR_HDR(p, SHR_ALWAYS, 0, 0);
+	if (cnstr_pdcp_u_plane_pdb(p, sn_size, hfn, bearer, direction,
+				   hfn_threshold)) {
+		pr_err("Error creating PDCP UPlane PDB\n");
+		return -EINVAL;
+	}
+	SET_LABEL(p, pdb_end);
+
+	err = insert_hfn_ov_op(p, sn_size, PDCP_PDB_TYPE_FULL_PDB,
+			       era_2_sw_hfn_ovrd);
+	if (err)
+		return err;
+
+	switch (sn_size) {
+	case PDCP_SN_SIZE_7:
+	case PDCP_SN_SIZE_12:
+		switch (cipherdata->algtype) {
+		case PDCP_CIPHER_TYPE_ZUC:
+			if (rta_sec_era < RTA_SEC_ERA_5) {
+				pr_err("Invalid era for selected algorithm\n");
+				return -ENOTSUP;
+			}
+		case PDCP_CIPHER_TYPE_AES:
+		case PDCP_CIPHER_TYPE_SNOW:
+			/* Insert Cipher Key */
+			KEY(p, KEY1, cipherdata->key_enc_flags,
+			    cipherdata->key, cipherdata->keylen,
+			    INLINE_KEY(cipherdata));
+			PROTOCOL(p, OP_TYPE_DECAP_PROTOCOL,
+				 OP_PCLID_LTE_PDCP_USER,
+				 (uint16_t)cipherdata->algtype);
+			break;
+		case PDCP_CIPHER_TYPE_NULL:
+			insert_copy_frame_op(p,
+					     cipherdata,
+					     OP_TYPE_DECAP_PROTOCOL);
+			break;
+		default:
+			pr_err("%s: Invalid encrypt algorithm selected: %d\n",
+			       "cnstr_pcl_shdsc_pdcp_u_plane_decap",
+			       cipherdata->algtype);
+			return -EINVAL;
+		}
+		break;
+
+	case PDCP_SN_SIZE_15:
+		switch (cipherdata->algtype) {
+		case PDCP_CIPHER_TYPE_NULL:
+			insert_copy_frame_op(p,
+					     cipherdata,
+					     OP_TYPE_DECAP_PROTOCOL);
+			break;
+
+		default:
+			err = pdcp_insert_uplane_15bit_op(p, swap, cipherdata,
+				OP_TYPE_DECAP_PROTOCOL);
+			if (err)
+				return err;
+			break;
+		}
+		break;
+
+	case PDCP_SN_SIZE_5:
+	default:
+		pr_err("Invalid SN size selected\n");
+		return -ENOTSUP;
+	}
+
+	PATCH_HDR(p, 0, pdb_end);
+	return PROGRAM_FINALIZE(p);
+}
+
+/**
+ * cnstr_shdsc_pdcp_short_mac - Function for creating a PDCP Short MAC
+ *                              descriptor.
+ * @descbuf: pointer to buffer for descriptor construction
+ * @ps: if 36/40bit addressing is desired, this parameter must be true
+ * @swap: must be true when core endianness doesn't match SEC endianness
+ * @authdata: pointer to authentication transform definitions
+ *            Valid algorithm values are those from auth_type_pdcp enum.
+ *
+ * Return: size of descriptor written in words or negative number on error.
+ *         Once the function returns, the value of this parameter can be used
+ *         for reclaiming the space that wasn't used for the descriptor.
+ *
+ * Note: descbuf must be large enough to contain a full 256 byte long
+ * descriptor; after the function returns, by subtracting the actual number of
+ * bytes used, the user can reuse the remaining buffer space for other purposes.
+ */
+static inline int
+cnstr_shdsc_pdcp_short_mac(uint32_t *descbuf,
+			   bool ps,
+			   bool swap,
+			   struct alginfo *authdata)
+{
+	struct program prg;
+	struct program *p = &prg;
+	uint32_t iv[3] = {0, 0, 0};
+	LABEL(local_offset);
+	REFERENCE(move_cmd_read_descbuf);
+	REFERENCE(move_cmd_write_descbuf);
+
+	PROGRAM_CNTXT_INIT(p, descbuf, 0);
+	if (swap)
+		PROGRAM_SET_BSWAP(p);
+	if (ps)
+		PROGRAM_SET_36BIT_ADDR(p);
+
+	SHR_HDR(p, SHR_ALWAYS, 1, 0);
+
+	if (rta_sec_era > RTA_SEC_ERA_2) {
+		MATHB(p, SEQINSZ, SUB, ZERO, VSEQINSZ, 4, 0);
+		MATHB(p, SEQINSZ, SUB, ZERO, MATH1, 4, 0);
+	} else {
+		MATHB(p, SEQINSZ, ADD, ONE, MATH1, 4, 0);
+		MATHB(p, MATH1, SUB, ONE, MATH1, 4, 0);
+		MATHB(p, ZERO, ADD, MATH1, VSEQINSZ, 4, 0);
+		MOVE(p, MATH1, 0, MATH0, 0, 8, IMMED);
+
+		/*
+		 * Since MOVELEN is available only starting with
+		 * SEC ERA 3, use poor man's MOVELEN: create a MOVE
+		 * command dynamically by writing the length from M1 by
+		 * OR-ing the command in the M1 register and MOVE the
+		 * result into the descriptor buffer. Care must be taken
+		 * wrt. the location of the command because of SEC
+		 * pipelining. The actual MOVEs are written at the end
+		 * of the descriptor due to calculations needed on the
+		 * offset in the descriptor for the MOVE command.
+		 */
+		move_cmd_read_descbuf = MOVE(p, DESCBUF, 0, MATH0, 0, 6,
+					     IMMED);
+		move_cmd_write_descbuf = MOVE(p, MATH0, 0, DESCBUF, 0, 8,
+					      WAITCOMP | IMMED);
+	}
+	MATHB(p, ZERO, ADD, MATH1, VSEQOUTSZ, 4, 0);
+
+	switch (authdata->algtype) {
+	case PDCP_AUTH_TYPE_NULL:
+		SEQFIFOSTORE(p, MSG, 0, 0, VLF);
+		if (rta_sec_era > RTA_SEC_ERA_2) {
+			MOVE(p, AB1, 0, OFIFO, 0, MATH1, 0);
+		} else {
+			SET_LABEL(p, local_offset);
+
+			/* Shut off automatic Info FIFO entries */
+			LOAD(p, 0, DCTRL, LDOFF_DISABLE_AUTO_NFIFO, 0, IMMED);
+
+			/* Placeholder for MOVE command with length from M1
+			 * register
+			 */
+			MOVE(p, IFIFOAB1, 0, OFIFO, 0, 0, IMMED);
+
+			/* Enable automatic Info FIFO entries */
+			LOAD(p, 0, DCTRL, LDOFF_ENABLE_AUTO_NFIFO, 0, IMMED);
+		}
+
+		LOAD(p, (uintptr_t)iv, MATH0, 0, 8, IMMED | COPY);
+		SEQFIFOLOAD(p, MSG1, 0, VLF | LAST1 | LAST2 | FLUSH1);
+		SEQSTORE(p, MATH0, 0, 4, 0);
+
+		break;
+
+	case PDCP_AUTH_TYPE_SNOW:
+		iv[0] = 0xFFFFFFFF;
+		iv[1] = swap ? swab32(0x04000000) : 0x04000000;
+		iv[2] = swap ? swab32(0xF8000000) : 0xF8000000;
+
+		KEY(p, KEY2, authdata->key_enc_flags, authdata->key,
+		    authdata->keylen, INLINE_KEY(authdata));
+		LOAD(p, (uintptr_t)&iv, CONTEXT2, 0, 12, IMMED | COPY);
+		ALG_OPERATION(p, OP_ALG_ALGSEL_SNOW_F9,
+			      OP_ALG_AAI_F9,
+			      OP_ALG_AS_INITFINAL,
+			      ICV_CHECK_DISABLE,
+			      DIR_ENC);
+		SEQFIFOSTORE(p, MSG, 0, 0, VLF);
+
+		if (rta_sec_era > RTA_SEC_ERA_2) {
+			MOVE(p, AB1, 0, OFIFO, 0, MATH1, 0);
+		} else {
+			SET_LABEL(p, local_offset);
+
+
+			/* Shut off automatic Info FIFO entries */
+			LOAD(p, 0, DCTRL, LDOFF_DISABLE_AUTO_NFIFO, 0, IMMED);
+
+			/* Placeholder for MOVE command with length from M1
+			 * register
+			 */
+			MOVE(p, IFIFOAB1, 0, OFIFO, 0, 0, IMMED);
+
+			/* Enable automatic Info FIFO entries */
+			LOAD(p, 0, DCTRL, LDOFF_ENABLE_AUTO_NFIFO, 0, IMMED);
+		}
+		SEQFIFOLOAD(p, MSGINSNOOP, 0, VLF | LAST1 | LAST2 | FLUSH1);
+		SEQSTORE(p, CONTEXT2, 0, 4, 0);
+
+		break;
+
+	case PDCP_AUTH_TYPE_AES:
+		iv[0] = 0xFFFFFFFF;
+		iv[1] = swap ? swab32(0xFC000000) : 0xFC000000;
+		iv[2] = 0x00000000; /* unused */
+
+		KEY(p, KEY1, authdata->key_enc_flags, authdata->key,
+		    authdata->keylen, INLINE_KEY(authdata));
+		LOAD(p, (uintptr_t)&iv, MATH0, 0, 8, IMMED | COPY);
+		MOVE(p, MATH0, 0, IFIFOAB1, 0, 8, IMMED);
+		ALG_OPERATION(p, OP_ALG_ALGSEL_AES,
+			      OP_ALG_AAI_CMAC,
+			      OP_ALG_AS_INITFINAL,
+			      ICV_CHECK_DISABLE,
+			      DIR_ENC);
+		SEQFIFOSTORE(p, MSG, 0, 0, VLF);
+
+		if (rta_sec_era > RTA_SEC_ERA_2) {
+			MOVE(p, AB2, 0, OFIFO, 0, MATH1, 0);
+		} else {
+			SET_LABEL(p, local_offset);
+
+			/* Shut off automatic Info FIFO entries */
+			LOAD(p, 0, DCTRL, LDOFF_DISABLE_AUTO_NFIFO, 0, IMMED);
+
+			/* Placeholder for MOVE command with length from M1
+			 * register
+			 */
+			MOVE(p, IFIFOAB2, 0, OFIFO, 0, 0, IMMED);
+
+			/* Enable automatic Info FIFO entries */
+			LOAD(p, 0, DCTRL, LDOFF_ENABLE_AUTO_NFIFO, 0, IMMED);
+		}
+		SEQFIFOLOAD(p, MSGINSNOOP, 0, VLF | LAST1 | LAST2 | FLUSH1);
+		SEQSTORE(p, CONTEXT1, 0, 4, 0);
+
+		break;
+
+	case PDCP_AUTH_TYPE_ZUC:
+		if (rta_sec_era < RTA_SEC_ERA_5) {
+			pr_err("Invalid era for selected algorithm\n");
+			return -ENOTSUP;
+		}
+		iv[0] = 0xFFFFFFFF;
+		iv[1] = swap ? swab32(0xFC000000) : 0xFC000000;
+		iv[2] = 0x00000000; /* unused */
+
+		KEY(p, KEY2, authdata->key_enc_flags, authdata->key,
+		    authdata->keylen, INLINE_KEY(authdata));
+		LOAD(p, (uintptr_t)&iv, CONTEXT2, 0, 12, IMMED | COPY);
+		ALG_OPERATION(p, OP_ALG_ALGSEL_ZUCA,
+			      OP_ALG_AAI_F9,
+			      OP_ALG_AS_INITFINAL,
+			      ICV_CHECK_DISABLE,
+			      DIR_ENC);
+		SEQFIFOSTORE(p, MSG, 0, 0, VLF);
+		MOVE(p, AB1, 0, OFIFO, 0, MATH1, 0);
+		SEQFIFOLOAD(p, MSGINSNOOP, 0, VLF | LAST1 | LAST2 | FLUSH1);
+		SEQSTORE(p, CONTEXT2, 0, 4, 0);
+
+		break;
+
+	default:
+		pr_err("%s: Invalid integrity algorithm selected: %d\n",
+		       "cnstr_shdsc_pdcp_short_mac", authdata->algtype);
+		return -EINVAL;
+	}
+
+
+	if (rta_sec_era < RTA_SEC_ERA_3) {
+		PATCH_MOVE(p, move_cmd_read_descbuf, local_offset);
+		PATCH_MOVE(p, move_cmd_write_descbuf, local_offset);
+	}
+
+	return PROGRAM_FINALIZE(p);
+}
+
+#endif /* __DESC_PDCP_H__ */
-- 
2.17.1

^ permalink raw reply	[flat|nested] 41+ messages in thread

* [dpdk-dev] [PATCH v4 3/3] crypto/dpaa2_sec: support pdcp offload
  2018-10-15 12:53     ` [dpdk-dev] [PATCH v4 0/3] security: support for pdcp Akhil Goyal
  2018-10-15 12:53       ` [dpdk-dev] [PATCH v4 1/3] security: support pdcp protocol Akhil Goyal
  2018-10-15 12:53       ` [dpdk-dev] [PATCH v4 2/3] crypto/dpaa2_sec: add sample pdcp descriptor apis Akhil Goyal
@ 2018-10-15 12:53       ` Akhil Goyal
  2018-10-16 10:38       ` [dpdk-dev] [PATCH v5 0/3] security: support for pdcp Akhil Goyal
  3 siblings, 0 replies; 41+ messages in thread
From: Akhil Goyal @ 2018-10-15 12:53 UTC (permalink / raw)
  To: dev
  Cc: pablo.de.lara.guarch, radu.nicolau, jerin.jacob,
	narayanaprasad.athreya, Shally.Verma, Anoob.Joseph,
	Vidya.Velumuri, Hemant Agrawal, Akhil Goyal

From: Akhil Goyal <akhil.goyal@nxp.com>

PDCP session configuration for lookaside protocol offload
and data path is added.

Signed-off-by: Hemant Agrawal <hemant.agrawal@nxp.com>
Signed-off-by: Akhil Goyal <akhil.goyal@nxp.com>
---
 drivers/crypto/dpaa2_sec/dpaa2_sec_dpseci.c | 257 ++++++++++++++++++++
 drivers/crypto/dpaa2_sec/dpaa2_sec_priv.h   | 208 +++++++++++++++-
 2 files changed, 457 insertions(+), 8 deletions(-)

diff --git a/drivers/crypto/dpaa2_sec/dpaa2_sec_dpseci.c b/drivers/crypto/dpaa2_sec/dpaa2_sec_dpseci.c
index 0336d5f4b..fe769a932 100644
--- a/drivers/crypto/dpaa2_sec/dpaa2_sec_dpseci.c
+++ b/drivers/crypto/dpaa2_sec/dpaa2_sec_dpseci.c
@@ -35,6 +35,7 @@ typedef uint64_t	dma_addr_t;
 
 /* RTA header files */
 #include <hw/desc/ipsec.h>
+#include <hw/desc/pdcp.h>
 #include <hw/desc/algo.h>
 
 /* Minimum job descriptor consists of a oneword job descriptor HEADER and
@@ -74,6 +75,9 @@ build_proto_compound_fd(dpaa2_sec_session *sess,
 	struct rte_mbuf *dst_mbuf = sym_op->m_dst;
 	int retval;
 
+	if (!dst_mbuf)
+		dst_mbuf = src_mbuf;
+
 	/* Save the shared descriptor */
 	flc = &priv->flc_desc[0].flc;
 
@@ -118,6 +122,15 @@ build_proto_compound_fd(dpaa2_sec_session *sess,
 	DPAA2_SET_FD_LEN(fd, ip_fle->length);
 	DPAA2_SET_FLE_FIN(ip_fle);
 
+#ifdef ENABLE_HFN_OVERRIDE
+	if (sess->ctxt_type == DPAA2_SEC_PDCP && sess->pdcp.hfn_ovd) {
+		/*enable HFN override override */
+		DPAA2_SET_FLE_INTERNAL_JD(ip_fle, sess->pdcp.hfn_ovd);
+		DPAA2_SET_FLE_INTERNAL_JD(op_fle, sess->pdcp.hfn_ovd);
+		DPAA2_SET_FD_INTERNAL_JD(fd, sess->pdcp.hfn_ovd);
+	}
+#endif
+
 	return 0;
 
 }
@@ -1188,6 +1201,9 @@ build_sec_fd(struct rte_crypto_op *op,
 		case DPAA2_SEC_IPSEC:
 			ret = build_proto_fd(sess, op, fd, bpid);
 			break;
+		case DPAA2_SEC_PDCP:
+			ret = build_proto_compound_fd(sess, op, fd, bpid);
+			break;
 		case DPAA2_SEC_HASH_CIPHER:
 		default:
 			DPAA2_SEC_ERR("error: Unsupported session");
@@ -2551,6 +2567,243 @@ dpaa2_sec_set_ipsec_session(struct rte_cryptodev *dev,
 	return ret;
 }
 
+static int
+dpaa2_sec_set_pdcp_session(struct rte_cryptodev *dev,
+			   struct rte_security_session_conf *conf,
+			   void *sess)
+{
+	struct rte_security_pdcp_xform *pdcp_xform = &conf->pdcp;
+	struct rte_crypto_sym_xform *xform = conf->crypto_xform;
+	struct rte_crypto_auth_xform *auth_xform = NULL;
+	struct rte_crypto_cipher_xform *cipher_xform;
+	dpaa2_sec_session *session = (dpaa2_sec_session *)sess;
+	struct ctxt_priv *priv;
+	struct dpaa2_sec_dev_private *dev_priv = dev->data->dev_private;
+	struct alginfo authdata, cipherdata;
+	int bufsize = -1;
+	struct sec_flow_context *flc;
+#if RTE_BYTE_ORDER == RTE_BIG_ENDIAN
+	int swap = true;
+#else
+	int swap = false;
+#endif
+
+	PMD_INIT_FUNC_TRACE();
+
+	memset(session, 0, sizeof(dpaa2_sec_session));
+
+	priv = (struct ctxt_priv *)rte_zmalloc(NULL,
+				sizeof(struct ctxt_priv) +
+				sizeof(struct sec_flc_desc),
+				RTE_CACHE_LINE_SIZE);
+
+	if (priv == NULL) {
+		DPAA2_SEC_ERR("No memory for priv CTXT");
+		return -ENOMEM;
+	}
+
+	priv->fle_pool = dev_priv->fle_pool;
+	flc = &priv->flc_desc[0].flc;
+
+	/* find xfrm types */
+	if (xform->type == RTE_CRYPTO_SYM_XFORM_CIPHER && xform->next == NULL) {
+		cipher_xform = &xform->cipher;
+	} else if (xform->type == RTE_CRYPTO_SYM_XFORM_CIPHER &&
+		   xform->next->type == RTE_CRYPTO_SYM_XFORM_AUTH) {
+		session->ext_params.aead_ctxt.auth_cipher_text = true;
+		cipher_xform = &xform->cipher;
+		auth_xform = &xform->next->auth;
+	} else if (xform->type == RTE_CRYPTO_SYM_XFORM_AUTH &&
+		   xform->next->type == RTE_CRYPTO_SYM_XFORM_CIPHER) {
+		session->ext_params.aead_ctxt.auth_cipher_text = false;
+		cipher_xform = &xform->next->cipher;
+		auth_xform = &xform->auth;
+	} else {
+		DPAA2_SEC_ERR("Invalid crypto type");
+		return -EINVAL;
+	}
+
+	session->ctxt_type = DPAA2_SEC_PDCP;
+	if (cipher_xform) {
+		session->cipher_key.data = rte_zmalloc(NULL,
+					       cipher_xform->key.length,
+					       RTE_CACHE_LINE_SIZE);
+		if (session->cipher_key.data == NULL &&
+				cipher_xform->key.length > 0) {
+			DPAA2_SEC_ERR("No Memory for cipher key");
+			rte_free(priv);
+			return -ENOMEM;
+		}
+		session->cipher_key.length = cipher_xform->key.length;
+		memcpy(session->cipher_key.data, cipher_xform->key.data,
+			cipher_xform->key.length);
+		session->dir = (cipher_xform->op == RTE_CRYPTO_CIPHER_OP_ENCRYPT) ?
+					DIR_ENC : DIR_DEC;
+		session->cipher_alg = cipher_xform->algo;
+	} else {
+		session->cipher_key.data = NULL;
+		session->cipher_key.length = 0;
+		session->cipher_alg = RTE_CRYPTO_CIPHER_NULL;
+		session->dir = DIR_ENC;
+	}
+
+	session->pdcp.domain = pdcp_xform->domain;
+	session->pdcp.bearer = pdcp_xform->bearer;
+	session->pdcp.pkt_dir = pdcp_xform->pkt_dir;
+	session->pdcp.sn_size = pdcp_xform->sn_size;
+#ifdef ENABLE_HFN_OVERRIDE
+	session->pdcp.hfn_ovd = pdcp_xform->hfn_ovd;
+#endif
+	session->pdcp.hfn = pdcp_xform->hfn;
+	session->pdcp.hfn_threshold = pdcp_xform->hfn_threshold;
+
+	cipherdata.key = (size_t)session->cipher_key.data;
+	cipherdata.keylen = session->cipher_key.length;
+	cipherdata.key_enc_flags = 0;
+	cipherdata.key_type = RTA_DATA_IMM;
+
+	switch (session->cipher_alg) {
+	case RTE_CRYPTO_CIPHER_SNOW3G_UEA2:
+		cipherdata.algtype = PDCP_CIPHER_TYPE_SNOW;
+		break;
+	case RTE_CRYPTO_CIPHER_ZUC_EEA3:
+		cipherdata.algtype = PDCP_CIPHER_TYPE_ZUC;
+		break;
+	case RTE_CRYPTO_CIPHER_AES_CTR:
+		cipherdata.algtype = PDCP_CIPHER_TYPE_AES;
+		break;
+	case RTE_CRYPTO_CIPHER_NULL:
+		cipherdata.algtype = PDCP_CIPHER_TYPE_NULL;
+		break;
+	default:
+		DPAA2_SEC_ERR("Crypto: Undefined Cipher specified %u",
+			      session->cipher_alg);
+		goto out;
+	}
+
+	/* Auth is only applicable for control mode operation. */
+	if (pdcp_xform->domain == RTE_SECURITY_PDCP_MODE_CONTROL) {
+		if (pdcp_xform->sn_size != RTE_SECURITY_PDCP_SN_SIZE_5) {
+			DPAA2_SEC_ERR(
+				"PDCP Seq Num size should be 5 bits for cmode");
+			goto out;
+		}
+		if (auth_xform) {
+			session->auth_key.data = rte_zmalloc(NULL,
+							auth_xform->key.length,
+							RTE_CACHE_LINE_SIZE);
+			if (session->auth_key.data == NULL &&
+					auth_xform->key.length > 0) {
+				DPAA2_SEC_ERR("No Memory for auth key");
+				rte_free(session->cipher_key.data);
+				rte_free(priv);
+				return -ENOMEM;
+			}
+			session->auth_key.length = auth_xform->key.length;
+			memcpy(session->auth_key.data, auth_xform->key.data,
+					auth_xform->key.length);
+			session->auth_alg = auth_xform->algo;
+		} else {
+			session->auth_key.data = NULL;
+			session->auth_key.length = 0;
+			session->auth_alg = RTE_CRYPTO_AUTH_NULL;
+		}
+		authdata.key = (size_t)session->auth_key.data;
+		authdata.keylen = session->auth_key.length;
+		authdata.key_enc_flags = 0;
+		authdata.key_type = RTA_DATA_IMM;
+
+		switch (session->auth_alg) {
+		case RTE_CRYPTO_AUTH_SNOW3G_UIA2:
+			authdata.algtype = PDCP_AUTH_TYPE_SNOW;
+			break;
+		case RTE_CRYPTO_AUTH_ZUC_EIA3:
+			authdata.algtype = PDCP_AUTH_TYPE_ZUC;
+			break;
+		case RTE_CRYPTO_AUTH_AES_CMAC:
+			authdata.algtype = PDCP_AUTH_TYPE_AES;
+			break;
+		case RTE_CRYPTO_AUTH_NULL:
+			authdata.algtype = PDCP_AUTH_TYPE_NULL;
+			break;
+		default:
+			DPAA2_SEC_ERR("Crypto: Unsupported auth alg %u",
+				      session->auth_alg);
+			goto out;
+		}
+
+		if (session->dir == DIR_ENC)
+			bufsize = cnstr_shdsc_pdcp_c_plane_encap(
+					priv->flc_desc[0].desc, 1, swap,
+					pdcp_xform->hfn,
+					pdcp_xform->bearer,
+					pdcp_xform->pkt_dir,
+					pdcp_xform->hfn_threshold,
+					&cipherdata, &authdata,
+					0);
+		else if (session->dir == DIR_DEC)
+			bufsize = cnstr_shdsc_pdcp_c_plane_decap(
+					priv->flc_desc[0].desc, 1, swap,
+					pdcp_xform->hfn,
+					pdcp_xform->bearer,
+					pdcp_xform->pkt_dir,
+					pdcp_xform->hfn_threshold,
+					&cipherdata, &authdata,
+					0);
+	} else {
+		if (session->dir == DIR_ENC)
+			bufsize = cnstr_shdsc_pdcp_u_plane_encap(
+					priv->flc_desc[0].desc, 1, swap,
+					pdcp_xform->sn_size,
+					pdcp_xform->hfn,
+					pdcp_xform->bearer,
+					pdcp_xform->pkt_dir,
+					pdcp_xform->hfn_threshold,
+					&cipherdata, 0);
+		else if (session->dir == DIR_DEC)
+			bufsize = cnstr_shdsc_pdcp_u_plane_decap(
+					priv->flc_desc[0].desc, 1, swap,
+					pdcp_xform->sn_size,
+					pdcp_xform->hfn,
+					pdcp_xform->bearer,
+					pdcp_xform->pkt_dir,
+					pdcp_xform->hfn_threshold,
+					&cipherdata, 0);
+	}
+
+	if (bufsize < 0) {
+		DPAA2_SEC_ERR("Crypto: Invalid buffer length");
+		goto out;
+	}
+
+	/* Enable the stashing control bit */
+	DPAA2_SET_FLC_RSC(flc);
+	flc->word2_rflc_31_0 = lower_32_bits(
+			(size_t)&(((struct dpaa2_sec_qp *)
+			dev->data->queue_pairs[0])->rx_vq) | 0x14);
+	flc->word3_rflc_63_32 = upper_32_bits(
+			(size_t)&(((struct dpaa2_sec_qp *)
+			dev->data->queue_pairs[0])->rx_vq));
+
+	flc->word1_sdl = (uint8_t)bufsize;
+
+	/* Set EWS bit i.e. enable write-safe */
+	DPAA2_SET_FLC_EWS(flc);
+	/* Set BS = 1 i.e reuse input buffers as output buffers */
+	DPAA2_SET_FLC_REUSE_BS(flc);
+	/* Set FF = 10; reuse input buffers if they provide sufficient space */
+	DPAA2_SET_FLC_REUSE_FF(flc);
+
+	session->ctxt = priv;
+
+	return 0;
+out:
+	rte_free(session->auth_key.data);
+	rte_free(session->cipher_key.data);
+	rte_free(priv);
+	return -1;
+}
+
 static int
 dpaa2_sec_security_session_create(void *dev,
 				  struct rte_security_session_conf *conf,
@@ -2573,6 +2826,10 @@ dpaa2_sec_security_session_create(void *dev,
 		break;
 	case RTE_SECURITY_PROTOCOL_MACSEC:
 		return -ENOTSUP;
+	case RTE_SECURITY_PROTOCOL_PDCP:
+		ret = dpaa2_sec_set_pdcp_session(cdev, conf,
+				sess_private_data);
+		break;
 	default:
 		return -EINVAL;
 	}
diff --git a/drivers/crypto/dpaa2_sec/dpaa2_sec_priv.h b/drivers/crypto/dpaa2_sec/dpaa2_sec_priv.h
index bce9633c0..51751103d 100644
--- a/drivers/crypto/dpaa2_sec/dpaa2_sec_priv.h
+++ b/drivers/crypto/dpaa2_sec/dpaa2_sec_priv.h
@@ -137,6 +137,19 @@ struct dpaa2_sec_aead_ctxt {
 	uint8_t auth_cipher_text;       /**< Authenticate/cipher ordering */
 };
 
+/*
+ * The structure is to be filled by user for PDCP Protocol
+ */
+struct dpaa2_pdcp_ctxt {
+	enum rte_security_pdcp_domain domain; /*!< Data/Control mode*/
+	int8_t bearer;	/*!< PDCP bearer ID */
+	int8_t pkt_dir;/*!< PDCP Frame Direction 0:UL 1:DL*/
+	int8_t hfn_ovd;/*!< Overwrite HFN per packet*/
+	uint32_t hfn;	/*!< Hyper Frame Number */
+	uint32_t hfn_threshold;	/*!< HFN Threashold for key renegotiation */
+	uint8_t sn_size;	/*!< Sequence number size, 7/12/15 */
+};
+
 typedef struct dpaa2_sec_session_entry {
 	void *ctxt;
 	uint8_t ctxt_type;
@@ -160,15 +173,20 @@ typedef struct dpaa2_sec_session_entry {
 			} auth_key;
 		};
 	};
-	struct {
-		uint16_t length; /**< IV length in bytes */
-		uint16_t offset; /**< IV offset in bytes */
-	} iv;
-	uint16_t digest_length;
-	uint8_t status;
 	union {
-		struct dpaa2_sec_aead_ctxt aead_ctxt;
-	} ext_params;
+		struct {
+			struct {
+				uint16_t length; /**< IV length in bytes */
+				uint16_t offset; /**< IV offset in bytes */
+			} iv;
+			uint16_t digest_length;
+			uint8_t status;
+			union {
+				struct dpaa2_sec_aead_ctxt aead_ctxt;
+			} ext_params;
+		};
+		struct dpaa2_pdcp_ctxt pdcp;
+	};
 } dpaa2_sec_session;
 
 static const struct rte_cryptodev_capabilities dpaa2_sec_capabilities[] = {
@@ -392,6 +410,162 @@ static const struct rte_cryptodev_capabilities dpaa2_sec_capabilities[] = {
 	RTE_CRYPTODEV_END_OF_CAPABILITIES_LIST()
 };
 
+static const struct rte_cryptodev_capabilities dpaa2_pdcp_capabilities[] = {
+	{	/* SNOW 3G (UIA2) */
+		.op = RTE_CRYPTO_OP_TYPE_SYMMETRIC,
+		{.sym = {
+			.xform_type = RTE_CRYPTO_SYM_XFORM_AUTH,
+			{.auth = {
+				.algo = RTE_CRYPTO_AUTH_SNOW3G_UIA2,
+				.block_size = 16,
+				.key_size = {
+					.min = 16,
+					.max = 16,
+					.increment = 0
+				},
+				.digest_size = {
+					.min = 4,
+					.max = 4,
+					.increment = 0
+				},
+				.iv_size = {
+					.min = 16,
+					.max = 16,
+					.increment = 0
+				}
+			}, }
+		}, }
+	},
+	{	/* SNOW 3G (UEA2) */
+		.op = RTE_CRYPTO_OP_TYPE_SYMMETRIC,
+		{.sym = {
+			.xform_type = RTE_CRYPTO_SYM_XFORM_CIPHER,
+			{.cipher = {
+				.algo = RTE_CRYPTO_CIPHER_SNOW3G_UEA2,
+				.block_size = 16,
+				.key_size = {
+					.min = 16,
+					.max = 16,
+					.increment = 0
+				},
+				.iv_size = {
+					.min = 16,
+					.max = 16,
+					.increment = 0
+				}
+			}, }
+		}, }
+	},
+	{	/* AES CTR */
+		.op = RTE_CRYPTO_OP_TYPE_SYMMETRIC,
+		{.sym = {
+			.xform_type = RTE_CRYPTO_SYM_XFORM_CIPHER,
+			{.cipher = {
+				.algo = RTE_CRYPTO_CIPHER_AES_CTR,
+				.block_size = 16,
+				.key_size = {
+					.min = 16,
+					.max = 32,
+					.increment = 8
+				},
+				.iv_size = {
+					.min = 16,
+					.max = 16,
+					.increment = 0
+				}
+			}, }
+		}, }
+	},
+	{	/* NULL (AUTH) */
+		.op = RTE_CRYPTO_OP_TYPE_SYMMETRIC,
+		{.sym = {
+			.xform_type = RTE_CRYPTO_SYM_XFORM_AUTH,
+			{.auth = {
+				.algo = RTE_CRYPTO_AUTH_NULL,
+				.block_size = 1,
+				.key_size = {
+					.min = 0,
+					.max = 0,
+					.increment = 0
+				},
+				.digest_size = {
+					.min = 0,
+					.max = 0,
+					.increment = 0
+				},
+				.iv_size = { 0 }
+			}, },
+		}, },
+	},
+	{	/* NULL (CIPHER) */
+		.op = RTE_CRYPTO_OP_TYPE_SYMMETRIC,
+		{.sym = {
+			.xform_type = RTE_CRYPTO_SYM_XFORM_CIPHER,
+			{.cipher = {
+				.algo = RTE_CRYPTO_CIPHER_NULL,
+				.block_size = 1,
+				.key_size = {
+					.min = 0,
+					.max = 0,
+					.increment = 0
+				},
+				.iv_size = {
+					.min = 0,
+					.max = 0,
+					.increment = 0
+				}
+			}, },
+		}, }
+	},
+	{	/* ZUC (EEA3) */
+		.op = RTE_CRYPTO_OP_TYPE_SYMMETRIC,
+		{.sym = {
+			.xform_type = RTE_CRYPTO_SYM_XFORM_CIPHER,
+			{.cipher = {
+				.algo = RTE_CRYPTO_CIPHER_ZUC_EEA3,
+				.block_size = 16,
+				.key_size = {
+					.min = 16,
+					.max = 16,
+					.increment = 0
+				},
+				.iv_size = {
+					.min = 16,
+					.max = 16,
+					.increment = 0
+				}
+			}, }
+		}, }
+	},
+	{	/* ZUC (EIA3) */
+		.op = RTE_CRYPTO_OP_TYPE_SYMMETRIC,
+		{.sym = {
+			.xform_type = RTE_CRYPTO_SYM_XFORM_AUTH,
+			{.auth = {
+				.algo = RTE_CRYPTO_AUTH_ZUC_EIA3,
+				.block_size = 16,
+				.key_size = {
+					.min = 16,
+					.max = 16,
+					.increment = 0
+				},
+				.digest_size = {
+					.min = 4,
+					.max = 4,
+					.increment = 0
+				},
+				.iv_size = {
+					.min = 16,
+					.max = 16,
+					.increment = 0
+				}
+			}, }
+		}, }
+	},
+
+	RTE_CRYPTODEV_END_OF_CAPABILITIES_LIST()
+};
+
 static const struct rte_security_capability dpaa2_sec_security_cap[] = {
 	{ /* IPsec Lookaside Protocol offload ESP Transport Egress */
 		.action = RTE_SECURITY_ACTION_TYPE_LOOKASIDE_PROTOCOL,
@@ -415,6 +589,24 @@ static const struct rte_security_capability dpaa2_sec_security_cap[] = {
 		},
 		.crypto_capabilities = dpaa2_sec_capabilities
 	},
+	{ /* PDCP Lookaside Protocol offload Data */
+		.action = RTE_SECURITY_ACTION_TYPE_LOOKASIDE_PROTOCOL,
+		.protocol = RTE_SECURITY_PROTOCOL_PDCP,
+		.pdcp = {
+			.domain = RTE_SECURITY_PDCP_MODE_DATA,
+			.capa_flags = 0
+		},
+		.crypto_capabilities = dpaa2_pdcp_capabilities
+	},
+	{ /* PDCP Lookaside Protocol offload Control */
+		.action = RTE_SECURITY_ACTION_TYPE_LOOKASIDE_PROTOCOL,
+		.protocol = RTE_SECURITY_PROTOCOL_PDCP,
+		.pdcp = {
+			.domain = RTE_SECURITY_PDCP_MODE_CONTROL,
+			.capa_flags = 0
+		},
+		.crypto_capabilities = dpaa2_pdcp_capabilities
+	},
 	{
 		.action = RTE_SECURITY_ACTION_TYPE_NONE
 	}
-- 
2.17.1

^ permalink raw reply	[flat|nested] 41+ messages in thread

* Re: [dpdk-dev] [PATCH 1/3] security: support pdcp protocol
  2018-10-09 11:38           ` Joseph, Anoob
@ 2018-10-15 13:03             ` Akhil Goyal
  2018-10-16  6:27               ` Joseph
  0 siblings, 1 reply; 41+ messages in thread
From: Akhil Goyal @ 2018-10-15 13:03 UTC (permalink / raw)
  To: Joseph, Anoob
  Cc: dev, Declan Doherty, Pablo de Lara, Radu Nicolau, Jerin Jacob,
	Narayana Prasad, Verma, Shally, Vidya Sagar Velumuri



On 10/9/2018 5:08 PM, Joseph, Anoob wrote:
> Hi Akhil,
>
> Please see inline.
>
> Thanks,
> Anoob
> On 08-10-2018 15:19, Akhil Goyal wrote:
>> External Email
>>
>> Hi Anoob,
>>>>>> @@ -494,6 +553,23 @@ IPsec related configuration parameters are
>>>>>> defined in ``rte_security_ipsec_xform
>>>>>>            /**< Tunnel parameters, NULL for transport mode */
>>>>>>        };
>>>>>> +PDCP related configuration parameters are defined in
>>>>>> ``rte_security_pdcp_xform``
>>>>>> +
>>>>>> +.. code-block:: c
>>>>>> +
>>>>>> +    struct rte_security_pdcp_xform {
>>>>>> +        int8_t bearer; /**< PDCP bearer ID */
>>>>>> +        enum rte_security_pdcp_domain domain;
>>>>>> +        /** < PDCP mode of operation: Control or data */
>>>>>> +        enum rte_security_pdcp_direction pkt_dir;
>>>>>> +        /**< PDCP Frame Direction 0:UL 1:DL */
>>>>>> +        enum rte_security_pdcp_sn_size sn_size;
>>>>>> +        /**< Sequence number size, 5/7/12/15 */
>>>>>> +        int8_t hfn_ovd; /**< Overwrite HFN per operation */
>>>>>> +        uint32_t hfn;  /**< Hyper Frame Number */
>>>>>> +        uint32_t hfn_threshold;        /**< HFN Threashold for key
>>>>>> renegotiation */
>>>>>> +    };
>>>>>> +
>>>>> [Anoob] PDCP packet ordering should be both a capability and a 
>>>>> setting.
>>>>> HFN will be incremented overtime and starts at 0. So why is it 
>>>>> part of
>>>>> the xform?
>>>>
>>>> The Security accelerators may assume packet in order. Latest PDCP TS
>>>> suggest to do de-Ciphering before re-Ordering the Rx PDCP PDUs. In 
>>>> this
>>>> situation, the accelerator may use wrong HFN value. The PDCP 
>>>> application
>>>> can provide the appropriate HFN value along with PDU to the security
>>>> accelerator.
>>>>
>>> So what is the expectation with regards to ordering? Would PDCP know
>>> the order or is it unaware of the order?
>>> If implementation of this Spec knows the order of packets(which is
>>> implied by the "In order delivery and Duplicate detection
>>> Sequence Numbering" statement in the PDCP flow diagram), then there
>>> should be no need to override the
>>> HFN. If the implementation does not know the order of packets, then
>>> the flow diagram should be corrected.
>>> Also, is implementation expected to support ordered delivery and
>>> duplicate detection. Perhaps it should be
>>> a capability or 2.
>> This patchset is basically talking about full protocol offload with look
>> aside accelerators.
>> And when we are talking about full protocol offload, all protocol
>> related stuff like ordering, headers etc.
>> needs to be handled by the HW/driver.
>> So the expectation is driver/HW should be able to perform in order
>> delivery and detect duplicates.
> How will errors in these situations be reported to the application - 
> if packets are not in order or if a duplicate is detected - how should 
> driver report it?
> Is the driver/HW expected to correct the order OR is the behaviour 
> limited to detection of out-of-order? In order to correct the order, 
> the driver/HW will need to accumulate packets. Is that really the 
> expectation of this specification
I have added a setting in xform and capability for in-order and 
duplicate packet detection.
So if the capability is there in hardware to do such processing then it 
will do that and report error
in crypto status and if the capability is not there then application 
will be responsible for handling such cases.
I hope this would answer your query.

>> If somebody have support for PDCP in the hardware, we can add
>> capabilities as per the specific requirements.
>> In v2/v3 I have removed the hfn_override. Will add it later when it will
>> be supported.
>>
>>
>> Thanks,
>> Akhil
>

^ permalink raw reply	[flat|nested] 41+ messages in thread

* Re: [dpdk-dev] [PATCH 1/3] security: support pdcp protocol
  2018-10-15 13:03             ` Akhil Goyal
@ 2018-10-16  6:27               ` Joseph
  0 siblings, 0 replies; 41+ messages in thread
From: Joseph @ 2018-10-16  6:27 UTC (permalink / raw)
  To: Akhil Goyal
  Cc: dev, Declan Doherty, Pablo de Lara, Radu Nicolau, Jacob,  Jerin,
	Athreya, Narayana Prasad, Verma, Shally, Velumuri, Vidya

Hi Akhil,


On 15-10-2018 18:33, Akhil Goyal wrote:
> External Email
>
> On 10/9/2018 5:08 PM, Joseph, Anoob wrote:
>> Hi Akhil,
>>
>> Please see inline.
>>
>> Thanks,
>> Anoob
>> On 08-10-2018 15:19, Akhil Goyal wrote:
>>> External Email
>>>
>>> Hi Anoob,
>>>>>>> @@ -494,6 +553,23 @@ IPsec related configuration parameters are
>>>>>>> defined in ``rte_security_ipsec_xform
>>>>>>>            /**< Tunnel parameters, NULL for transport mode */
>>>>>>>        };
>>>>>>> +PDCP related configuration parameters are defined in
>>>>>>> ``rte_security_pdcp_xform``
>>>>>>> +
>>>>>>> +.. code-block:: c
>>>>>>> +
>>>>>>> +    struct rte_security_pdcp_xform {
>>>>>>> +        int8_t bearer; /**< PDCP bearer ID */
>>>>>>> +        enum rte_security_pdcp_domain domain;
>>>>>>> +        /** < PDCP mode of operation: Control or data */
>>>>>>> +        enum rte_security_pdcp_direction pkt_dir;
>>>>>>> +        /**< PDCP Frame Direction 0:UL 1:DL */
>>>>>>> +        enum rte_security_pdcp_sn_size sn_size;
>>>>>>> +        /**< Sequence number size, 5/7/12/15 */
>>>>>>> +        int8_t hfn_ovd; /**< Overwrite HFN per operation */
>>>>>>> +        uint32_t hfn;  /**< Hyper Frame Number */
>>>>>>> +        uint32_t hfn_threshold;        /**< HFN Threashold for key
>>>>>>> renegotiation */
>>>>>>> +    };
>>>>>>> +
>>>>>> [Anoob] PDCP packet ordering should be both a capability and a
>>>>>> setting.
>>>>>> HFN will be incremented overtime and starts at 0. So why is it
>>>>>> part of
>>>>>> the xform?
>>>>>
>>>>> The Security accelerators may assume packet in order. Latest PDCP TS
>>>>> suggest to do de-Ciphering before re-Ordering the Rx PDCP PDUs. In
>>>>> this
>>>>> situation, the accelerator may use wrong HFN value. The PDCP
>>>>> application
>>>>> can provide the appropriate HFN value along with PDU to the security
>>>>> accelerator.
>>>>>
>>>> So what is the expectation with regards to ordering? Would PDCP know
>>>> the order or is it unaware of the order?
>>>> If implementation of this Spec knows the order of packets(which is
>>>> implied by the "In order delivery and Duplicate detection
>>>> Sequence Numbering" statement in the PDCP flow diagram), then there
>>>> should be no need to override the
>>>> HFN. If the implementation does not know the order of packets, then
>>>> the flow diagram should be corrected.
>>>> Also, is implementation expected to support ordered delivery and
>>>> duplicate detection. Perhaps it should be
>>>> a capability or 2.
>>> This patchset is basically talking about full protocol offload with 
>>> look
>>> aside accelerators.
>>> And when we are talking about full protocol offload, all protocol
>>> related stuff like ordering, headers etc.
>>> needs to be handled by the HW/driver.
>>> So the expectation is driver/HW should be able to perform in order
>>> delivery and detect duplicates.
>> How will errors in these situations be reported to the application -
>> if packets are not in order or if a duplicate is detected - how should
>> driver report it?
>> Is the driver/HW expected to correct the order OR is the behaviour
>> limited to detection of out-of-order? In order to correct the order,
>> the driver/HW will need to accumulate packets. Is that really the
>> expectation of this specification
> I have added a setting in xform and capability for in-order and
> duplicate packet detection.
> So if the capability is there in hardware to do such processing then it
> will do that and report error
> in crypto status and if the capability is not there then application
> will be responsible for handling such cases.
> I hope this would answer your query.
Seems good.
>
>>> If somebody have support for PDCP in the hardware, we can add
>>> capabilities as per the specific requirements.
>>> In v2/v3 I have removed the hfn_override. Will add it later when it 
>>> will
>>> be supported.
>>>
>>>
>>> Thanks,
>>> Akhil
>>
>


^ permalink raw reply	[flat|nested] 41+ messages in thread

* Re: [dpdk-dev] [PATCH v4 1/3] security: support pdcp protocol
  2018-10-15 12:53       ` [dpdk-dev] [PATCH v4 1/3] security: support pdcp protocol Akhil Goyal
@ 2018-10-16  6:40         ` Joseph
  2018-10-16  6:55           ` Akhil Goyal
  0 siblings, 1 reply; 41+ messages in thread
From: Joseph @ 2018-10-16  6:40 UTC (permalink / raw)
  To: Akhil Goyal, dev
  Cc: pablo.de.lara.guarch, radu.nicolau, Jacob,  Jerin, Athreya,
	Narayana Prasad, Verma, Shally, Velumuri, Vidya, Hemant Agrawal

Hi Akhil,

https://tools.ietf.org/html/rfc4301#section-1

RFC says we need to use "IPsec" and not "IPSec". Can you fix this in the 
lines you have added?

And do see inline for other comments.

Thanks,
Anoob
On 15-10-2018 18:23, Akhil Goyal wrote:
> External Email
>
> From: Akhil Goyal <akhil.goyal@nxp.com>
>
> Packet Data Convergence Protocol (PDCP) is added in rte_security
> for 3GPP TS 36.323 for LTE.
>
> The patchset provide the structure definitions for configuring the
> PDCP sessions and relevant documentation is added.
>
> Signed-off-by: Hemant Agrawal <hemant.agrawal@nxp.com>
> Signed-off-by: Akhil Goyal <akhil.goyal@nxp.com>
> ---
>   doc/guides/prog_guide/rte_security.rst | 107 +++++++++++++++++++++++--
>   lib/librte_security/rte_security.c     |   4 +
>   lib/librte_security/rte_security.h     |  91 +++++++++++++++++++++
>   3 files changed, 195 insertions(+), 7 deletions(-)
>
> diff --git a/doc/guides/prog_guide/rte_security.rst b/doc/guides/prog_guide/rte_security.rst
> index 0812abe77..f09e7c8bb 100644
> --- a/doc/guides/prog_guide/rte_security.rst
> +++ b/doc/guides/prog_guide/rte_security.rst
> @@ -10,8 +10,8 @@ The security library provides a framework for management and provisioning
>   of security protocol operations offloaded to hardware based devices. The
>   library defines generic APIs to create and free security sessions which can
>   support full protocol offload as well as inline crypto operation with
> -NIC or crypto devices. The framework currently only supports the IPSec protocol
> -and associated operations, other protocols will be added in future.
> +NIC or crypto devices. The framework currently only supports the IPSec and PDCP
> +protocol and associated operations, other protocols will be added in future.
>
>   Design Principles
>   -----------------
> @@ -253,6 +253,49 @@ for any protocol header addition.
>           +--------|--------+
>                    V
>
> +PDCP Flow Diagram
> +~~~~~~~~~~~~~~~~~
> +
> +Based on 3GPP TS 36.323 Evolved Universal Terrestrial Radio Access (E-UTRA);
> +Packet Data Convergence Protocol (PDCP) specification
> +
> +.. code-block:: c
> +
> +        Transmitting PDCP Entity          Receiving PDCP Entity
> +                  |                                   ^
> +                  |                       +-----------|-----------+
> +                  V                       | In order delivery and |
> +        +---------|----------+            | Duplicate detection   |
> +        | Sequence Numbering |            |  (Data Plane only)    |
> +        +---------|----------+            +-----------|-----------+
> +                  |                                   |
> +        +---------|----------+            +-----------|----------+
> +        | Header Compression*|            | Header Decompression*|
> +        | (Data-Plane only)  |            |   (Data Plane only)  |
> +        +---------|----------+            +-----------|----------+
> +                  |                                   |
> +        +---------|-----------+           +-----------|----------+
> +        | Integrity Protection|           |Integrity Verification|
> +        | (Control Plane only)|           | (Control Plane only) |
> +        +---------|-----------+           +-----------|----------+
> +        +---------|-----------+            +----------|----------+
> +        |     Ciphering       |            |     Deciphering     |
> +        +---------|-----------+            +----------|----------+
> +        +---------|-----------+            +----------|----------+
> +        |   Add PDCP header   |            | Remove PDCP Header  |
> +        +---------|-----------+            +----------|----------+
> +                  |                                   |
> +                  +----------------->>----------------+
> +
> +
> +.. note::
> +
> +    * Header Compression and decompression are not supported currently.
> +
> +Just like IPSec, in case of PDCP also header addition/deletion, cipher/
> +de-cipher, integrity protection/verification is done based on the action
> +type chosen.
> +
>   Device Features and Capabilities
>   ---------------------------------
>
> @@ -271,7 +314,7 @@ structure in the *DPDK API Reference*.
>
>   Each driver (crypto or ethernet) defines its own private array of capabilities
>   for the operations it supports. Below is an example of the capabilities for a
> -PMD which supports the IPSec protocol.
> +PMD which supports the IPSec and PDCP protocol.
>
>   .. code-block:: c
>
> @@ -298,6 +341,24 @@ PMD which supports the IPSec protocol.
>                   },
>                   .crypto_capabilities = pmd_capabilities
>           },
> +        { /* PDCP Lookaside Protocol offload Data Plane */
> +                .action = RTE_SECURITY_ACTION_TYPE_LOOKASIDE_PROTOCOL,
> +                .protocol = RTE_SECURITY_PROTOCOL_PDCP,
> +                .pdcp = {
> +                        .domain = RTE_SECURITY_PDCP_MODE_DATA,
> +                        .capa_flags = 0
> +                },
> +                .crypto_capabilities = pmd_capabilities
> +        },
> +        { /* PDCP Lookaside Protocol offload Control */
> +                .action = RTE_SECURITY_ACTION_TYPE_LOOKASIDE_PROTOCOL,
> +                .protocol = RTE_SECURITY_PROTOCOL_PDCP,
> +                .pdcp = {
> +                        .domain = RTE_SECURITY_PDCP_MODE_CONTROL,
> +                        .capa_flags = 0
> +                },
> +                .crypto_capabilities = pmd_capabilities
> +        },
>           {
>                   .action = RTE_SECURITY_ACTION_TYPE_NONE
>           }
> @@ -429,6 +490,7 @@ Security Session configuration structure is defined as ``rte_security_session_co
>           union {
>                   struct rte_security_ipsec_xform ipsec;
>                   struct rte_security_macsec_xform macsec;
> +                struct rte_security_pdcp_xform pdcp;
>           };
>           /**< Configuration parameters for security session */
>           struct rte_crypto_sym_xform *crypto_xform;
> @@ -463,15 +525,17 @@ The ``rte_security_session_protocol`` is defined as
>   .. code-block:: c
>
>       enum rte_security_session_protocol {
> -        RTE_SECURITY_PROTOCOL_IPSEC,
> +        RTE_SECURITY_PROTOCOL_IPSEC = 1,
>           /**< IPsec Protocol */
>           RTE_SECURITY_PROTOCOL_MACSEC,
>           /**< MACSec Protocol */
> +        RTE_SECURITY_PROTOCOL_PDCP,
> +        /**< PDCP Protocol */
>       };
>
> -Currently the library defines configuration parameters for IPSec only. For other
> -protocols like MACSec, structures and enums are defined as place holders which
> -will be updated in the future.
> +Currently the library defines configuration parameters for IPSec and PDCP only.
> +For other protocols like MACSec, structures and enums are defined as place holders
> +which will be updated in the future.
>
>   IPsec related configuration parameters are defined in ``rte_security_ipsec_xform``
>
> @@ -494,6 +558,35 @@ IPsec related configuration parameters are defined in ``rte_security_ipsec_xform
>           /**< Tunnel parameters, NULL for transport mode */
>       };
>
> +PDCP related configuration parameters are defined in ``rte_security_pdcp_xform``
> +
> +.. code-block:: c
> +
> +    struct rte_security_pdcp_xform {
> +        int8_t bearer; /**< PDCP bearer ID */
> +        /**< PDCP mode of operation: Control or data */
> +        uint8_t en_ordering;
> +        /**< Enable in order delivery, this field shall be set only if
> +         * driver/HW is capable. See RTE_SECURITY_PDCP_ORDERING_CAP.
> +         */
> +        uint8_t remove_duplicates;
> +        /**< Notify driver/HW to detect and remove duplicate packets.
> +         * This field should be set only when driver/hw is capable.
> +         * See RTE_SECURITY_PDCP_DUP_DETECT_CAP.
> +         */
> +        enum rte_security_pdcp_domain domain;
> +        /**< PDCP Frame Direction 0:UL 1:DL */
> +        enum rte_security_pdcp_direction pkt_dir;
> +        /**< Sequence number size, 5/7/12/15/18 */
> +        enum rte_security_pdcp_sn_size sn_size;
> +        /**< Starting Hyper Frame Number to be used together with the SN
> +         * from the PDCP frames
> +         */
> +        uint32_t hfn;
> +        /**< HFN Threashold for key renegotiation */
> +        uint32_t hfn_threshold;
> +    };
> +
>
>   Security API
>   ~~~~~~~~~~~~
> diff --git a/lib/librte_security/rte_security.c b/lib/librte_security/rte_security.c
> index 1954960a5..c6355de95 100644
> --- a/lib/librte_security/rte_security.c
> +++ b/lib/librte_security/rte_security.c
> @@ -131,6 +131,10 @@ rte_security_capability_get(struct rte_security_ctx *instance,
>                                          capability->ipsec.direction ==
>                                                          idx->ipsec.direction)
>                                          return capability;
> +                       } else if (idx->protocol == RTE_SECURITY_PROTOCOL_PDCP) {
> +                               if (capability->pdcp.domain ==
> +                                                       idx->pdcp.domain)
> +                                       return capability;
>                          }
>                  }
>          }
> diff --git a/lib/librte_security/rte_security.h b/lib/librte_security/rte_security.h
> index b0d1b97ee..1d20530f4 100644
> --- a/lib/librte_security/rte_security.h
> +++ b/lib/librte_security/rte_security.h
> @@ -206,6 +206,66 @@ struct rte_security_macsec_xform {
>          int dummy;
>   };
>
> +/**
> + * PDCP Mode of session
> + */
> +enum rte_security_pdcp_domain {
> +       RTE_SECURITY_PDCP_MODE_CONTROL, /**< PDCP control plane */
> +       RTE_SECURITY_PDCP_MODE_DATA,    /**< PDCP data plane */
> +};
> +
> +/** PDCP Frame direction */
> +enum rte_security_pdcp_direction {
> +       RTE_SECURITY_PDCP_UPLINK,       /**< Uplink */
> +       RTE_SECURITY_PDCP_DOWNLINK,     /**< Downlink */
> +};
> +
> +/**
> + * PDCP Sequence Number Size selectors
> + * @PDCP_SN_SIZE_5: 5bit sequence number
> + * @PDCP_SN_SIZE_7: 7bit sequence number
> + * @PDCP_SN_SIZE_12: 12bit sequence number
> + * @PDCP_SN_SIZE_15: 15bit sequence number
> + * @PDCP_SN_SIZE_18: 18bit sequence number
> + */
> +enum rte_security_pdcp_sn_size {
> +       RTE_SECURITY_PDCP_SN_SIZE_5 = 5,
> +       RTE_SECURITY_PDCP_SN_SIZE_7 = 7,
> +       RTE_SECURITY_PDCP_SN_SIZE_12 = 12,
> +       RTE_SECURITY_PDCP_SN_SIZE_15 = 15,
> +       RTE_SECURITY_PDCP_SN_SIZE_18 = 18
> +};
> +
> +/**
> + * PDCP security association configuration data.
> + *
> + * This structure contains data required to create a PDCP security session.
> + */
> +struct rte_security_pdcp_xform {
> +       int8_t bearer;  /**< PDCP bearer ID */
> +       /**< PDCP mode of operation: Control or data */
> +       uint8_t en_ordering;
> +       /**< Enable in order delivery, this field shall be set only if
> +        * driver/HW is capable. See RTE_SECURITY_PDCP_ORDERING_CAP.
> +        */
> +       uint8_t remove_duplicates;
> +       /**< Notify driver/HW to detect and remove duplicate packets.
> +        * This field should be set only when driver/hw is capable.
> +        * See RTE_SECURITY_PDCP_DUP_DETECT_CAP.
> +        */
> +       enum rte_security_pdcp_domain domain;
> +       /**< PDCP Frame Direction 0:UL 1:DL */
> +       enum rte_security_pdcp_direction pkt_dir;
> +       /**< Sequence number size, 5/7/12/15/18 */
> +       enum rte_security_pdcp_sn_size sn_size;
> +       /**< Starting Hyper Frame Number to be used together with the SN
> +        * from the PDCP frames
> +        */
> +       uint32_t hfn;
> +       /**< HFN Threshold for key renegotiation */
The above comment is for which member?
> +       uint32_t hfn_threshold;
> +};
> +
>   /**
>    * Security session action type.
>    */
> @@ -232,6 +292,8 @@ enum rte_security_session_protocol {
>          /**< IPsec Protocol */
>          RTE_SECURITY_PROTOCOL_MACSEC,
>          /**< MACSec Protocol */
> +       RTE_SECURITY_PROTOCOL_PDCP,
> +       /**< PDCP Protocol */
>   };
>
>   /**
> @@ -246,6 +308,7 @@ struct rte_security_session_conf {
>          union {
>                  struct rte_security_ipsec_xform ipsec;
>                  struct rte_security_macsec_xform macsec;
> +               struct rte_security_pdcp_xform pdcp;
>          };
>          /**< Configuration parameters for security session */
>          struct rte_crypto_sym_xform *crypto_xform;
> @@ -413,6 +476,10 @@ struct rte_security_ipsec_stats {
>
>   };
>
> +struct rte_security_pdcp_stats {
> +       uint64_t reserved;
> +};
> +
>   struct rte_security_stats {
>          enum rte_security_session_protocol protocol;
>          /**< Security protocol to be configured */
> @@ -421,6 +488,7 @@ struct rte_security_stats {
>          union {
>                  struct rte_security_macsec_stats macsec;
>                  struct rte_security_ipsec_stats ipsec;
> +               struct rte_security_pdcp_stats pdcp;
>          };
>   };
>
> @@ -465,6 +533,13 @@ struct rte_security_capability {
>                          int dummy;
>                  } macsec;
>                  /**< MACsec capability */
> +               struct {
> +                       enum rte_security_pdcp_domain domain;
> +                       /** < PDCP mode of operation: Control or data */
> +                       uint32_t capa_flags;
> +                       /** < Capabilitity flags, see RTE_SECURITY_PDCP_* */
> +               } pdcp;
> +               /**< PDCP capability */
>          };
>
>          const struct rte_cryptodev_capabilities *crypto_capabilities;
> @@ -474,6 +549,19 @@ struct rte_security_capability {
>          /**< Device offload flags */
>   };
>
> +/**< Underlying Hardware/driver which support PDCP may or may not support
> + * packet ordering. Set RTE_SECURITY_PDCP_ORDERING_CAP if it support.
> + * If it is not set, driver/HW assumes packets received are in order
> + * and it will be application's responsibility to maintain ordering.
> + */
> +#define RTE_SECURITY_PDCP_ORDERING_CAP         0x00000001
Would this flag contradict with RTE_SECURITY_TX_OLOAD_NEED_MDATA? 
Suppose if we have a security device which would do PDCP in inline mode, 
this would become a problem, right?
> +
> +/**< Underlying Hardware/driver which support PDCP may or may not detect
> + * duplicate packet. Set RTE_SECURITY_PDCP_DUP_DETECT_CAP if it support.
> + * If it is not set, driver/HW assumes there is no duplicate packet received.
> + */
> +#define RTE_SECURITY_PDCP_DUP_DETECT_CAP       0x00000002
> +
>   #define RTE_SECURITY_TX_OLOAD_NEED_MDATA       0x00000001
>   /**< HW needs metadata update, see rte_security_set_pkt_metadata().
>    */
> @@ -506,6 +594,9 @@ struct rte_security_capability_idx {
>                          enum rte_security_ipsec_sa_mode mode;
>                          enum rte_security_ipsec_sa_direction direction;
>                  } ipsec;
> +               struct {
> +                       enum rte_security_pdcp_domain domain;
> +               } pdcp;
>          };
>   };
>
> --
> 2.17.1
>


^ permalink raw reply	[flat|nested] 41+ messages in thread

* Re: [dpdk-dev] [PATCH v4 1/3] security: support pdcp protocol
  2018-10-16  6:40         ` Joseph
@ 2018-10-16  6:55           ` Akhil Goyal
  0 siblings, 0 replies; 41+ messages in thread
From: Akhil Goyal @ 2018-10-16  6:55 UTC (permalink / raw)
  To: Joseph, dev
  Cc: pablo.de.lara.guarch, radu.nicolau, Jacob, Jerin, Athreya,
	Narayana Prasad, Verma, Shally, Velumuri, Vidya, Hemant Agrawal



On 10/16/2018 12:10 PM, Joseph@dpdk.org wrote:
> Hi Akhil,
>
> https://tools.ietf.org/html/rfc4301#section-1
>
> RFC says we need to use "IPsec" and not "IPSec". Can you fix this in the
> lines you have added?
I will send a separate patch to correct it in the complete document.
>
> And do see inline for other comments.
>
> Thanks,
> Anoob
> On 15-10-2018 18:23, Akhil Goyal wrote:
>> External Email
>>
>> From: Akhil Goyal <akhil.goyal@nxp.com>
>>
>> Packet Data Convergence Protocol (PDCP) is added in rte_security
>> for 3GPP TS 36.323 for LTE.
>>
>> The patchset provide the structure definitions for configuring the
>> PDCP sessions and relevant documentation is added.
>>
>> Signed-off-by: Hemant Agrawal <hemant.agrawal@nxp.com>
>> Signed-off-by: Akhil Goyal <akhil.goyal@nxp.com>
>> ---
>>    doc/guides/prog_guide/rte_security.rst | 107 +++++++++++++++++++++++--
>>    lib/librte_security/rte_security.c     |   4 +
>>    lib/librte_security/rte_security.h     |  91 +++++++++++++++++++++
>>    3 files changed, 195 insertions(+), 7 deletions(-)
>>
>> diff --git a/doc/guides/prog_guide/rte_security.rst b/doc/guides/prog_guide/rte_security.rst
>> index 0812abe77..f09e7c8bb 100644
>> --- a/doc/guides/prog_guide/rte_security.rst
>> +++ b/doc/guides/prog_guide/rte_security.rst
>> @@ -10,8 +10,8 @@ The security library provides a framework for management and provisioning
>>    of security protocol operations offloaded to hardware based devices. The
>>    library defines generic APIs to create and free security sessions which can
>>    support full protocol offload as well as inline crypto operation with
>> -NIC or crypto devices. The framework currently only supports the IPSec protocol
>> -and associated operations, other protocols will be added in future.
>> +NIC or crypto devices. The framework currently only supports the IPSec and PDCP
>> +protocol and associated operations, other protocols will be added in future.
>>
>>    Design Principles
>>    -----------------
>> @@ -253,6 +253,49 @@ for any protocol header addition.
>>            +--------|--------+
>>                     V
>>
>> +PDCP Flow Diagram
>> +~~~~~~~~~~~~~~~~~
>> +
>> +Based on 3GPP TS 36.323 Evolved Universal Terrestrial Radio Access (E-UTRA);
>> +Packet Data Convergence Protocol (PDCP) specification
>> +
>> +.. code-block:: c
>> +
>> +        Transmitting PDCP Entity          Receiving PDCP Entity
>> +                  |                                   ^
>> +                  |                       +-----------|-----------+
>> +                  V                       | In order delivery and |
>> +        +---------|----------+            | Duplicate detection   |
>> +        | Sequence Numbering |            |  (Data Plane only)    |
>> +        +---------|----------+            +-----------|-----------+
>> +                  |                                   |
>> +        +---------|----------+            +-----------|----------+
>> +        | Header Compression*|            | Header Decompression*|
>> +        | (Data-Plane only)  |            |   (Data Plane only)  |
>> +        +---------|----------+            +-----------|----------+
>> +                  |                                   |
>> +        +---------|-----------+           +-----------|----------+
>> +        | Integrity Protection|           |Integrity Verification|
>> +        | (Control Plane only)|           | (Control Plane only) |
>> +        +---------|-----------+           +-----------|----------+
>> +        +---------|-----------+            +----------|----------+
>> +        |     Ciphering       |            |     Deciphering     |
>> +        +---------|-----------+            +----------|----------+
>> +        +---------|-----------+            +----------|----------+
>> +        |   Add PDCP header   |            | Remove PDCP Header  |
>> +        +---------|-----------+            +----------|----------+
>> +                  |                                   |
>> +                  +----------------->>----------------+
>> +
>> +
>> +.. note::
>> +
>> +    * Header Compression and decompression are not supported currently.
>> +
>> +Just like IPSec, in case of PDCP also header addition/deletion, cipher/
>> +de-cipher, integrity protection/verification is done based on the action
>> +type chosen.
>> +
>>    Device Features and Capabilities
>>    ---------------------------------
>>
>> @@ -271,7 +314,7 @@ structure in the *DPDK API Reference*.
>>
>>    Each driver (crypto or ethernet) defines its own private array of capabilities
>>    for the operations it supports. Below is an example of the capabilities for a
>> -PMD which supports the IPSec protocol.
>> +PMD which supports the IPSec and PDCP protocol.
>>
>>    .. code-block:: c
>>
>> @@ -298,6 +341,24 @@ PMD which supports the IPSec protocol.
>>                    },
>>                    .crypto_capabilities = pmd_capabilities
>>            },
>> +        { /* PDCP Lookaside Protocol offload Data Plane */
>> +                .action = RTE_SECURITY_ACTION_TYPE_LOOKASIDE_PROTOCOL,
>> +                .protocol = RTE_SECURITY_PROTOCOL_PDCP,
>> +                .pdcp = {
>> +                        .domain = RTE_SECURITY_PDCP_MODE_DATA,
>> +                        .capa_flags = 0
>> +                },
>> +                .crypto_capabilities = pmd_capabilities
>> +        },
>> +        { /* PDCP Lookaside Protocol offload Control */
>> +                .action = RTE_SECURITY_ACTION_TYPE_LOOKASIDE_PROTOCOL,
>> +                .protocol = RTE_SECURITY_PROTOCOL_PDCP,
>> +                .pdcp = {
>> +                        .domain = RTE_SECURITY_PDCP_MODE_CONTROL,
>> +                        .capa_flags = 0
>> +                },
>> +                .crypto_capabilities = pmd_capabilities
>> +        },
>>            {
>>                    .action = RTE_SECURITY_ACTION_TYPE_NONE
>>            }
>> @@ -429,6 +490,7 @@ Security Session configuration structure is defined as ``rte_security_session_co
>>            union {
>>                    struct rte_security_ipsec_xform ipsec;
>>                    struct rte_security_macsec_xform macsec;
>> +                struct rte_security_pdcp_xform pdcp;
>>            };
>>            /**< Configuration parameters for security session */
>>            struct rte_crypto_sym_xform *crypto_xform;
>> @@ -463,15 +525,17 @@ The ``rte_security_session_protocol`` is defined as
>>    .. code-block:: c
>>
>>        enum rte_security_session_protocol {
>> -        RTE_SECURITY_PROTOCOL_IPSEC,
>> +        RTE_SECURITY_PROTOCOL_IPSEC = 1,
>>            /**< IPsec Protocol */
>>            RTE_SECURITY_PROTOCOL_MACSEC,
>>            /**< MACSec Protocol */
>> +        RTE_SECURITY_PROTOCOL_PDCP,
>> +        /**< PDCP Protocol */
>>        };
>>
>> -Currently the library defines configuration parameters for IPSec only. For other
>> -protocols like MACSec, structures and enums are defined as place holders which
>> -will be updated in the future.
>> +Currently the library defines configuration parameters for IPSec and PDCP only.
>> +For other protocols like MACSec, structures and enums are defined as place holders
>> +which will be updated in the future.
>>
>>    IPsec related configuration parameters are defined in ``rte_security_ipsec_xform``
>>
>> @@ -494,6 +558,35 @@ IPsec related configuration parameters are defined in ``rte_security_ipsec_xform
>>            /**< Tunnel parameters, NULL for transport mode */
>>        };
>>
>> +PDCP related configuration parameters are defined in ``rte_security_pdcp_xform``
>> +
>> +.. code-block:: c
>> +
>> +    struct rte_security_pdcp_xform {
>> +        int8_t bearer; /**< PDCP bearer ID */
>> +        /**< PDCP mode of operation: Control or data */
>> +        uint8_t en_ordering;
>> +        /**< Enable in order delivery, this field shall be set only if
>> +         * driver/HW is capable. See RTE_SECURITY_PDCP_ORDERING_CAP.
>> +         */
>> +        uint8_t remove_duplicates;
>> +        /**< Notify driver/HW to detect and remove duplicate packets.
>> +         * This field should be set only when driver/hw is capable.
>> +         * See RTE_SECURITY_PDCP_DUP_DETECT_CAP.
>> +         */
>> +        enum rte_security_pdcp_domain domain;
>> +        /**< PDCP Frame Direction 0:UL 1:DL */
>> +        enum rte_security_pdcp_direction pkt_dir;
>> +        /**< Sequence number size, 5/7/12/15/18 */
>> +        enum rte_security_pdcp_sn_size sn_size;
>> +        /**< Starting Hyper Frame Number to be used together with the SN
>> +         * from the PDCP frames
>> +         */
>> +        uint32_t hfn;
>> +        /**< HFN Threashold for key renegotiation */
>> +        uint32_t hfn_threshold;
>> +    };
>> +
>>
>>    Security API
>>    ~~~~~~~~~~~~
>> diff --git a/lib/librte_security/rte_security.c b/lib/librte_security/rte_security.c
>> index 1954960a5..c6355de95 100644
>> --- a/lib/librte_security/rte_security.c
>> +++ b/lib/librte_security/rte_security.c
>> @@ -131,6 +131,10 @@ rte_security_capability_get(struct rte_security_ctx *instance,
>>                                           capability->ipsec.direction ==
>>                                                           idx->ipsec.direction)
>>                                           return capability;
>> +                       } else if (idx->protocol == RTE_SECURITY_PROTOCOL_PDCP) {
>> +                               if (capability->pdcp.domain ==
>> +                                                       idx->pdcp.domain)
>> +                                       return capability;
>>                           }
>>                   }
>>           }
>> diff --git a/lib/librte_security/rte_security.h b/lib/librte_security/rte_security.h
>> index b0d1b97ee..1d20530f4 100644
>> --- a/lib/librte_security/rte_security.h
>> +++ b/lib/librte_security/rte_security.h
>> @@ -206,6 +206,66 @@ struct rte_security_macsec_xform {
>>           int dummy;
>>    };
>>
>> +/**
>> + * PDCP Mode of session
>> + */
>> +enum rte_security_pdcp_domain {
>> +       RTE_SECURITY_PDCP_MODE_CONTROL, /**< PDCP control plane */
>> +       RTE_SECURITY_PDCP_MODE_DATA,    /**< PDCP data plane */
>> +};
>> +
>> +/** PDCP Frame direction */
>> +enum rte_security_pdcp_direction {
>> +       RTE_SECURITY_PDCP_UPLINK,       /**< Uplink */
>> +       RTE_SECURITY_PDCP_DOWNLINK,     /**< Downlink */
>> +};
>> +
>> +/**
>> + * PDCP Sequence Number Size selectors
>> + * @PDCP_SN_SIZE_5: 5bit sequence number
>> + * @PDCP_SN_SIZE_7: 7bit sequence number
>> + * @PDCP_SN_SIZE_12: 12bit sequence number
>> + * @PDCP_SN_SIZE_15: 15bit sequence number
>> + * @PDCP_SN_SIZE_18: 18bit sequence number
>> + */
>> +enum rte_security_pdcp_sn_size {
>> +       RTE_SECURITY_PDCP_SN_SIZE_5 = 5,
>> +       RTE_SECURITY_PDCP_SN_SIZE_7 = 7,
>> +       RTE_SECURITY_PDCP_SN_SIZE_12 = 12,
>> +       RTE_SECURITY_PDCP_SN_SIZE_15 = 15,
>> +       RTE_SECURITY_PDCP_SN_SIZE_18 = 18
>> +};
>> +
>> +/**
>> + * PDCP security association configuration data.
>> + *
>> + * This structure contains data required to create a PDCP security session.
>> + */
>> +struct rte_security_pdcp_xform {
>> +       int8_t bearer;  /**< PDCP bearer ID */
>> +       /**< PDCP mode of operation: Control or data */
>> +       uint8_t en_ordering;
>> +       /**< Enable in order delivery, this field shall be set only if
>> +        * driver/HW is capable. See RTE_SECURITY_PDCP_ORDERING_CAP.
>> +        */
>> +       uint8_t remove_duplicates;
>> +       /**< Notify driver/HW to detect and remove duplicate packets.
>> +        * This field should be set only when driver/hw is capable.
>> +        * See RTE_SECURITY_PDCP_DUP_DETECT_CAP.
>> +        */
>> +       enum rte_security_pdcp_domain domain;
>> +       /**< PDCP Frame Direction 0:UL 1:DL */
>> +       enum rte_security_pdcp_direction pkt_dir;
>> +       /**< Sequence number size, 5/7/12/15/18 */
>> +       enum rte_security_pdcp_sn_size sn_size;
>> +       /**< Starting Hyper Frame Number to be used together with the SN
>> +        * from the PDCP frames
>> +        */
>> +       uint32_t hfn;
>> +       /**< HFN Threshold for key renegotiation */
> The above comment is for which member?
this is for hfn_threshold. However, one comment it misplaced, will 
correct it.
>> +       uint32_t hfn_threshold;
>> +};
>> +
>>    /**
>>     * Security session action type.
>>     */
>> @@ -232,6 +292,8 @@ enum rte_security_session_protocol {
>>           /**< IPsec Protocol */
>>           RTE_SECURITY_PROTOCOL_MACSEC,
>>           /**< MACSec Protocol */
>> +       RTE_SECURITY_PROTOCOL_PDCP,
>> +       /**< PDCP Protocol */
>>    };
>>
>>    /**
>> @@ -246,6 +308,7 @@ struct rte_security_session_conf {
>>           union {
>>                   struct rte_security_ipsec_xform ipsec;
>>                   struct rte_security_macsec_xform macsec;
>> +               struct rte_security_pdcp_xform pdcp;
>>           };
>>           /**< Configuration parameters for security session */
>>           struct rte_crypto_sym_xform *crypto_xform;
>> @@ -413,6 +476,10 @@ struct rte_security_ipsec_stats {
>>
>>    };
>>
>> +struct rte_security_pdcp_stats {
>> +       uint64_t reserved;
>> +};
>> +
>>    struct rte_security_stats {
>>           enum rte_security_session_protocol protocol;
>>           /**< Security protocol to be configured */
>> @@ -421,6 +488,7 @@ struct rte_security_stats {
>>           union {
>>                   struct rte_security_macsec_stats macsec;
>>                   struct rte_security_ipsec_stats ipsec;
>> +               struct rte_security_pdcp_stats pdcp;
>>           };
>>    };
>>
>> @@ -465,6 +533,13 @@ struct rte_security_capability {
>>                           int dummy;
>>                   } macsec;
>>                   /**< MACsec capability */
>> +               struct {
>> +                       enum rte_security_pdcp_domain domain;
>> +                       /** < PDCP mode of operation: Control or data */
>> +                       uint32_t capa_flags;
>> +                       /** < Capabilitity flags, see RTE_SECURITY_PDCP_* */
>> +               } pdcp;
>> +               /**< PDCP capability */
>>           };
>>
>>           const struct rte_cryptodev_capabilities *crypto_capabilities;
>> @@ -474,6 +549,19 @@ struct rte_security_capability {
>>           /**< Device offload flags */
>>    };
>>
>> +/**< Underlying Hardware/driver which support PDCP may or may not support
>> + * packet ordering. Set RTE_SECURITY_PDCP_ORDERING_CAP if it support.
>> + * If it is not set, driver/HW assumes packets received are in order
>> + * and it will be application's responsibility to maintain ordering.
>> + */
>> +#define RTE_SECURITY_PDCP_ORDERING_CAP         0x00000001
> Would this flag contradict with RTE_SECURITY_TX_OLOAD_NEED_MDATA?
> Suppose if we have a security device which would do PDCP in inline mode,
> this would become a problem, right?
I think this would not, as I have defined a separate field in pdcp 
capability as capa_flags.
>> +
>> +/**< Underlying Hardware/driver which support PDCP may or may not detect
>> + * duplicate packet. Set RTE_SECURITY_PDCP_DUP_DETECT_CAP if it support.
>> + * If it is not set, driver/HW assumes there is no duplicate packet received.
>> + */
>> +#define RTE_SECURITY_PDCP_DUP_DETECT_CAP       0x00000002
>> +
>>    #define RTE_SECURITY_TX_OLOAD_NEED_MDATA       0x00000001
>>    /**< HW needs metadata update, see rte_security_set_pkt_metadata().
>>     */
>> @@ -506,6 +594,9 @@ struct rte_security_capability_idx {
>>                           enum rte_security_ipsec_sa_mode mode;
>>                           enum rte_security_ipsec_sa_direction direction;
>>                   } ipsec;
>> +               struct {
>> +                       enum rte_security_pdcp_domain domain;
missed the capa_flags in this one. Will add it. It is added in the 
rte_security_capability
>> +               } pdcp;
>>           };
>>    };
>>
>> --
>> 2.17.1
>>


^ permalink raw reply	[flat|nested] 41+ messages in thread

* [dpdk-dev] [PATCH v5 0/3] security: support for pdcp
  2018-10-15 12:53     ` [dpdk-dev] [PATCH v4 0/3] security: support for pdcp Akhil Goyal
                         ` (2 preceding siblings ...)
  2018-10-15 12:53       ` [dpdk-dev] [PATCH v4 3/3] crypto/dpaa2_sec: support pdcp offload Akhil Goyal
@ 2018-10-16 10:38       ` Akhil Goyal
  2018-10-16 10:39         ` [dpdk-dev] [PATCH v5 1/3] security: support pdcp protocol Akhil Goyal
                           ` (4 more replies)
  3 siblings, 5 replies; 41+ messages in thread
From: Akhil Goyal @ 2018-10-16 10:38 UTC (permalink / raw)
  To: dev
  Cc: pablo.de.lara.guarch, radu.nicolau, jerin.jacob,
	narayanaprasad.athreya, Shally.Verma, Anoob.Joseph,
	Vidya.Velumuri, Hemant Agrawal, Akhil Goyal

From: Akhil Goyal <akhil.goyal@nxp.com>

Security library currently only has support for IPSec protocol.
This patchset defines structures for pdcp protocol in rte_security
and provide a sample driver implementation for lookaside protocol
offload to support PDCP.

Changes in v5:
- corrected comments in xform structure.

changes in v4:
- added capability and setting for packet ordering and duplicate
detection.
- some fixes in driver.

changes in v3:
removed checkpatch warnings.

changes in v2:
- removed hfn override. Will be added later when it is supported
- added seq number size = 18bits
- coding style issues corrected in pdcp.h
- updated documentation for specifying the 3GPP specification reference
- removed some duplicate code in dpaa2_sec_dpseci.c


Akhil Goyal (3):
  security: support pdcp protocol
  crypto/dpaa2_sec: add sample pdcp descriptor apis
  crypto/dpaa2_sec: support pdcp offload

 doc/guides/prog_guide/rte_security.rst      |  107 +-
 drivers/crypto/dpaa2_sec/dpaa2_sec_dpseci.c |  257 ++
 drivers/crypto/dpaa2_sec/dpaa2_sec_priv.h   |  208 +-
 drivers/crypto/dpaa2_sec/hw/desc.h          |    2 +-
 drivers/crypto/dpaa2_sec/hw/desc/pdcp.h     | 2796 +++++++++++++++++++
 lib/librte_security/rte_security.c          |    4 +
 lib/librte_security/rte_security.h          |   92 +
 7 files changed, 3450 insertions(+), 16 deletions(-)
 create mode 100644 drivers/crypto/dpaa2_sec/hw/desc/pdcp.h

-- 
2.17.1

^ permalink raw reply	[flat|nested] 41+ messages in thread

* [dpdk-dev] [PATCH v5 1/3] security: support pdcp protocol
  2018-10-16 10:38       ` [dpdk-dev] [PATCH v5 0/3] security: support for pdcp Akhil Goyal
@ 2018-10-16 10:39         ` Akhil Goyal
  2018-10-16 10:49           ` Joseph, Anoob
  2018-10-16 10:39         ` [dpdk-dev] [PATCH v5 2/3] crypto/dpaa2_sec: add sample pdcp descriptor apis Akhil Goyal
                           ` (3 subsequent siblings)
  4 siblings, 1 reply; 41+ messages in thread
From: Akhil Goyal @ 2018-10-16 10:39 UTC (permalink / raw)
  To: dev
  Cc: pablo.de.lara.guarch, radu.nicolau, jerin.jacob,
	narayanaprasad.athreya, Shally.Verma, Anoob.Joseph,
	Vidya.Velumuri, Hemant Agrawal, Akhil Goyal

From: Akhil Goyal <akhil.goyal@nxp.com>

Packet Data Convergence Protocol (PDCP) is added in rte_security
for 3GPP TS 36.323 for LTE.

The patchset provide the structure definitions for configuring the
PDCP sessions and relevant documentation is added.

Signed-off-by: Hemant Agrawal <hemant.agrawal@nxp.com>
Signed-off-by: Akhil Goyal <akhil.goyal@nxp.com>
---
 doc/guides/prog_guide/rte_security.rst | 107 +++++++++++++++++++++++--
 lib/librte_security/rte_security.c     |   4 +
 lib/librte_security/rte_security.h     |  92 +++++++++++++++++++++
 3 files changed, 196 insertions(+), 7 deletions(-)

diff --git a/doc/guides/prog_guide/rte_security.rst b/doc/guides/prog_guide/rte_security.rst
index 0812abe77..e43f1554c 100644
--- a/doc/guides/prog_guide/rte_security.rst
+++ b/doc/guides/prog_guide/rte_security.rst
@@ -10,8 +10,8 @@ The security library provides a framework for management and provisioning
 of security protocol operations offloaded to hardware based devices. The
 library defines generic APIs to create and free security sessions which can
 support full protocol offload as well as inline crypto operation with
-NIC or crypto devices. The framework currently only supports the IPSec protocol
-and associated operations, other protocols will be added in future.
+NIC or crypto devices. The framework currently only supports the IPsec and PDCP
+protocol and associated operations, other protocols will be added in future.
 
 Design Principles
 -----------------
@@ -253,6 +253,49 @@ for any protocol header addition.
         +--------|--------+
                  V
 
+PDCP Flow Diagram
+~~~~~~~~~~~~~~~~~
+
+Based on 3GPP TS 36.323 Evolved Universal Terrestrial Radio Access (E-UTRA);
+Packet Data Convergence Protocol (PDCP) specification
+
+.. code-block:: c
+
+        Transmitting PDCP Entity          Receiving PDCP Entity
+                  |                                   ^
+                  |                       +-----------|-----------+
+                  V                       | In order delivery and |
+        +---------|----------+            | Duplicate detection   |
+        | Sequence Numbering |            |  (Data Plane only)    |
+        +---------|----------+            +-----------|-----------+
+                  |                                   |
+        +---------|----------+            +-----------|----------+
+        | Header Compression*|            | Header Decompression*|
+        | (Data-Plane only)  |            |   (Data Plane only)  |
+        +---------|----------+            +-----------|----------+
+                  |                                   |
+        +---------|-----------+           +-----------|----------+
+        | Integrity Protection|           |Integrity Verification|
+        | (Control Plane only)|           | (Control Plane only) |
+        +---------|-----------+           +-----------|----------+
+        +---------|-----------+            +----------|----------+
+        |     Ciphering       |            |     Deciphering     |
+        +---------|-----------+            +----------|----------+
+        +---------|-----------+            +----------|----------+
+        |   Add PDCP header   |            | Remove PDCP Header  |
+        +---------|-----------+            +----------|----------+
+                  |                                   |
+                  +----------------->>----------------+
+
+
+.. note::
+
+    * Header Compression and decompression are not supported currently.
+
+Just like IPsec, in case of PDCP also header addition/deletion, cipher/
+de-cipher, integrity protection/verification is done based on the action
+type chosen.
+
 Device Features and Capabilities
 ---------------------------------
 
@@ -271,7 +314,7 @@ structure in the *DPDK API Reference*.
 
 Each driver (crypto or ethernet) defines its own private array of capabilities
 for the operations it supports. Below is an example of the capabilities for a
-PMD which supports the IPSec protocol.
+PMD which supports the IPsec and PDCP protocol.
 
 .. code-block:: c
 
@@ -298,6 +341,24 @@ PMD which supports the IPSec protocol.
                 },
                 .crypto_capabilities = pmd_capabilities
         },
+        { /* PDCP Lookaside Protocol offload Data Plane */
+                .action = RTE_SECURITY_ACTION_TYPE_LOOKASIDE_PROTOCOL,
+                .protocol = RTE_SECURITY_PROTOCOL_PDCP,
+                .pdcp = {
+                        .domain = RTE_SECURITY_PDCP_MODE_DATA,
+                        .capa_flags = 0
+                },
+                .crypto_capabilities = pmd_capabilities
+        },
+        { /* PDCP Lookaside Protocol offload Control */
+                .action = RTE_SECURITY_ACTION_TYPE_LOOKASIDE_PROTOCOL,
+                .protocol = RTE_SECURITY_PROTOCOL_PDCP,
+                .pdcp = {
+                        .domain = RTE_SECURITY_PDCP_MODE_CONTROL,
+                        .capa_flags = 0
+                },
+                .crypto_capabilities = pmd_capabilities
+        },
         {
                 .action = RTE_SECURITY_ACTION_TYPE_NONE
         }
@@ -429,6 +490,7 @@ Security Session configuration structure is defined as ``rte_security_session_co
         union {
                 struct rte_security_ipsec_xform ipsec;
                 struct rte_security_macsec_xform macsec;
+                struct rte_security_pdcp_xform pdcp;
         };
         /**< Configuration parameters for security session */
         struct rte_crypto_sym_xform *crypto_xform;
@@ -463,15 +525,17 @@ The ``rte_security_session_protocol`` is defined as
 .. code-block:: c
 
     enum rte_security_session_protocol {
-        RTE_SECURITY_PROTOCOL_IPSEC,
+        RTE_SECURITY_PROTOCOL_IPSEC = 1,
         /**< IPsec Protocol */
         RTE_SECURITY_PROTOCOL_MACSEC,
         /**< MACSec Protocol */
+        RTE_SECURITY_PROTOCOL_PDCP,
+        /**< PDCP Protocol */
     };
 
-Currently the library defines configuration parameters for IPSec only. For other
-protocols like MACSec, structures and enums are defined as place holders which
-will be updated in the future.
+Currently the library defines configuration parameters for IPsec and PDCP only.
+For other protocols like MACSec, structures and enums are defined as place holders
+which will be updated in the future.
 
 IPsec related configuration parameters are defined in ``rte_security_ipsec_xform``
 
@@ -494,6 +558,35 @@ IPsec related configuration parameters are defined in ``rte_security_ipsec_xform
         /**< Tunnel parameters, NULL for transport mode */
     };
 
+PDCP related configuration parameters are defined in ``rte_security_pdcp_xform``
+
+.. code-block:: c
+
+    struct rte_security_pdcp_xform {
+        int8_t bearer;	/**< PDCP bearer ID */
+        /**< Enable in order delivery, this field shall be set only if
+         * driver/HW is capable. See RTE_SECURITY_PDCP_ORDERING_CAP.
+         */
+        uint8_t en_ordering;
+        /**< Notify driver/HW to detect and remove duplicate packets.
+         * This field should be set only when driver/hw is capable.
+         * See RTE_SECURITY_PDCP_DUP_DETECT_CAP.
+         */
+        uint8_t remove_duplicates;
+        /**< PDCP mode of operation: Control or data */
+        enum rte_security_pdcp_domain domain;
+        /**< PDCP Frame Direction 0:UL 1:DL */
+        enum rte_security_pdcp_direction pkt_dir;
+        /**< Sequence number size, 5/7/12/15/18 */
+        enum rte_security_pdcp_sn_size sn_size;
+        /**< Starting Hyper Frame Number to be used together with the SN
+         * from the PDCP frames
+         */
+        uint32_t hfn;
+        /**< HFN Threshold for key renegotiation */
+        uint32_t hfn_threshold;
+    };
+
 
 Security API
 ~~~~~~~~~~~~
diff --git a/lib/librte_security/rte_security.c b/lib/librte_security/rte_security.c
index 1954960a5..c6355de95 100644
--- a/lib/librte_security/rte_security.c
+++ b/lib/librte_security/rte_security.c
@@ -131,6 +131,10 @@ rte_security_capability_get(struct rte_security_ctx *instance,
 					capability->ipsec.direction ==
 							idx->ipsec.direction)
 					return capability;
+			} else if (idx->protocol == RTE_SECURITY_PROTOCOL_PDCP) {
+				if (capability->pdcp.domain ==
+							idx->pdcp.domain)
+					return capability;
 			}
 		}
 	}
diff --git a/lib/librte_security/rte_security.h b/lib/librte_security/rte_security.h
index b0d1b97ee..de49017e1 100644
--- a/lib/librte_security/rte_security.h
+++ b/lib/librte_security/rte_security.h
@@ -206,6 +206,66 @@ struct rte_security_macsec_xform {
 	int dummy;
 };
 
+/**
+ * PDCP Mode of session
+ */
+enum rte_security_pdcp_domain {
+	RTE_SECURITY_PDCP_MODE_CONTROL,	/**< PDCP control plane */
+	RTE_SECURITY_PDCP_MODE_DATA,	/**< PDCP data plane */
+};
+
+/** PDCP Frame direction */
+enum rte_security_pdcp_direction {
+	RTE_SECURITY_PDCP_UPLINK,	/**< Uplink */
+	RTE_SECURITY_PDCP_DOWNLINK,	/**< Downlink */
+};
+
+/**
+ * PDCP Sequence Number Size selectors
+ * @PDCP_SN_SIZE_5: 5bit sequence number
+ * @PDCP_SN_SIZE_7: 7bit sequence number
+ * @PDCP_SN_SIZE_12: 12bit sequence number
+ * @PDCP_SN_SIZE_15: 15bit sequence number
+ * @PDCP_SN_SIZE_18: 18bit sequence number
+ */
+enum rte_security_pdcp_sn_size {
+	RTE_SECURITY_PDCP_SN_SIZE_5 = 5,
+	RTE_SECURITY_PDCP_SN_SIZE_7 = 7,
+	RTE_SECURITY_PDCP_SN_SIZE_12 = 12,
+	RTE_SECURITY_PDCP_SN_SIZE_15 = 15,
+	RTE_SECURITY_PDCP_SN_SIZE_18 = 18
+};
+
+/**
+ * PDCP security association configuration data.
+ *
+ * This structure contains data required to create a PDCP security session.
+ */
+struct rte_security_pdcp_xform {
+	int8_t bearer;	/**< PDCP bearer ID */
+	/**< Enable in order delivery, this field shall be set only if
+	 * driver/HW is capable. See RTE_SECURITY_PDCP_ORDERING_CAP.
+	 */
+	uint8_t en_ordering;
+	/**< Notify driver/HW to detect and remove duplicate packets.
+	 * This field should be set only when driver/hw is capable.
+	 * See RTE_SECURITY_PDCP_DUP_DETECT_CAP.
+	 */
+	uint8_t remove_duplicates;
+	/**< PDCP mode of operation: Control or data */
+	enum rte_security_pdcp_domain domain;
+	/**< PDCP Frame Direction 0:UL 1:DL */
+	enum rte_security_pdcp_direction pkt_dir;
+	/**< Sequence number size, 5/7/12/15/18 */
+	enum rte_security_pdcp_sn_size sn_size;
+	/**< Starting Hyper Frame Number to be used together with the SN
+	 * from the PDCP frames
+	 */
+	uint32_t hfn;
+	/**< HFN Threshold for key renegotiation */
+	uint32_t hfn_threshold;
+};
+
 /**
  * Security session action type.
  */
@@ -232,6 +292,8 @@ enum rte_security_session_protocol {
 	/**< IPsec Protocol */
 	RTE_SECURITY_PROTOCOL_MACSEC,
 	/**< MACSec Protocol */
+	RTE_SECURITY_PROTOCOL_PDCP,
+	/**< PDCP Protocol */
 };
 
 /**
@@ -246,6 +308,7 @@ struct rte_security_session_conf {
 	union {
 		struct rte_security_ipsec_xform ipsec;
 		struct rte_security_macsec_xform macsec;
+		struct rte_security_pdcp_xform pdcp;
 	};
 	/**< Configuration parameters for security session */
 	struct rte_crypto_sym_xform *crypto_xform;
@@ -413,6 +476,10 @@ struct rte_security_ipsec_stats {
 
 };
 
+struct rte_security_pdcp_stats {
+	uint64_t reserved;
+};
+
 struct rte_security_stats {
 	enum rte_security_session_protocol protocol;
 	/**< Security protocol to be configured */
@@ -421,6 +488,7 @@ struct rte_security_stats {
 	union {
 		struct rte_security_macsec_stats macsec;
 		struct rte_security_ipsec_stats ipsec;
+		struct rte_security_pdcp_stats pdcp;
 	};
 };
 
@@ -465,6 +533,13 @@ struct rte_security_capability {
 			int dummy;
 		} macsec;
 		/**< MACsec capability */
+		struct {
+			enum rte_security_pdcp_domain domain;
+			/** < PDCP mode of operation: Control or data */
+			uint32_t capa_flags;
+			/** < Capabilitity flags, see RTE_SECURITY_PDCP_* */
+		} pdcp;
+		/**< PDCP capability */
 	};
 
 	const struct rte_cryptodev_capabilities *crypto_capabilities;
@@ -474,6 +549,19 @@ struct rte_security_capability {
 	/**< Device offload flags */
 };
 
+/**< Underlying Hardware/driver which support PDCP may or may not support
+ * packet ordering. Set RTE_SECURITY_PDCP_ORDERING_CAP if it support.
+ * If it is not set, driver/HW assumes packets received are in order
+ * and it will be application's responsibility to maintain ordering.
+ */
+#define RTE_SECURITY_PDCP_ORDERING_CAP		0x00000001
+
+/**< Underlying Hardware/driver which support PDCP may or may not detect
+ * duplicate packet. Set RTE_SECURITY_PDCP_DUP_DETECT_CAP if it support.
+ * If it is not set, driver/HW assumes there is no duplicate packet received.
+ */
+#define RTE_SECURITY_PDCP_DUP_DETECT_CAP	0x00000002
+
 #define RTE_SECURITY_TX_OLOAD_NEED_MDATA	0x00000001
 /**< HW needs metadata update, see rte_security_set_pkt_metadata().
  */
@@ -506,6 +594,10 @@ struct rte_security_capability_idx {
 			enum rte_security_ipsec_sa_mode mode;
 			enum rte_security_ipsec_sa_direction direction;
 		} ipsec;
+		struct {
+			enum rte_security_pdcp_domain domain;
+			uint32_t capa_flags;
+		} pdcp;
 	};
 };
 
-- 
2.17.1

^ permalink raw reply	[flat|nested] 41+ messages in thread

* [dpdk-dev] [PATCH v5 2/3] crypto/dpaa2_sec: add sample pdcp descriptor apis
  2018-10-16 10:38       ` [dpdk-dev] [PATCH v5 0/3] security: support for pdcp Akhil Goyal
  2018-10-16 10:39         ` [dpdk-dev] [PATCH v5 1/3] security: support pdcp protocol Akhil Goyal
@ 2018-10-16 10:39         ` Akhil Goyal
  2018-10-16 10:39         ` [dpdk-dev] [PATCH v5 3/3] crypto/dpaa2_sec: support pdcp offload Akhil Goyal
                           ` (2 subsequent siblings)
  4 siblings, 0 replies; 41+ messages in thread
From: Akhil Goyal @ 2018-10-16 10:39 UTC (permalink / raw)
  To: dev
  Cc: pablo.de.lara.guarch, radu.nicolau, jerin.jacob,
	narayanaprasad.athreya, Shally.Verma, Anoob.Joseph,
	Vidya.Velumuri, Hemant Agrawal, Akhil Goyal

From: Akhil Goyal <akhil.goyal@nxp.com>

DPAA2 SEC platform can support look aside protocol
offload for PDCP protocol.

The relevant APIs for configuring the hardware for PDCP
is added for various modes and crypto algorithms.

Signed-off-by: Hemant Agrawal <hemant.agrawal@nxp.com>
Signed-off-by: Horia Geanta Neag <horia.geanta@nxp.com>
Signed-off-by: Alex Porosanu <alexandru.porosanu@nxp.com>
Signed-off-by: Akhil Goyal <akhil.goyal@nxp.com>
---
 drivers/crypto/dpaa2_sec/hw/desc.h      |    2 +-
 drivers/crypto/dpaa2_sec/hw/desc/pdcp.h | 2796 +++++++++++++++++++++++
 2 files changed, 2797 insertions(+), 1 deletion(-)
 create mode 100644 drivers/crypto/dpaa2_sec/hw/desc/pdcp.h

diff --git a/drivers/crypto/dpaa2_sec/hw/desc.h b/drivers/crypto/dpaa2_sec/hw/desc.h
index ca94ea3ff..5d99dd8af 100644
--- a/drivers/crypto/dpaa2_sec/hw/desc.h
+++ b/drivers/crypto/dpaa2_sec/hw/desc.h
@@ -868,7 +868,7 @@
 #define OP_PCL_LTE_MIXED_AUTH_SHIFT	0
 #define OP_PCL_LTE_MIXED_AUTH_MASK	(3 << OP_PCL_LTE_MIXED_AUTH_SHIFT)
 #define OP_PCL_LTE_MIXED_ENC_SHIFT	8
-#define OP_PCL_LTE_MIXED_ENC_MASK	(3 < OP_PCL_LTE_MIXED_ENC_SHIFT)
+#define OP_PCL_LTE_MIXED_ENC_MASK	(3 << OP_PCL_LTE_MIXED_ENC_SHIFT)
 #define OP_PCL_LTE_MIXED_AUTH_NULL	(OP_PCL_LTE_NULL << \
 					 OP_PCL_LTE_MIXED_AUTH_SHIFT)
 #define OP_PCL_LTE_MIXED_AUTH_SNOW	(OP_PCL_LTE_SNOW << \
diff --git a/drivers/crypto/dpaa2_sec/hw/desc/pdcp.h b/drivers/crypto/dpaa2_sec/hw/desc/pdcp.h
new file mode 100644
index 000000000..719ef605f
--- /dev/null
+++ b/drivers/crypto/dpaa2_sec/hw/desc/pdcp.h
@@ -0,0 +1,2796 @@
+/*
+ * Copyright 2008-2013 Freescale Semiconductor, Inc.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause or GPL-2.0+
+ */
+
+#ifndef __DESC_PDCP_H__
+#define __DESC_PDCP_H__
+
+#include "hw/rta.h"
+#include "common.h"
+
+/**
+ * DOC: PDCP Shared Descriptor Constructors
+ *
+ * Shared descriptors for PDCP protocol.
+ */
+
+/**
+ * PDCP_NULL_MAX_FRAME_LEN - The maximum frame frame length that is supported by
+ *                           PDCP NULL protocol.
+ */
+#define PDCP_NULL_MAX_FRAME_LEN		0x00002FFF
+
+/**
+ * PDCP_MAC_I_LEN - The length of the MAC-I for PDCP protocol operation
+ */
+#define PDCP_MAC_I_LEN			0x00000004
+
+/**
+ * PDCP_MAX_FRAME_LEN_STATUS - The status returned in FD status/command field in
+ *                             case the input frame is larger than
+ *                             PDCP_NULL_MAX_FRAME_LEN.
+ */
+#define PDCP_MAX_FRAME_LEN_STATUS	0xF1
+
+/**
+ * PDCP_C_PLANE_SN_MASK - This mask is used in the PDCP descriptors for
+ *                        extracting the sequence number (SN) from the PDCP
+ *                        Control Plane header. For PDCP Control Plane, the SN
+ *                        is constant (5 bits) as opposed to PDCP Data Plane
+ *                        (7/12/15 bits).
+ */
+#define PDCP_C_PLANE_SN_MASK		0x1F000000
+#define PDCP_C_PLANE_SN_MASK_BE		0x0000001F
+
+/**
+ * PDCP_U_PLANE_15BIT_SN_MASK - This mask is used in the PDCP descriptors for
+ *                              extracting the sequence number (SN) from the
+ *                              PDCP User Plane header. For PDCP Control Plane,
+ *                              the SN is constant (5 bits) as opposed to PDCP
+ *                              Data Plane (7/12/15 bits).
+ */
+#define PDCP_U_PLANE_15BIT_SN_MASK	0xFF7F0000
+#define PDCP_U_PLANE_15BIT_SN_MASK_BE	0x00007FFF
+
+/**
+ * PDCP_BEARER_MASK - This mask is used masking out the bearer for PDCP
+ *                    processing with SNOW f9 in LTE.
+ *
+ * The value on which this mask is applied is formatted as below:
+ *     Count-C (32 bit) | Bearer (5 bit) | Direction (1 bit) | 0 (26 bits)
+ *
+ * Applying this mask is done for creating the upper 64 bits of the IV needed
+ * for SNOW f9.
+ *
+ * The lower 32 bits of the mask are used for masking the direction for AES
+ * CMAC IV.
+ */
+#define PDCP_BEARER_MASK		0x00000004FFFFFFFFull
+#define PDCP_BEARER_MASK_BE		0xFFFFFFFF04000000ull
+
+/**
+ * PDCP_DIR_MASK - This mask is used masking out the direction for PDCP
+ *                 processing with SNOW f9 in LTE.
+ *
+ * The value on which this mask is applied is formatted as below:
+ *     Bearer (5 bit) | Direction (1 bit) | 0 (26 bits)
+ *
+ * Applying this mask is done for creating the lower 32 bits of the IV needed
+ * for SNOW f9.
+ *
+ * The upper 32 bits of the mask are used for masking the direction for AES
+ * CMAC IV.
+ */
+#define PDCP_DIR_MASK			0x00000000000000F8ull
+#define PDCP_DIR_MASK_BE			0xF800000000000000ull
+
+/**
+ * PDCP_NULL_INT_MAC_I_VAL - The value of the PDCP PDU MAC-I in case NULL
+ *                           integrity is used.
+ */
+
+#define PDCP_NULL_INT_MAC_I_VAL		0x00000000
+
+/**
+ * PDCP_NULL_INT_ICV_CHECK_FAILED_STATUS - The status used to report ICV check
+ *                                         failed in case of NULL integrity
+ *                                         Control Plane processing.
+ */
+#define PDCP_NULL_INT_ICV_CHECK_FAILED_STATUS	0x0A
+/**
+ * PDCP_DPOVRD_HFN_OV_EN - Value to be used in the FD status/cmd field to
+ *                         indicate the HFN override mechanism is active for the
+ *                         frame.
+ */
+#define PDCP_DPOVRD_HFN_OV_EN		0x80000000
+
+/**
+ * PDCP_P4080REV2_HFN_OV_BUFLEN - The length in bytes of the supplementary space
+ *                                that must be provided by the user at the
+ *                                beginning of the input frame buffer for
+ *                                P4080 REV 2.
+ *
+ * The format of the frame buffer is the following:
+ *
+ *  |<---PDCP_P4080REV2_HFN_OV_BUFLEN-->|
+ * //===================================||============||==============\\
+ * || PDCP_DPOVRD_HFN_OV_EN | HFN value || PDCP Header|| PDCP Payload ||
+ * \\===================================||============||==============//
+ *
+ * If HFN override mechanism is not desired, then the MSB of the first 4 bytes
+ * must be set to 0b.
+ */
+#define PDCP_P4080REV2_HFN_OV_BUFLEN	4
+
+/**
+ * enum cipher_type_pdcp - Type selectors for cipher types in PDCP protocol OP
+ *                         instructions.
+ * @PDCP_CIPHER_TYPE_NULL: NULL
+ * @PDCP_CIPHER_TYPE_SNOW: SNOW F8
+ * @PDCP_CIPHER_TYPE_AES: AES
+ * @PDCP_CIPHER_TYPE_ZUC: ZUCE
+ * @PDCP_CIPHER_TYPE_INVALID: invalid option
+ */
+enum cipher_type_pdcp {
+	PDCP_CIPHER_TYPE_NULL,
+	PDCP_CIPHER_TYPE_SNOW,
+	PDCP_CIPHER_TYPE_AES,
+	PDCP_CIPHER_TYPE_ZUC,
+	PDCP_CIPHER_TYPE_INVALID
+};
+
+/**
+ * enum auth_type_pdcp - Type selectors for integrity types in PDCP protocol OP
+ *                       instructions.
+ * @PDCP_AUTH_TYPE_NULL: NULL
+ * @PDCP_AUTH_TYPE_SNOW: SNOW F9
+ * @PDCP_AUTH_TYPE_AES: AES CMAC
+ * @PDCP_AUTH_TYPE_ZUC: ZUCA
+ * @PDCP_AUTH_TYPE_INVALID: invalid option
+ */
+enum auth_type_pdcp {
+	PDCP_AUTH_TYPE_NULL,
+	PDCP_AUTH_TYPE_SNOW,
+	PDCP_AUTH_TYPE_AES,
+	PDCP_AUTH_TYPE_ZUC,
+	PDCP_AUTH_TYPE_INVALID
+};
+
+/**
+ * enum pdcp_dir - Type selectors for direction for PDCP protocol
+ * @PDCP_DIR_UPLINK: uplink direction
+ * @PDCP_DIR_DOWNLINK: downlink direction
+ * @PDCP_DIR_INVALID: invalid option
+ */
+enum pdcp_dir {
+	PDCP_DIR_UPLINK = 0,
+	PDCP_DIR_DOWNLINK = 1,
+	PDCP_DIR_INVALID
+};
+
+/**
+ * enum pdcp_plane - PDCP domain selectors
+ * @PDCP_CONTROL_PLANE: Control Plane
+ * @PDCP_DATA_PLANE: Data Plane
+ * @PDCP_SHORT_MAC: Short MAC
+ */
+enum pdcp_plane {
+	PDCP_CONTROL_PLANE,
+	PDCP_DATA_PLANE,
+	PDCP_SHORT_MAC
+};
+
+/**
+ * enum pdcp_sn_size - Sequence Number Size selectors for PDCP protocol
+ * @PDCP_SN_SIZE_5: 5bit sequence number
+ * @PDCP_SN_SIZE_7: 7bit sequence number
+ * @PDCP_SN_SIZE_12: 12bit sequence number
+ * @PDCP_SN_SIZE_15: 15bit sequence number
+ * @PDCP_SN_SIZE_18: 18bit sequence number
+ */
+enum pdcp_sn_size {
+	PDCP_SN_SIZE_5 = 5,
+	PDCP_SN_SIZE_7 = 7,
+	PDCP_SN_SIZE_12 = 12,
+	PDCP_SN_SIZE_15 = 15
+};
+
+/*
+ * PDCP Control Plane Protocol Data Blocks
+ */
+#define PDCP_C_PLANE_PDB_HFN_SHIFT		5
+#define PDCP_C_PLANE_PDB_BEARER_SHIFT		27
+#define PDCP_C_PLANE_PDB_DIR_SHIFT		26
+#define PDCP_C_PLANE_PDB_HFN_THR_SHIFT		5
+
+#define PDCP_U_PLANE_PDB_OPT_SHORT_SN		0x2
+#define PDCP_U_PLANE_PDB_OPT_15B_SN		0x4
+#define PDCP_U_PLANE_PDB_SHORT_SN_HFN_SHIFT	7
+#define PDCP_U_PLANE_PDB_LONG_SN_HFN_SHIFT	12
+#define PDCP_U_PLANE_PDB_15BIT_SN_HFN_SHIFT	15
+#define PDCP_U_PLANE_PDB_BEARER_SHIFT		27
+#define PDCP_U_PLANE_PDB_DIR_SHIFT		26
+#define PDCP_U_PLANE_PDB_SHORT_SN_HFN_THR_SHIFT	7
+#define PDCP_U_PLANE_PDB_LONG_SN_HFN_THR_SHIFT	12
+#define PDCP_U_PLANE_PDB_15BIT_SN_HFN_THR_SHIFT	15
+
+struct pdcp_pdb {
+	union {
+		uint32_t opt;
+		uint32_t rsvd;
+	} opt_res;
+	uint32_t hfn_res;	/* HyperFrame number,(27, 25 or 21 bits),
+				 * left aligned & right-padded with zeros.
+				 */
+	uint32_t bearer_dir_res;/* Bearer(5 bits), packet direction (1 bit),
+				 * left aligned & right-padded with zeros.
+				 */
+	uint32_t hfn_thr_res;	/* HyperFrame number threshold (27, 25 or 21
+				 * bits), left aligned & right-padded with
+				 * zeros.
+				 */
+};
+
+/*
+ * PDCP internal PDB types
+ */
+enum pdb_type_e {
+	PDCP_PDB_TYPE_NO_PDB,
+	PDCP_PDB_TYPE_FULL_PDB,
+	PDCP_PDB_TYPE_REDUCED_PDB,
+	PDCP_PDB_TYPE_INVALID
+};
+
+/*
+ * Function for appending the portion of a PDCP Control Plane shared descriptor
+ * which performs NULL encryption and integrity (i.e. copies the input frame
+ * to the output frame, appending 32 bits of zeros at the end (MAC-I for
+ * NULL integrity).
+ */
+static inline int
+pdcp_insert_cplane_null_op(struct program *p,
+			   bool swap __maybe_unused,
+			   struct alginfo *cipherdata __maybe_unused,
+			   struct alginfo *authdata __maybe_unused,
+			   unsigned int dir,
+			   unsigned char era_2_sw_hfn_ovrd __maybe_unused)
+{
+	LABEL(local_offset);
+	REFERENCE(move_cmd_read_descbuf);
+	REFERENCE(move_cmd_write_descbuf);
+
+	if (rta_sec_era > RTA_SEC_ERA_2) {
+		MATHB(p, SEQINSZ, ADD, ZERO, VSEQINSZ, 4, 0);
+		if (dir == OP_TYPE_ENCAP_PROTOCOL)
+			MATHB(p, SEQINSZ, ADD, PDCP_MAC_I_LEN, VSEQOUTSZ, 4,
+			      IMMED2);
+		else
+			MATHB(p, SEQINSZ, SUB, PDCP_MAC_I_LEN, VSEQOUTSZ, 4,
+			      IMMED2);
+	} else {
+		MATHB(p, SEQINSZ, ADD, ONE, VSEQINSZ, 4, 0);
+		MATHB(p, VSEQINSZ, SUB, ONE, VSEQINSZ, 4, 0);
+
+		if (dir == OP_TYPE_ENCAP_PROTOCOL) {
+			MATHB(p, SEQINSZ, ADD, PDCP_MAC_I_LEN, VSEQOUTSZ, 4,
+			      IMMED2);
+			MATHB(p, VSEQINSZ, SUB, ONE, MATH0, 4, 0);
+		} else {
+			MATHB(p, VSEQINSZ, SUB, PDCP_MAC_I_LEN, VSEQINSZ, 4,
+			      IMMED2);
+			MATHB(p, SEQINSZ, SUB, PDCP_MAC_I_LEN, VSEQOUTSZ, 4,
+			      IMMED2);
+			MATHB(p, VSEQOUTSZ, SUB, ONE, MATH0, 4, 0);
+		}
+
+		MATHB(p, MATH0, ADD, ONE, MATH0, 4, 0);
+
+		/*
+		 * Since MOVELEN is available only starting with
+		 * SEC ERA 3, use poor man's MOVELEN: create a MOVE
+		 * command dynamically by writing the length from M1 by
+		 * OR-ing the command in the M1 register and MOVE the
+		 * result into the descriptor buffer. Care must be taken
+		 * wrt. the location of the command because of SEC
+		 * pipelining. The actual MOVEs are written at the end
+		 * of the descriptor due to calculations needed on the
+		 * offset in the descriptor for the MOVE command.
+		 */
+		move_cmd_read_descbuf = MOVE(p, DESCBUF, 0, MATH0, 0, 6,
+					     IMMED);
+		move_cmd_write_descbuf = MOVE(p, MATH0, 0, DESCBUF, 0, 8,
+					      WAITCOMP | IMMED);
+	}
+	MATHB(p, VSEQINSZ, SUB, PDCP_NULL_MAX_FRAME_LEN, NONE, 4,
+	      IMMED2);
+	JUMP(p, PDCP_MAX_FRAME_LEN_STATUS, HALT_STATUS, ALL_FALSE, MATH_N);
+
+	if (rta_sec_era > RTA_SEC_ERA_2) {
+		if (dir == OP_TYPE_ENCAP_PROTOCOL)
+			MATHB(p, VSEQINSZ, ADD, ZERO, MATH0, 4, 0);
+		else
+			MATHB(p, VSEQOUTSZ, ADD, ZERO, MATH0, 4, 0);
+	}
+	SEQFIFOSTORE(p, MSG, 0, 0, VLF);
+	SEQFIFOLOAD(p, MSG1, 0, VLF | LAST1 | FLUSH1);
+
+	if (rta_sec_era > RTA_SEC_ERA_2) {
+		MOVE(p, AB1, 0, OFIFO, 0, MATH0, 0);
+	} else {
+		SET_LABEL(p, local_offset);
+
+		/* Shut off automatic Info FIFO entries */
+		LOAD(p, 0, DCTRL, LDOFF_DISABLE_AUTO_NFIFO, 0, IMMED);
+		/* Placeholder for MOVE command with length from M1 register */
+		MOVE(p, IFIFOAB1, 0, OFIFO, 0, 0, IMMED);
+		/* Enable automatic Info FIFO entries */
+		LOAD(p, 0, DCTRL, LDOFF_ENABLE_AUTO_NFIFO, 0, IMMED);
+	}
+
+	if (dir == OP_TYPE_ENCAP_PROTOCOL) {
+		MATHB(p, MATH1, XOR, MATH1, MATH0, 8, 0);
+		MOVE(p, MATH0, 0, OFIFO, 0, 4, IMMED);
+	}
+
+	if (rta_sec_era < RTA_SEC_ERA_3) {
+		PATCH_MOVE(p, move_cmd_read_descbuf, local_offset);
+		PATCH_MOVE(p, move_cmd_write_descbuf, local_offset);
+	}
+
+	return 0;
+}
+
+static inline int
+insert_copy_frame_op(struct program *p,
+		     struct alginfo *cipherdata __maybe_unused,
+		     unsigned int dir __maybe_unused)
+{
+	LABEL(local_offset);
+	REFERENCE(move_cmd_read_descbuf);
+	REFERENCE(move_cmd_write_descbuf);
+
+	if (rta_sec_era > RTA_SEC_ERA_2) {
+		MATHB(p, SEQINSZ, ADD, ZERO, VSEQINSZ,  4, 0);
+		MATHB(p, SEQINSZ, ADD, ZERO, VSEQOUTSZ,  4, 0);
+	} else {
+		MATHB(p, SEQINSZ, ADD, ONE, VSEQINSZ,  4, 0);
+		MATHB(p, VSEQINSZ, SUB, ONE, VSEQINSZ,  4, 0);
+		MATHB(p, SEQINSZ, ADD, ONE, VSEQOUTSZ,  4, 0);
+		MATHB(p, VSEQOUTSZ, SUB, ONE, VSEQOUTSZ,  4, 0);
+		MATHB(p, VSEQINSZ, SUB, ONE, MATH0,  4, 0);
+		MATHB(p, MATH0, ADD, ONE, MATH0,  4, 0);
+
+		/*
+		 * Since MOVELEN is available only starting with
+		 * SEC ERA 3, use poor man's MOVELEN: create a MOVE
+		 * command dynamically by writing the length from M1 by
+		 * OR-ing the command in the M1 register and MOVE the
+		 * result into the descriptor buffer. Care must be taken
+		 * wrt. the location of the command because of SEC
+		 * pipelining. The actual MOVEs are written at the end
+		 * of the descriptor due to calculations needed on the
+		 * offset in the descriptor for the MOVE command.
+		 */
+		move_cmd_read_descbuf = MOVE(p, DESCBUF, 0, MATH0, 0, 6,
+					     IMMED);
+		move_cmd_write_descbuf = MOVE(p, MATH0, 0, DESCBUF, 0, 8,
+					      WAITCOMP | IMMED);
+	}
+	MATHB(p, SEQINSZ, SUB, PDCP_NULL_MAX_FRAME_LEN, NONE,  4,
+	      IFB | IMMED2);
+	JUMP(p, PDCP_MAX_FRAME_LEN_STATUS, HALT_STATUS, ALL_FALSE, MATH_N);
+
+	if (rta_sec_era > RTA_SEC_ERA_2)
+		MATHB(p, VSEQINSZ, ADD, ZERO, MATH0,  4, 0);
+
+	SEQFIFOLOAD(p, MSG1, 0, VLF | LAST1 | FLUSH1);
+	if (rta_sec_era > RTA_SEC_ERA_2) {
+		MOVE(p, AB1, 0, OFIFO, 0, MATH0, 0);
+	} else {
+		SET_LABEL(p, local_offset);
+
+		/* Shut off automatic Info FIFO entries */
+		LOAD(p, 0, DCTRL, LDOFF_DISABLE_AUTO_NFIFO, 0, IMMED);
+
+		/* Placeholder for MOVE command with length from M0 register */
+		MOVE(p, IFIFOAB1, 0, OFIFO, 0, 0, IMMED);
+
+		/* Enable automatic Info FIFO entries */
+		LOAD(p, 0, DCTRL, LDOFF_ENABLE_AUTO_NFIFO, 0, IMMED);
+	}
+
+	SEQFIFOSTORE(p, MSG, 0, 0, VLF);
+
+	if (rta_sec_era < RTA_SEC_ERA_3) {
+		PATCH_MOVE(p, move_cmd_read_descbuf, local_offset);
+		PATCH_MOVE(p, move_cmd_write_descbuf, local_offset);
+	}
+	return 0;
+}
+
+static inline int
+pdcp_insert_cplane_int_only_op(struct program *p,
+			       bool swap __maybe_unused,
+			       struct alginfo *cipherdata __maybe_unused,
+			       struct alginfo *authdata, unsigned int dir,
+			       unsigned char era_2_sw_hfn_ovrd)
+{
+	LABEL(local_offset);
+	REFERENCE(move_cmd_read_descbuf);
+	REFERENCE(move_cmd_write_descbuf);
+
+	switch (authdata->algtype) {
+	case PDCP_AUTH_TYPE_SNOW:
+		/* Insert Auth Key */
+		KEY(p, KEY2, authdata->key_enc_flags, authdata->key,
+		    authdata->keylen, INLINE_KEY(authdata));
+		SEQLOAD(p, MATH0, 7, 1, 0);
+		JUMP(p, 1, LOCAL_JUMP, ALL_TRUE, CALM);
+
+		if (rta_sec_era > RTA_SEC_ERA_2 ||
+		    (rta_sec_era == RTA_SEC_ERA_2 &&
+				   era_2_sw_hfn_ovrd == 0)) {
+			SEQINPTR(p, 0, 1, RTO);
+		} else {
+			SEQINPTR(p, 0, 5, RTO);
+			SEQFIFOLOAD(p, SKIP, 4, 0);
+		}
+
+		if (swap == false) {
+			MATHB(p, MATH0, AND, PDCP_C_PLANE_SN_MASK, MATH1,  8,
+			      IFB | IMMED2);
+			MATHB(p, MATH1, SHLD, MATH1, MATH1,  8, 0);
+
+			MOVEB(p, DESCBUF, 8, MATH2, 0, 8, WAITCOMP | IMMED);
+
+			MATHB(p, MATH2, AND, PDCP_BEARER_MASK, MATH2, 8,
+			      IMMED2);
+			MOVEB(p, DESCBUF, 0x0C, MATH3, 0, 4, WAITCOMP | IMMED);
+			MATHB(p, MATH3, AND, PDCP_DIR_MASK, MATH3, 8, IMMED2);
+			MATHB(p, MATH1, OR, MATH2, MATH2, 8, 0);
+			MOVEB(p, MATH2, 0, CONTEXT2, 0, 0x0C, WAITCOMP | IMMED);
+		} else {
+			MATHB(p, MATH0, AND, PDCP_C_PLANE_SN_MASK_BE, MATH1,  8,
+			      IFB | IMMED2);
+			MATHB(p, MATH1, SHLD, MATH1, MATH1,  8, 0);
+
+			MOVE(p, DESCBUF, 8, MATH2, 0, 8, WAITCOMP | IMMED);
+			MATHB(p, MATH2, AND, PDCP_BEARER_MASK_BE, MATH2, 8,
+			      IMMED2);
+
+			MOVE(p, DESCBUF, 0x0C, MATH3, 0, 4, WAITCOMP | IMMED);
+			MATHB(p, MATH3, AND, PDCP_DIR_MASK_BE, MATH3, 8,
+			      IMMED2);
+			MATHB(p, MATH1, OR, MATH2, MATH2, 8, 0);
+			MOVE(p, MATH2, 0, CONTEXT2, 0, 0x0C, WAITCOMP | IMMED);
+		}
+
+		if (dir == OP_TYPE_DECAP_PROTOCOL) {
+			MATHB(p, SEQINSZ, SUB, PDCP_MAC_I_LEN, MATH1, 4,
+			      IMMED2);
+		} else {
+			if (rta_sec_era > RTA_SEC_ERA_2) {
+				MATHB(p, SEQINSZ, SUB, ZERO, MATH1, 4,
+				      0);
+			} else {
+				MATHB(p, SEQINSZ, ADD, ONE, MATH1, 4,
+				      0);
+				MATHB(p, MATH1, SUB, ONE, MATH1, 4,
+				      0);
+			}
+		}
+
+		if (rta_sec_era > RTA_SEC_ERA_2) {
+			MATHB(p, MATH1, SUB, ZERO, VSEQINSZ, 4, 0);
+			MATHB(p, MATH1, SUB, ZERO, VSEQOUTSZ, 4, 0);
+		} else {
+			MATHB(p, ZERO, ADD, MATH1, VSEQINSZ, 4, 0);
+			MATHB(p, ZERO, ADD, MATH1, VSEQOUTSZ, 4, 0);
+
+			/*
+			 * Since MOVELEN is available only starting with
+			 * SEC ERA 3, use poor man's MOVELEN: create a MOVE
+			 * command dynamically by writing the length from M1 by
+			 * OR-ing the command in the M1 register and MOVE the
+			 * result into the descriptor buffer. Care must be taken
+			 * wrt. the location of the command because of SEC
+			 * pipelining. The actual MOVEs are written at the end
+			 * of the descriptor due to calculations needed on the
+			 * offset in the descriptor for the MOVE command.
+			 */
+			move_cmd_read_descbuf = MOVE(p, DESCBUF, 0, MATH1, 0, 6,
+						     IMMED);
+			move_cmd_write_descbuf = MOVE(p, MATH1, 0, DESCBUF, 0,
+						      8, WAITCOMP | IMMED);
+		}
+
+		SEQFIFOSTORE(p, MSG, 0, 0, VLF);
+		ALG_OPERATION(p, OP_ALG_ALGSEL_SNOW_F9, OP_ALG_AAI_F9,
+			      OP_ALG_AS_INITFINAL,
+			      dir == OP_TYPE_ENCAP_PROTOCOL ?
+				     ICV_CHECK_DISABLE : ICV_CHECK_ENABLE,
+			      DIR_ENC);
+
+		if (rta_sec_era > RTA_SEC_ERA_2) {
+			SEQFIFOLOAD(p, MSGINSNOOP, 0,
+				    VLF | LAST1 | LAST2 | FLUSH1);
+			MOVE(p, AB1, 0, OFIFO, 0, MATH1, 0);
+		} else {
+			SEQFIFOLOAD(p, MSGINSNOOP, 0,
+				    VLF | LAST1 | LAST2 | FLUSH1);
+			SET_LABEL(p, local_offset);
+
+			/* Shut off automatic Info FIFO entries */
+			LOAD(p, 0, DCTRL, LDOFF_DISABLE_AUTO_NFIFO, 0, IMMED);
+			/*
+			 * Placeholder for MOVE command with length from M1
+			 * register
+			 */
+			MOVE(p, IFIFOAB1, 0, OFIFO, 0, 0, IMMED);
+			/* Enable automatic Info FIFO entries */
+			LOAD(p, 0, DCTRL, LDOFF_ENABLE_AUTO_NFIFO, 0, IMMED);
+		}
+
+		if (dir == OP_TYPE_DECAP_PROTOCOL)
+			SEQFIFOLOAD(p, ICV2, 4, LAST2);
+		else
+			SEQSTORE(p, CONTEXT2, 0, 4, 0);
+
+		break;
+
+	case PDCP_AUTH_TYPE_AES:
+		/* Insert Auth Key */
+		KEY(p, KEY1, authdata->key_enc_flags, authdata->key,
+		    authdata->keylen, INLINE_KEY(authdata));
+		SEQLOAD(p, MATH0, 7, 1, 0);
+		JUMP(p, 1, LOCAL_JUMP, ALL_TRUE, CALM);
+		if (rta_sec_era > RTA_SEC_ERA_2 ||
+		    (rta_sec_era == RTA_SEC_ERA_2 &&
+		     era_2_sw_hfn_ovrd == 0)) {
+			SEQINPTR(p, 0, 1, RTO);
+		} else {
+			SEQINPTR(p, 0, 5, RTO);
+			SEQFIFOLOAD(p, SKIP, 4, 0);
+		}
+
+		if (swap == false) {
+			MATHB(p, MATH0, AND, PDCP_C_PLANE_SN_MASK, MATH1, 8,
+			      IFB | IMMED2);
+			MATHB(p, MATH1, SHLD, MATH1, MATH1, 8, 0);
+
+			MOVEB(p, DESCBUF, 8, MATH2, 0, 8, WAITCOMP | IMMED);
+			MATHB(p, MATH1, OR, MATH2, MATH2, 8, 0);
+			MOVEB(p, MATH2, 0, IFIFOAB1, 0, 8, IMMED);
+		} else {
+			MATHB(p, MATH0, AND, PDCP_C_PLANE_SN_MASK_BE, MATH1, 8,
+			      IFB | IMMED2);
+			MATHB(p, MATH1, SHLD, MATH1, MATH1, 8, 0);
+
+			MOVE(p, DESCBUF, 8, MATH2, 0, 8, WAITCOMP | IMMED);
+			MATHB(p, MATH1, OR, MATH2, MATH2, 8, 0);
+			MOVE(p, MATH2, 0, IFIFOAB1, 0, 8, IMMED);
+		}
+
+		if (dir == OP_TYPE_DECAP_PROTOCOL) {
+			MATHB(p, SEQINSZ, SUB, PDCP_MAC_I_LEN, MATH1, 4,
+			      IMMED2);
+		} else {
+			if (rta_sec_era > RTA_SEC_ERA_2) {
+				MATHB(p, SEQINSZ, SUB, ZERO, MATH1, 4,
+				      0);
+			} else {
+				MATHB(p, SEQINSZ, ADD, ONE, MATH1, 4,
+				      0);
+				MATHB(p, MATH1, SUB, ONE, MATH1, 4,
+				      0);
+			}
+		}
+
+		if (rta_sec_era > RTA_SEC_ERA_2) {
+			MATHB(p, MATH1, SUB, ZERO, VSEQINSZ, 4, 0);
+			MATHB(p, MATH1, SUB, ZERO, VSEQOUTSZ, 4, 0);
+		} else {
+			MATHB(p, ZERO, ADD, MATH1, VSEQINSZ, 4, 0);
+			MATHB(p, ZERO, ADD, MATH1, VSEQOUTSZ, 4, 0);
+
+			/*
+			 * Since MOVELEN is available only starting with
+			 * SEC ERA 3, use poor man's MOVELEN: create a MOVE
+			 * command dynamically by writing the length from M1 by
+			 * OR-ing the command in the M1 register and MOVE the
+			 * result into the descriptor buffer. Care must be taken
+			 * wrt. the location of the command because of SEC
+			 * pipelining. The actual MOVEs are written at the end
+			 * of the descriptor due to calculations needed on the
+			 * offset in the descriptor for the MOVE command.
+			 */
+			move_cmd_read_descbuf = MOVE(p, DESCBUF, 0, MATH1, 0, 6,
+						     IMMED);
+			move_cmd_write_descbuf = MOVE(p, MATH1, 0, DESCBUF, 0,
+						      8, WAITCOMP | IMMED);
+		}
+		SEQFIFOSTORE(p, MSG, 0, 0, VLF);
+		ALG_OPERATION(p, OP_ALG_ALGSEL_AES,
+			      OP_ALG_AAI_CMAC,
+			      OP_ALG_AS_INITFINAL,
+			      dir == OP_TYPE_ENCAP_PROTOCOL ?
+				     ICV_CHECK_DISABLE : ICV_CHECK_ENABLE,
+			      DIR_ENC);
+
+		if (rta_sec_era > RTA_SEC_ERA_2) {
+			MOVE(p, AB2, 0, OFIFO, 0, MATH1, 0);
+			SEQFIFOLOAD(p, MSGINSNOOP, 0,
+				    VLF | LAST1 | LAST2 | FLUSH1);
+		} else {
+			SEQFIFOLOAD(p, MSGINSNOOP, 0,
+				    VLF | LAST1 | LAST2 | FLUSH1);
+			SET_LABEL(p, local_offset);
+
+			/* Shut off automatic Info FIFO entries */
+			LOAD(p, 0, DCTRL, LDOFF_DISABLE_AUTO_NFIFO, 0, IMMED);
+
+			/*
+			 * Placeholder for MOVE command with length from
+			 * M1 register
+			 */
+			MOVE(p, IFIFOAB2, 0, OFIFO, 0, 0, IMMED);
+
+			/* Enable automatic Info FIFO entries */
+			LOAD(p, 0, DCTRL, LDOFF_ENABLE_AUTO_NFIFO, 0, IMMED);
+		}
+
+		if (dir == OP_TYPE_DECAP_PROTOCOL)
+			SEQFIFOLOAD(p, ICV1, 4, LAST1 | FLUSH1);
+		else
+			SEQSTORE(p, CONTEXT1, 0, 4, 0);
+
+		break;
+
+	case PDCP_AUTH_TYPE_ZUC:
+		if (rta_sec_era < RTA_SEC_ERA_5) {
+			pr_err("Invalid era for selected algorithm\n");
+			return -ENOTSUP;
+		}
+		/* Insert Auth Key */
+		KEY(p, KEY2, authdata->key_enc_flags, authdata->key,
+		    authdata->keylen, INLINE_KEY(authdata));
+		SEQLOAD(p, MATH0, 7, 1, 0);
+		JUMP(p, 1, LOCAL_JUMP, ALL_TRUE, CALM);
+		SEQINPTR(p, 0, 1, RTO);
+		if (swap == false) {
+			MATHB(p, MATH0, AND, PDCP_C_PLANE_SN_MASK, MATH1, 8,
+			      IFB | IMMED2);
+			MATHB(p, MATH1, SHLD, MATH1, MATH1, 8, 0);
+
+			MOVEB(p, DESCBUF, 8, MATH2, 0, 8, WAITCOMP | IMMED);
+			MATHB(p, MATH1, OR, MATH2, MATH2, 8, 0);
+			MOVEB(p, MATH2, 0, CONTEXT2, 0, 8, IMMED);
+
+		} else {
+			MATHB(p, MATH0, AND, PDCP_C_PLANE_SN_MASK_BE, MATH1, 8,
+			      IFB | IMMED2);
+			MATHB(p, MATH1, SHLD, MATH1, MATH1, 8, 0);
+
+			MOVE(p, DESCBUF, 8, MATH2, 0, 8, WAITCOMP | IMMED);
+			MATHB(p, MATH1, OR, MATH2, MATH2, 8, 0);
+			MOVE(p, MATH2, 0, CONTEXT2, 0, 8, IMMED);
+		}
+		if (dir == OP_TYPE_DECAP_PROTOCOL)
+			MATHB(p, SEQINSZ, SUB, PDCP_MAC_I_LEN, MATH1, 4,
+			      IMMED2);
+		else
+			MATHB(p, SEQINSZ, SUB, ZERO, MATH1, 4, 0);
+
+		MATHB(p, MATH1, SUB, ZERO, VSEQINSZ, 4, 0);
+		MATHB(p, MATH1, SUB, ZERO, VSEQOUTSZ, 4, 0);
+		SEQFIFOSTORE(p, MSG, 0, 0, VLF);
+		ALG_OPERATION(p, OP_ALG_ALGSEL_ZUCA,
+			      OP_ALG_AAI_F9,
+			      OP_ALG_AS_INITFINAL,
+			      dir == OP_TYPE_ENCAP_PROTOCOL ?
+				     ICV_CHECK_DISABLE : ICV_CHECK_ENABLE,
+			      DIR_ENC);
+		SEQFIFOLOAD(p, MSGINSNOOP, 0, VLF | LAST1 | LAST2 | FLUSH1);
+		MOVE(p, AB1, 0, OFIFO, 0, MATH1, 0);
+
+		if (dir == OP_TYPE_DECAP_PROTOCOL)
+			SEQFIFOLOAD(p, ICV2, 4, LAST2);
+		else
+			SEQSTORE(p, CONTEXT2, 0, 4, 0);
+
+		break;
+
+	default:
+		pr_err("%s: Invalid integrity algorithm selected: %d\n",
+		       "pdcp_insert_cplane_int_only_op", authdata->algtype);
+		return -EINVAL;
+	}
+
+	if (rta_sec_era < RTA_SEC_ERA_3) {
+		PATCH_MOVE(p, move_cmd_read_descbuf, local_offset);
+		PATCH_MOVE(p, move_cmd_write_descbuf, local_offset);
+	}
+
+	return 0;
+}
+
+static inline int
+pdcp_insert_cplane_enc_only_op(struct program *p,
+			       bool swap __maybe_unused,
+			       struct alginfo *cipherdata,
+			       struct alginfo *authdata __maybe_unused,
+			       unsigned int dir,
+			       unsigned char era_2_sw_hfn_ovrd __maybe_unused)
+{
+	/* Insert Cipher Key */
+	KEY(p, KEY1, cipherdata->key_enc_flags, cipherdata->key,
+	    cipherdata->keylen, INLINE_KEY(cipherdata));
+
+	if (rta_sec_era >= RTA_SEC_ERA_8) {
+		PROTOCOL(p, dir, OP_PCLID_LTE_PDCP_CTRL_MIXED,
+				(uint16_t)cipherdata->algtype << 8);
+		return 0;
+	}
+
+	SEQLOAD(p, MATH0, 7, 1, 0);
+	JUMP(p, 1, LOCAL_JUMP, ALL_TRUE, CALM);
+	if (swap == false)
+		MATHB(p, MATH0, AND, PDCP_C_PLANE_SN_MASK, MATH1, 8,
+			IFB | IMMED2);
+	else
+		MATHB(p, MATH0, AND, PDCP_C_PLANE_SN_MASK_BE, MATH1, 8,
+			IFB | IMMED2);
+	SEQSTORE(p, MATH0, 7, 1, 0);
+	MATHB(p, MATH1, SHLD, MATH1, MATH1, 8, 0);
+	MOVE(p, DESCBUF, 8, MATH2, 0, 8, WAITCOMP | IMMED);
+	MATHB(p, MATH1, OR, MATH2, MATH2, 8, 0);
+
+	switch (cipherdata->algtype) {
+	case PDCP_CIPHER_TYPE_SNOW:
+		MOVE(p, MATH2, 0, CONTEXT1, 0, 8, WAITCOMP | IMMED);
+
+		if (rta_sec_era > RTA_SEC_ERA_2) {
+			MATHB(p, SEQINSZ, SUB, ZERO, VSEQINSZ, 4, 0);
+		} else {
+			MATHB(p, SEQINSZ, SUB, ONE, MATH1, 4, 0);
+			MATHB(p, MATH1, ADD, ONE, VSEQINSZ, 4, 0);
+		}
+
+		if (dir == OP_TYPE_ENCAP_PROTOCOL)
+			MATHB(p, SEQINSZ, ADD, PDCP_MAC_I_LEN, VSEQOUTSZ, 4,
+			      IMMED2);
+		else
+			MATHB(p, SEQINSZ, SUB, PDCP_MAC_I_LEN, VSEQOUTSZ, 4,
+			      IMMED2);
+		SEQFIFOSTORE(p, MSG, 0, 0, VLF | CONT);
+		ALG_OPERATION(p, OP_ALG_ALGSEL_SNOW_F8,
+			      OP_ALG_AAI_F8,
+			      OP_ALG_AS_INITFINAL, ICV_CHECK_DISABLE,
+			      dir == OP_TYPE_ENCAP_PROTOCOL ?
+					DIR_ENC : DIR_DEC);
+		break;
+
+	case PDCP_CIPHER_TYPE_AES:
+		MOVE(p, MATH2, 0, CONTEXT1, 0x10, 0x10, WAITCOMP | IMMED);
+
+		if (rta_sec_era > RTA_SEC_ERA_2) {
+			MATHB(p, SEQINSZ, SUB, ZERO, VSEQINSZ, 4, 0);
+		} else {
+			MATHB(p, SEQINSZ, SUB, ONE, MATH1, 4, 0);
+			MATHB(p, MATH1, ADD, ONE, VSEQINSZ, 4, 0);
+		}
+
+		if (dir == OP_TYPE_ENCAP_PROTOCOL)
+			MATHB(p, SEQINSZ, ADD, PDCP_MAC_I_LEN, VSEQOUTSZ, 4,
+			      IMMED2);
+		else
+			MATHB(p, SEQINSZ, SUB, PDCP_MAC_I_LEN, VSEQOUTSZ, 4,
+			      IMMED2);
+
+		SEQFIFOSTORE(p, MSG, 0, 0, VLF | CONT);
+		ALG_OPERATION(p, OP_ALG_ALGSEL_AES,
+			      OP_ALG_AAI_CTR,
+			      OP_ALG_AS_INITFINAL,
+			      ICV_CHECK_DISABLE,
+			      dir == OP_TYPE_ENCAP_PROTOCOL ?
+					DIR_ENC : DIR_DEC);
+		break;
+
+	case PDCP_CIPHER_TYPE_ZUC:
+		if (rta_sec_era < RTA_SEC_ERA_5) {
+			pr_err("Invalid era for selected algorithm\n");
+			return -ENOTSUP;
+		}
+
+		MOVE(p, MATH2, 0, CONTEXT1, 0, 0x08, IMMED);
+		MOVE(p, MATH2, 0, CONTEXT1, 0x08, 0x08, WAITCOMP | IMMED);
+		MATHB(p, SEQINSZ, SUB, ZERO, VSEQINSZ, 4, 0);
+		if (dir == OP_TYPE_ENCAP_PROTOCOL)
+			MATHB(p, SEQINSZ, ADD, PDCP_MAC_I_LEN, VSEQOUTSZ, 4,
+			      IMMED2);
+		else
+			MATHB(p, SEQINSZ, SUB, PDCP_MAC_I_LEN, VSEQOUTSZ, 4,
+			      IMMED2);
+
+		SEQFIFOSTORE(p, MSG, 0, 0, VLF | CONT);
+		ALG_OPERATION(p, OP_ALG_ALGSEL_ZUCE,
+			      OP_ALG_AAI_F8,
+			      OP_ALG_AS_INITFINAL,
+			      ICV_CHECK_DISABLE,
+			      dir == OP_TYPE_ENCAP_PROTOCOL ?
+					DIR_ENC : DIR_DEC);
+		break;
+
+	default:
+		pr_err("%s: Invalid encrypt algorithm selected: %d\n",
+		       "pdcp_insert_cplane_enc_only_op", cipherdata->algtype);
+		return -EINVAL;
+	}
+
+	if (dir == OP_TYPE_ENCAP_PROTOCOL) {
+		SEQFIFOLOAD(p, MSG1, 0, VLF);
+		FIFOLOAD(p, MSG1, PDCP_NULL_INT_MAC_I_VAL, 4,
+			 LAST1 | FLUSH1 | IMMED);
+	} else {
+		SEQFIFOLOAD(p, MSG1, 0, VLF | LAST1 | FLUSH1);
+		MOVE(p, OFIFO, 0, MATH1, 4, PDCP_MAC_I_LEN, WAITCOMP | IMMED);
+		MATHB(p, MATH1, XOR, PDCP_NULL_INT_MAC_I_VAL, NONE, 4, IMMED2);
+		JUMP(p, PDCP_NULL_INT_ICV_CHECK_FAILED_STATUS,
+		     HALT_STATUS, ALL_FALSE, MATH_Z);
+	}
+
+	return 0;
+}
+
+static inline int
+pdcp_insert_cplane_acc_op(struct program *p,
+			  bool swap __maybe_unused,
+			  struct alginfo *cipherdata,
+			  struct alginfo *authdata,
+			  unsigned int dir,
+			  unsigned char era_2_hfn_ovrd __maybe_unused)
+{
+	/* Insert Auth Key */
+	KEY(p, KEY2, authdata->key_enc_flags, authdata->key, authdata->keylen,
+	    INLINE_KEY(authdata));
+
+	/* Insert Cipher Key */
+	KEY(p, KEY1, cipherdata->key_enc_flags, cipherdata->key,
+	    cipherdata->keylen, INLINE_KEY(cipherdata));
+	PROTOCOL(p, dir, OP_PCLID_LTE_PDCP_CTRL, (uint16_t)cipherdata->algtype);
+
+	return 0;
+}
+
+static inline int
+pdcp_insert_cplane_snow_aes_op(struct program *p,
+			       bool swap __maybe_unused,
+			       struct alginfo *cipherdata,
+			       struct alginfo *authdata,
+			       unsigned int dir,
+			       unsigned char era_2_sw_hfn_ovrd)
+{
+	LABEL(back_to_sd_offset);
+	LABEL(end_desc);
+	LABEL(local_offset);
+	LABEL(jump_to_beginning);
+	LABEL(fifo_load_mac_i_offset);
+	REFERENCE(seqin_ptr_read);
+	REFERENCE(seqin_ptr_write);
+	REFERENCE(seq_out_read);
+	REFERENCE(jump_back_to_sd_cmd);
+	REFERENCE(move_mac_i_to_desc_buf);
+
+	if (rta_sec_era >= RTA_SEC_ERA_8) {
+		KEY(p, KEY1, cipherdata->key_enc_flags, cipherdata->key,
+				cipherdata->keylen, INLINE_KEY(cipherdata));
+		KEY(p, KEY2, authdata->key_enc_flags, authdata->key,
+				authdata->keylen, INLINE_KEY(authdata));
+
+		PROTOCOL(p, dir, OP_PCLID_LTE_PDCP_CTRL_MIXED,
+			 ((uint16_t)cipherdata->algtype << 8) |
+			 (uint16_t)authdata->algtype);
+
+		return 0;
+	}
+
+	SEQLOAD(p, MATH0, 7, 1, 0);
+	JUMP(p, 1, LOCAL_JUMP, ALL_TRUE, CALM);
+	if (swap == false)
+		MATHB(p, MATH0, AND, PDCP_C_PLANE_SN_MASK, MATH1, 8,
+			IFB | IMMED2);
+	else
+		MATHB(p, MATH0, AND, PDCP_C_PLANE_SN_MASK_BE, MATH1, 8,
+			IFB | IMMED2);
+	MATHB(p, MATH1, SHLD, MATH1, MATH1, 8, 0);
+	MOVE(p, DESCBUF, 4, MATH2, 0, 0x08, WAITCOMP | IMMED);
+	MATHB(p, MATH1, OR, MATH2, MATH2, 8, 0);
+	SEQSTORE(p, MATH0, 7, 1, 0);
+	if (dir == OP_TYPE_ENCAP_PROTOCOL) {
+		if (rta_sec_era > RTA_SEC_ERA_2 ||
+		    (rta_sec_era == RTA_SEC_ERA_2 &&
+				   era_2_sw_hfn_ovrd == 0)) {
+			SEQINPTR(p, 0, 1, RTO);
+		} else {
+			SEQINPTR(p, 0, 5, RTO);
+			SEQFIFOLOAD(p, SKIP, 4, 0);
+		}
+		KEY(p, KEY1, authdata->key_enc_flags, authdata->key,
+		    authdata->keylen, INLINE_KEY(authdata));
+		MOVE(p, MATH2, 0, IFIFOAB1, 0, 0x08, IMMED);
+
+		if (rta_sec_era > RTA_SEC_ERA_2) {
+			MATHB(p, SEQINSZ, SUB, ZERO, VSEQINSZ, 4, 0);
+			MATHB(p, SEQINSZ, SUB, ZERO, MATH1, 4, 0);
+			MATHB(p, VSEQINSZ, ADD, PDCP_MAC_I_LEN - 1, VSEQOUTSZ,
+			      4, IMMED2);
+		} else {
+			MATHB(p, SEQINSZ, SUB, MATH3, VSEQINSZ, 4, 0);
+			MATHB(p, VSEQINSZ, ADD, PDCP_MAC_I_LEN - 1, VSEQOUTSZ,
+			      4, IMMED2);
+			/*
+			 * Note: Although the calculations below might seem a
+			 * little off, the logic is the following:
+			 *
+			 * - SEQ IN PTR RTO below needs the full length of the
+			 *   frame; in case of P4080_REV_2_HFN_OV_WORKAROUND,
+			 *   this means the length of the frame to be processed
+			 *   + 4 bytes (the HFN override flag and value).
+			 *   The length of the frame to be processed minus 1
+			 *   byte is in the VSIL register (because
+			 *   VSIL = SIL + 3, due to 1 byte, the header being
+			 *   already written by the SEQ STORE above). So for
+			 *   calculating the length to use in RTO, I add one
+			 *   to the VSIL value in order to obtain the total
+			 *   frame length. This helps in case of P4080 which
+			 *   can have the value 0 as an operand in a MATH
+			 *   command only as SRC1 When the HFN override
+			 *   workaround is not enabled, the length of the
+			 *   frame is given by the SIL register; the
+			 *   calculation is similar to the one in the SEC 4.2
+			 *   and SEC 5.3 cases.
+			 */
+			if (era_2_sw_hfn_ovrd)
+				MATHB(p, VSEQOUTSZ, ADD, ONE, MATH1, 4,
+				      0);
+			else
+				MATHB(p, SEQINSZ, ADD, MATH3, MATH1, 4,
+				      0);
+		}
+		/*
+		 * Placeholder for filling the length in
+		 * SEQIN PTR RTO below
+		 */
+		seqin_ptr_read = MOVE(p, DESCBUF, 0, MATH1, 0, 6, IMMED);
+		seqin_ptr_write = MOVE(p, MATH1, 0, DESCBUF, 0, 8,
+				       WAITCOMP | IMMED);
+		ALG_OPERATION(p, OP_ALG_ALGSEL_AES,
+			      OP_ALG_AAI_CMAC,
+			      OP_ALG_AS_INITFINAL,
+			      ICV_CHECK_DISABLE,
+			      DIR_DEC);
+		SEQFIFOLOAD(p, MSG1, 0, VLF | LAST1 | FLUSH1);
+		MOVE(p, CONTEXT1, 0, MATH3, 0, 4, WAITCOMP | IMMED);
+		if (rta_sec_era <= RTA_SEC_ERA_3)
+			LOAD(p, CLRW_CLR_C1KEY |
+			     CLRW_CLR_C1CTX |
+			     CLRW_CLR_C1ICV |
+			     CLRW_CLR_C1DATAS |
+			     CLRW_CLR_C1MODE,
+			     CLRW, 0, 4, IMMED);
+		else
+			LOAD(p, CLRW_RESET_CLS1_CHA |
+			     CLRW_CLR_C1KEY |
+			     CLRW_CLR_C1CTX |
+			     CLRW_CLR_C1ICV |
+			     CLRW_CLR_C1DATAS |
+			     CLRW_CLR_C1MODE,
+			     CLRW, 0, 4, IMMED);
+
+		if (rta_sec_era <= RTA_SEC_ERA_3)
+			LOAD(p, CCTRL_RESET_CHA_ALL, CCTRL, 0, 4, IMMED);
+
+		KEY(p, KEY1, cipherdata->key_enc_flags, cipherdata->key,
+		    cipherdata->keylen, INLINE_KEY(cipherdata));
+		SET_LABEL(p, local_offset);
+		MOVE(p, MATH2, 0, CONTEXT1, 0, 8, IMMED);
+		SEQINPTR(p, 0, 0, RTO);
+
+		if (rta_sec_era == RTA_SEC_ERA_2 && era_2_sw_hfn_ovrd) {
+			SEQFIFOLOAD(p, SKIP, 5, 0);
+			MATHB(p, SEQINSZ, ADD, ONE, SEQINSZ, 4, 0);
+		}
+
+		MATHB(p, SEQINSZ, SUB, ONE, VSEQINSZ, 4, 0);
+		ALG_OPERATION(p, OP_ALG_ALGSEL_SNOW_F8,
+			      OP_ALG_AAI_F8,
+			      OP_ALG_AS_INITFINAL,
+			      ICV_CHECK_DISABLE,
+			      DIR_ENC);
+		SEQFIFOSTORE(p, MSG, 0, 0, VLF);
+
+		if (rta_sec_era > RTA_SEC_ERA_2 ||
+		    (rta_sec_era == RTA_SEC_ERA_2 &&
+				   era_2_sw_hfn_ovrd == 0))
+			SEQFIFOLOAD(p, SKIP, 1, 0);
+
+		SEQFIFOLOAD(p, MSG1, 0, VLF);
+		MOVE(p, MATH3, 0, IFIFOAB1, 0, 4, LAST1 | FLUSH1 | IMMED);
+		PATCH_MOVE(p, seqin_ptr_read, local_offset);
+		PATCH_MOVE(p, seqin_ptr_write, local_offset);
+	} else {
+		MOVE(p, MATH2, 0, CONTEXT1, 0, 8, IMMED);
+
+		if (rta_sec_era >= RTA_SEC_ERA_5)
+			MOVE(p, CONTEXT1, 0, CONTEXT2, 0, 8, IMMED);
+
+		if (rta_sec_era > RTA_SEC_ERA_2)
+			MATHB(p, SEQINSZ, SUB, ZERO, VSEQINSZ, 4, 0);
+		else
+			MATHB(p, SEQINSZ, SUB, MATH3, VSEQINSZ, 4, 0);
+
+		MATHB(p, SEQINSZ, SUB, PDCP_MAC_I_LEN, VSEQOUTSZ, 4, IMMED2);
+/*
+ * TODO: To be changed when proper support is added in RTA (can't load a
+ * command that is also written by RTA (or patch it for that matter).
+ * Change when proper RTA support is added.
+ */
+		if (p->ps)
+			WORD(p, 0x168B0004);
+		else
+			WORD(p, 0x16880404);
+
+		jump_back_to_sd_cmd = JUMP(p, 0, LOCAL_JUMP, ALL_TRUE, 0);
+		/*
+		 * Placeholder for command reading  the SEQ OUT command in
+		 * JD. Done for rereading the decrypted data and performing
+		 * the integrity check
+		 */
+/*
+ * TODO: RTA currently doesn't support patching of length of a MOVE command
+ * Thus, it is inserted as a raw word, as per PS setting.
+ */
+		if (p->ps)
+			seq_out_read = MOVE(p, DESCBUF, 0, MATH1, 0, 20,
+					    WAITCOMP | IMMED);
+		else
+			seq_out_read = MOVE(p, DESCBUF, 0, MATH1, 0, 16,
+					    WAITCOMP | IMMED);
+
+		MATHB(p, MATH1, XOR, CMD_SEQ_IN_PTR ^ CMD_SEQ_OUT_PTR, MATH1, 4,
+		      IMMED2);
+		/* Placeholder for overwriting the SEQ IN  with SEQ OUT */
+/*
+ * TODO: RTA currently doesn't support patching of length of a MOVE command
+ * Thus, it is inserted as a raw word, as per PS setting.
+ */
+		if (p->ps)
+			MOVE(p, MATH1, 0, DESCBUF, 0, 24, IMMED);
+		else
+			MOVE(p, MATH1, 0, DESCBUF, 0, 20, IMMED);
+
+		KEY(p, KEY1, cipherdata->key_enc_flags, cipherdata->key,
+		    cipherdata->keylen, INLINE_KEY(cipherdata));
+
+		if (rta_sec_era >= RTA_SEC_ERA_4)
+			MOVE(p, CONTEXT1, 0, CONTEXT2, 0, 8, IMMED);
+		else
+			MOVE(p, CONTEXT1, 0, MATH3, 0, 8, IMMED);
+
+		ALG_OPERATION(p, OP_ALG_ALGSEL_SNOW_F8,
+			      OP_ALG_AAI_F8,
+			      OP_ALG_AS_INITFINAL,
+			      ICV_CHECK_DISABLE,
+			      DIR_DEC);
+		SEQFIFOSTORE(p, MSG, 0, 0, VLF | CONT);
+		SEQFIFOLOAD(p, MSG1, 0, VLF | LAST1 | FLUSH1);
+
+		if (rta_sec_era <= RTA_SEC_ERA_3)
+			move_mac_i_to_desc_buf = MOVE(p, OFIFO, 0, DESCBUF, 0,
+						      4, WAITCOMP | IMMED);
+		else
+			MOVE(p, OFIFO, 0, MATH3, 0, 4, IMMED);
+
+		if (rta_sec_era <= RTA_SEC_ERA_3)
+			LOAD(p, CCTRL_RESET_CHA_ALL, CCTRL, 0, 4, IMMED);
+		else
+			LOAD(p, CLRW_RESET_CLS1_CHA |
+			     CLRW_CLR_C1KEY |
+			     CLRW_CLR_C1CTX |
+			     CLRW_CLR_C1ICV |
+			     CLRW_CLR_C1DATAS |
+			     CLRW_CLR_C1MODE,
+			     CLRW, 0, 4, IMMED);
+
+		KEY(p, KEY1, authdata->key_enc_flags, authdata->key,
+		    authdata->keylen, INLINE_KEY(authdata));
+		/*
+		 * Placeholder for jump in SD for executing the new SEQ IN PTR
+		 * command (which is actually the old SEQ OUT PTR command
+		 * copied over from JD.
+		 */
+		SET_LABEL(p, jump_to_beginning);
+		JUMP(p, 1 - jump_to_beginning, LOCAL_JUMP, ALL_TRUE, 0);
+		SET_LABEL(p, back_to_sd_offset);
+		ALG_OPERATION(p, OP_ALG_ALGSEL_AES,
+			      OP_ALG_AAI_CMAC,
+			      OP_ALG_AS_INITFINAL,
+			      ICV_CHECK_ENABLE,
+			      DIR_DEC);
+
+		/* Read the # of bytes written in the output buffer + 1 (HDR) */
+		MATHB(p, VSEQOUTSZ, ADD, ONE, VSEQINSZ, 4, 0);
+
+		if (rta_sec_era <= RTA_SEC_ERA_3)
+			MOVE(p, MATH3, 0, IFIFOAB1, 0, 8, IMMED);
+		else
+			MOVE(p, CONTEXT2, 0, IFIFOAB1, 0, 8, IMMED);
+
+		if (rta_sec_era == RTA_SEC_ERA_2 && era_2_sw_hfn_ovrd)
+			SEQFIFOLOAD(p, SKIP, 4, 0);
+
+		SEQFIFOLOAD(p, MSG1, 0, VLF | LAST1 | FLUSH1);
+
+		if (rta_sec_era >= RTA_SEC_ERA_4) {
+			LOAD(p, NFIFOENTRY_STYPE_ALTSOURCE |
+			     NFIFOENTRY_DEST_CLASS1 |
+			     NFIFOENTRY_DTYPE_ICV |
+			     NFIFOENTRY_LC1 |
+			     NFIFOENTRY_FC1 | 4, NFIFO_SZL, 0, 4, IMMED);
+			MOVE(p, MATH3, 0, ALTSOURCE, 0, 4, IMMED);
+		} else {
+			SET_LABEL(p, fifo_load_mac_i_offset);
+			FIFOLOAD(p, ICV1, fifo_load_mac_i_offset, 4,
+				 LAST1 | FLUSH1 | IMMED);
+		}
+
+		SET_LABEL(p, end_desc);
+
+		if (!p->ps) {
+			PATCH_MOVE(p, seq_out_read, end_desc + 1);
+			PATCH_JUMP(p, jump_back_to_sd_cmd,
+				   back_to_sd_offset + jump_back_to_sd_cmd - 5);
+
+			if (rta_sec_era <= RTA_SEC_ERA_3)
+				PATCH_MOVE(p, move_mac_i_to_desc_buf,
+					   fifo_load_mac_i_offset + 1);
+		} else {
+			PATCH_MOVE(p, seq_out_read, end_desc + 2);
+			PATCH_JUMP(p, jump_back_to_sd_cmd,
+				   back_to_sd_offset + jump_back_to_sd_cmd - 5);
+
+			if (rta_sec_era <= RTA_SEC_ERA_3)
+				PATCH_MOVE(p, move_mac_i_to_desc_buf,
+					   fifo_load_mac_i_offset + 1);
+		}
+	}
+
+	return 0;
+}
+
+static inline int
+pdcp_insert_cplane_aes_snow_op(struct program *p,
+			       bool swap __maybe_unused,
+			       struct alginfo *cipherdata,
+			       struct alginfo *authdata,
+			       unsigned int dir,
+			       unsigned char era_2_sw_hfn_ovrd __maybe_unused)
+{
+	KEY(p, KEY1, cipherdata->key_enc_flags, cipherdata->key,
+	    cipherdata->keylen, INLINE_KEY(cipherdata));
+	KEY(p, KEY2, authdata->key_enc_flags, authdata->key, authdata->keylen,
+	    INLINE_KEY(authdata));
+
+	if (rta_sec_era >= RTA_SEC_ERA_8) {
+		PROTOCOL(p, dir, OP_PCLID_LTE_PDCP_CTRL_MIXED,
+			 ((uint16_t)cipherdata->algtype << 8) |
+			 (uint16_t)authdata->algtype);
+
+		return 0;
+	}
+
+	if (dir == OP_TYPE_ENCAP_PROTOCOL)
+		MATHB(p, SEQINSZ, SUB, ONE, VSEQINSZ, 4, 0);
+
+	SEQLOAD(p, MATH0, 7, 1, 0);
+	JUMP(p, 1, LOCAL_JUMP, ALL_TRUE, CALM);
+	MOVE(p, MATH0, 7, IFIFOAB2, 0, 1, IMMED);
+	if (swap == false)
+		MATHB(p, MATH0, AND, PDCP_C_PLANE_SN_MASK, MATH1, 8,
+			IFB | IMMED2);
+	else
+		MATHB(p, MATH0, AND, PDCP_C_PLANE_SN_MASK_BE, MATH1, 8,
+			IFB | IMMED2);
+
+	SEQSTORE(p, MATH0, 7, 1, 0);
+	MATHB(p, MATH1, SHLD, MATH1, MATH1, 8, 0);
+	MOVE(p, DESCBUF, 4, MATH2, 0, 8, WAITCOMP | IMMED);
+	MATHB(p, MATH1, OR, MATH2, MATH1, 8, 0);
+	MOVE(p, MATH1, 0, CONTEXT1, 16, 8, IMMED);
+	MOVE(p, MATH1, 0, CONTEXT2, 0, 4, IMMED);
+	if (swap == false) {
+		MATHB(p, MATH1, AND, lower_32_bits(PDCP_BEARER_MASK), MATH2, 4,
+			IMMED2);
+		MATHB(p, MATH1, AND, upper_32_bits(PDCP_DIR_MASK), MATH3, 4,
+			IMMED2);
+	} else {
+		MATHB(p, MATH1, AND, lower_32_bits(PDCP_BEARER_MASK_BE), MATH2,
+			4, IMMED2);
+		MATHB(p, MATH1, AND, upper_32_bits(PDCP_DIR_MASK_BE), MATH3,
+			4, IMMED2);
+	}
+	MATHB(p, MATH3, SHLD, MATH3, MATH3, 8, 0);
+	MOVE(p, MATH2, 4, OFIFO, 0, 12, IMMED);
+	MOVE(p, OFIFO, 0, CONTEXT2, 4, 12, IMMED);
+	if (dir == OP_TYPE_ENCAP_PROTOCOL) {
+		MATHB(p, SEQINSZ, ADD, PDCP_MAC_I_LEN, VSEQOUTSZ, 4, IMMED2);
+	} else {
+		MATHB(p, SEQINSZ, SUB, PDCP_MAC_I_LEN, MATH1, 4, IMMED2);
+
+		MATHB(p, ZERO, ADD, MATH1, VSEQOUTSZ, 4, 0);
+		MATHB(p, ZERO, ADD, MATH1, VSEQINSZ, 4, 0);
+	}
+
+	if (dir == OP_TYPE_ENCAP_PROTOCOL)
+		SEQFIFOSTORE(p, MSG, 0, 0, VLF);
+	else
+		SEQFIFOSTORE(p, MSG, 0, 0, VLF | CONT);
+
+	ALG_OPERATION(p, OP_ALG_ALGSEL_SNOW_F9,
+		      OP_ALG_AAI_F9,
+		      OP_ALG_AS_INITFINAL,
+		      dir == OP_TYPE_ENCAP_PROTOCOL ?
+			     ICV_CHECK_DISABLE : ICV_CHECK_ENABLE,
+		      DIR_DEC);
+	ALG_OPERATION(p, OP_ALG_ALGSEL_AES,
+		      OP_ALG_AAI_CTR,
+		      OP_ALG_AS_INITFINAL,
+		      ICV_CHECK_DISABLE,
+		      dir == OP_TYPE_ENCAP_PROTOCOL ? DIR_ENC : DIR_DEC);
+
+	if (dir == OP_TYPE_ENCAP_PROTOCOL) {
+		SEQFIFOLOAD(p, MSGINSNOOP, 0, VLF | LAST2);
+		MOVE(p, CONTEXT2, 0, IFIFOAB1, 0, 4, LAST1 | FLUSH1 | IMMED);
+	} else {
+		SEQFIFOLOAD(p, MSGOUTSNOOP, 0, VLF | LAST2);
+		SEQFIFOLOAD(p, MSG1, 4, LAST1 | FLUSH1);
+		JUMP(p, 1, LOCAL_JUMP, ALL_TRUE, CLASS1 | NOP | NIFP);
+
+		if (rta_sec_era >= RTA_SEC_ERA_6)
+			LOAD(p, 0, DCTRL, 0, LDLEN_RST_CHA_OFIFO_PTR, IMMED);
+
+		MOVE(p, OFIFO, 0, MATH0, 0, 4, WAITCOMP | IMMED);
+
+		NFIFOADD(p, IFIFO, ICV2, 4, LAST2);
+
+		if (rta_sec_era <= RTA_SEC_ERA_2) {
+			/* Shut off automatic Info FIFO entries */
+			LOAD(p, 0, DCTRL, LDOFF_DISABLE_AUTO_NFIFO, 0, IMMED);
+			MOVE(p, MATH0, 0, IFIFOAB2, 0, 4, WAITCOMP | IMMED);
+		} else {
+			MOVE(p, MATH0, 0, IFIFO, 0, 4, WAITCOMP | IMMED);
+		}
+	}
+
+	return 0;
+}
+
+static inline int
+pdcp_insert_cplane_snow_zuc_op(struct program *p,
+			       bool swap __maybe_unused,
+			       struct alginfo *cipherdata,
+			       struct alginfo *authdata,
+			       unsigned int dir,
+			       unsigned char era_2_sw_hfn_ovrd __maybe_unused)
+{
+	LABEL(keyjump);
+	REFERENCE(pkeyjump);
+
+	if (rta_sec_era < RTA_SEC_ERA_5) {
+		pr_err("Invalid era for selected algorithm\n");
+		return -ENOTSUP;
+	}
+
+	pkeyjump = JUMP(p, keyjump, LOCAL_JUMP, ALL_TRUE, SHRD | SELF | BOTH);
+	KEY(p, KEY1, cipherdata->key_enc_flags, cipherdata->key,
+	    cipherdata->keylen, INLINE_KEY(cipherdata));
+	KEY(p, KEY2, authdata->key_enc_flags, authdata->key, authdata->keylen,
+	    INLINE_KEY(authdata));
+
+	SET_LABEL(p, keyjump);
+
+	if (rta_sec_era >= RTA_SEC_ERA_8) {
+		PROTOCOL(p, dir, OP_PCLID_LTE_PDCP_CTRL_MIXED,
+			 ((uint16_t)cipherdata->algtype << 8) |
+			 (uint16_t)authdata->algtype);
+		return 0;
+	}
+
+	SEQLOAD(p, MATH0, 7, 1, 0);
+	JUMP(p, 1, LOCAL_JUMP, ALL_TRUE, CALM);
+	MOVE(p, MATH0, 7, IFIFOAB2, 0, 1, IMMED);
+	if (swap == false)
+		MATHB(p, MATH0, AND, PDCP_C_PLANE_SN_MASK, MATH1, 8,
+			IFB | IMMED2);
+	else
+		MATHB(p, MATH0, AND, PDCP_C_PLANE_SN_MASK, MATH1, 8,
+			IFB | IMMED2);
+
+	MATHB(p, MATH1, SHLD, MATH1, MATH1, 8, 0);
+	MOVE(p, DESCBUF, 4, MATH2, 0, 8, WAITCOMP | IMMED);
+	MATHB(p, MATH1, OR, MATH2, MATH2, 8, 0);
+	MOVE(p, MATH2, 0, CONTEXT1, 0, 8, IMMED);
+	MOVE(p, MATH2, 0, CONTEXT2, 0, 8, WAITCOMP | IMMED);
+
+	if (dir == OP_TYPE_ENCAP_PROTOCOL)
+		MATHB(p, SEQINSZ, ADD, PDCP_MAC_I_LEN, VSEQOUTSZ, 4, IMMED2);
+	else
+		MATHB(p, SEQINSZ, SUB, PDCP_MAC_I_LEN, VSEQOUTSZ, 4, IMMED2);
+
+	MATHB(p, SEQINSZ, SUB, ZERO, VSEQINSZ, 4, 0);
+	SEQSTORE(p, MATH0, 7, 1, 0);
+
+	if (dir == OP_TYPE_ENCAP_PROTOCOL) {
+		SEQFIFOSTORE(p, MSG, 0, 0, VLF);
+		SEQFIFOLOAD(p, MSGINSNOOP, 0, VLF | LAST2);
+	} else {
+		SEQFIFOSTORE(p, MSG, 0, 0, VLF | CONT);
+		SEQFIFOLOAD(p, MSGOUTSNOOP, 0, VLF | LAST1 | FLUSH1);
+	}
+
+	ALG_OPERATION(p, OP_ALG_ALGSEL_ZUCA,
+		      OP_ALG_AAI_F9,
+		      OP_ALG_AS_INITFINAL,
+		      dir == OP_TYPE_ENCAP_PROTOCOL ?
+			     ICV_CHECK_DISABLE : ICV_CHECK_ENABLE,
+		      DIR_ENC);
+
+	ALG_OPERATION(p, OP_ALG_ALGSEL_SNOW_F8,
+		      OP_ALG_AAI_F8,
+		      OP_ALG_AS_INITFINAL,
+		      ICV_CHECK_DISABLE,
+		      dir == OP_TYPE_ENCAP_PROTOCOL ? DIR_ENC : DIR_DEC);
+	if (dir == OP_TYPE_ENCAP_PROTOCOL) {
+		MOVE(p, CONTEXT2, 0, IFIFOAB1, 0, 4, LAST1 | FLUSH1 | IMMED);
+	} else {
+		/* Save ICV */
+		MOVE(p, OFIFO, 0, MATH0, 0, 4, IMMED);
+		LOAD(p, NFIFOENTRY_STYPE_ALTSOURCE |
+		     NFIFOENTRY_DEST_CLASS2 |
+		     NFIFOENTRY_DTYPE_ICV |
+		     NFIFOENTRY_LC2 | 4, NFIFO_SZL, 0, 4, IMMED);
+		MOVE(p, MATH0, 0, ALTSOURCE, 0, 4, WAITCOMP | IMMED);
+	}
+
+	/* Reset ZUCA mode and done interrupt */
+	LOAD(p, CLRW_CLR_C2MODE, CLRW, 0, 4, IMMED);
+	LOAD(p, CIRQ_ZADI, ICTRL, 0, 4, IMMED);
+
+	PATCH_JUMP(p, pkeyjump, keyjump);
+	return 0;
+}
+
+static inline int
+pdcp_insert_cplane_aes_zuc_op(struct program *p,
+			      bool swap __maybe_unused,
+			      struct alginfo *cipherdata,
+			      struct alginfo *authdata,
+			      unsigned int dir,
+			      unsigned char era_2_sw_hfn_ovrd __maybe_unused)
+{
+	LABEL(keyjump);
+	REFERENCE(pkeyjump);
+
+	if (rta_sec_era < RTA_SEC_ERA_5) {
+		pr_err("Invalid era for selected algorithm\n");
+		return -ENOTSUP;
+	}
+
+	pkeyjump = JUMP(p, keyjump, LOCAL_JUMP, ALL_TRUE, SHRD | SELF | BOTH);
+	KEY(p, KEY1, cipherdata->key_enc_flags, cipherdata->key,
+	    cipherdata->keylen, INLINE_KEY(cipherdata));
+	KEY(p, KEY2, authdata->key_enc_flags, authdata->key, authdata->keylen,
+	    INLINE_KEY(authdata));
+
+	if (rta_sec_era >= RTA_SEC_ERA_8) {
+		PROTOCOL(p, dir, OP_PCLID_LTE_PDCP_CTRL_MIXED,
+			 ((uint16_t)cipherdata->algtype << 8) |
+			 (uint16_t)authdata->algtype);
+
+		return 0;
+	}
+
+	SET_LABEL(p, keyjump);
+	SEQLOAD(p, MATH0, 7, 1, 0);
+	JUMP(p, 1, LOCAL_JUMP, ALL_TRUE, CALM);
+	MOVE(p, MATH0, 7, IFIFOAB2, 0, 1, IMMED);
+	if (swap == false)
+		MATHB(p, MATH0, AND, PDCP_C_PLANE_SN_MASK, MATH1, 8,
+			IFB | IMMED2);
+	else
+		MATHB(p, MATH0, AND, PDCP_C_PLANE_SN_MASK, MATH1, 8,
+			IFB | IMMED2);
+
+	MATHB(p, MATH1, SHLD, MATH1, MATH1, 8, 0);
+	MOVE(p, DESCBUF, 4, MATH2, 0, 8, WAITCOMP | IMMED);
+	MATHB(p, MATH1, OR, MATH2, MATH2, 8, 0);
+	MOVE(p, MATH2, 0, CONTEXT1, 16, 8, IMMED);
+	MOVE(p, MATH2, 0, CONTEXT2, 0, 8, WAITCOMP | IMMED);
+
+	if (dir == OP_TYPE_ENCAP_PROTOCOL)
+		MATHB(p, SEQINSZ, ADD, PDCP_MAC_I_LEN, VSEQOUTSZ, 4, IMMED2);
+	else
+		MATHB(p, SEQINSZ, SUB, PDCP_MAC_I_LEN, VSEQOUTSZ, 4, IMMED2);
+
+	MATHB(p, SEQINSZ, SUB, ZERO, VSEQINSZ, 4, 0);
+	SEQSTORE(p, MATH0, 7, 1, 0);
+
+	if (dir == OP_TYPE_ENCAP_PROTOCOL) {
+		SEQFIFOSTORE(p, MSG, 0, 0, VLF);
+		SEQFIFOLOAD(p, MSGINSNOOP, 0, VLF | LAST2);
+	} else {
+		SEQFIFOSTORE(p, MSG, 0, 0, VLF | CONT);
+		SEQFIFOLOAD(p, MSGOUTSNOOP, 0, VLF | LAST1 | FLUSH1);
+	}
+
+	ALG_OPERATION(p, OP_ALG_ALGSEL_ZUCA,
+		      OP_ALG_AAI_F9,
+		      OP_ALG_AS_INITFINAL,
+		      dir == OP_TYPE_ENCAP_PROTOCOL ?
+			     ICV_CHECK_DISABLE : ICV_CHECK_ENABLE,
+		      DIR_ENC);
+
+	ALG_OPERATION(p, OP_ALG_ALGSEL_AES,
+		      OP_ALG_AAI_CTR,
+		      OP_ALG_AS_INITFINAL,
+		      ICV_CHECK_DISABLE,
+		      dir == OP_TYPE_ENCAP_PROTOCOL ? DIR_ENC : DIR_DEC);
+
+	if (dir == OP_TYPE_ENCAP_PROTOCOL) {
+		MOVE(p, CONTEXT2, 0, IFIFOAB1, 0, 4, LAST1 | FLUSH1 | IMMED);
+	} else {
+		/* Save ICV */
+		MOVE(p, OFIFO, 0, MATH0, 0, 4, IMMED);
+
+		LOAD(p, NFIFOENTRY_STYPE_ALTSOURCE |
+		     NFIFOENTRY_DEST_CLASS2 |
+		     NFIFOENTRY_DTYPE_ICV |
+		     NFIFOENTRY_LC2 | 4, NFIFO_SZL, 0, 4, IMMED);
+		MOVE(p, MATH0, 0, ALTSOURCE, 0, 4, WAITCOMP | IMMED);
+	}
+
+	/* Reset ZUCA mode and done interrupt */
+	LOAD(p, CLRW_CLR_C2MODE, CLRW, 0, 4, IMMED);
+	LOAD(p, CIRQ_ZADI, ICTRL, 0, 4, IMMED);
+
+	PATCH_JUMP(p, pkeyjump, keyjump);
+
+	return 0;
+}
+
+static inline int
+pdcp_insert_cplane_zuc_snow_op(struct program *p,
+			       bool swap __maybe_unused,
+			       struct alginfo *cipherdata,
+			       struct alginfo *authdata,
+			       unsigned int dir,
+			       unsigned char era_2_sw_hfn_ovrd __maybe_unused)
+{
+	LABEL(keyjump);
+	REFERENCE(pkeyjump);
+
+	if (rta_sec_era < RTA_SEC_ERA_5) {
+		pr_err("Invalid era for selected algorithm\n");
+		return -ENOTSUP;
+	}
+
+	pkeyjump = JUMP(p, keyjump, LOCAL_JUMP, ALL_TRUE, SHRD | SELF | BOTH);
+	KEY(p, KEY1, cipherdata->key_enc_flags, cipherdata->key,
+	    cipherdata->keylen, INLINE_KEY(cipherdata));
+	KEY(p, KEY2, authdata->key_enc_flags, authdata->key, authdata->keylen,
+	    INLINE_KEY(authdata));
+
+	if (rta_sec_era >= RTA_SEC_ERA_8) {
+		PROTOCOL(p, dir, OP_PCLID_LTE_PDCP_CTRL_MIXED,
+			 ((uint16_t)cipherdata->algtype << 8) |
+			 (uint16_t)authdata->algtype);
+
+		return 0;
+	}
+
+	SET_LABEL(p, keyjump);
+	SEQLOAD(p, MATH0, 7, 1, 0);
+	JUMP(p, 1, LOCAL_JUMP, ALL_TRUE, CALM);
+	MOVE(p, MATH0, 7, IFIFOAB2, 0, 1, IMMED);
+	if (swap == false)
+		MATHB(p, MATH0, AND, PDCP_C_PLANE_SN_MASK, MATH1, 8,
+			IFB | IMMED2);
+	else
+		MATHB(p, MATH0, AND, PDCP_C_PLANE_SN_MASK, MATH1, 8,
+			IFB | IMMED2);
+
+	MATHB(p, MATH1, SHLD, MATH1, MATH1, 8, 0);
+	MOVE(p, DESCBUF, 4, MATH2, 0, 8, WAITCOMP | IMMED);
+	MATHB(p, MATH1, OR, MATH2, MATH1, 8, 0);
+	MOVE(p, MATH1, 0, CONTEXT1, 0, 8, IMMED);
+	MOVE(p, MATH1, 0, CONTEXT2, 0, 4, IMMED);
+	if (swap == false) {
+		MATHB(p, MATH1, AND, lower_32_bits(PDCP_BEARER_MASK), MATH2,
+			4, IMMED2);
+		MATHB(p, MATH1, AND, upper_32_bits(PDCP_DIR_MASK), MATH3,
+			4, IMMED2);
+	} else {
+		MATHB(p, MATH1, AND, lower_32_bits(PDCP_BEARER_MASK_BE), MATH2,
+			4, IMMED2);
+		MATHB(p, MATH1, AND, upper_32_bits(PDCP_DIR_MASK_BE), MATH3,
+			4, IMMED2);
+	}
+	MATHB(p, MATH3, SHLD, MATH3, MATH3, 8, 0);
+	MOVE(p, MATH2, 4, OFIFO, 0, 12, IMMED);
+	MOVE(p, OFIFO, 0, CONTEXT2, 4, 12, IMMED);
+
+	if (dir == OP_TYPE_ENCAP_PROTOCOL) {
+		MATHB(p, SEQINSZ, ADD, PDCP_MAC_I_LEN, VSEQOUTSZ, 4, IMMED2);
+		MATHB(p, SEQINSZ, SUB, ZERO, VSEQINSZ, 4, 0);
+	} else {
+		MATHB(p, SEQINSZ, SUB, PDCP_MAC_I_LEN, VSEQOUTSZ, 4, IMMED2);
+		MATHB(p, VSEQOUTSZ, SUB, ZERO, VSEQINSZ, 4, 0);
+	}
+
+	SEQSTORE(p, MATH0, 7, 1, 0);
+
+	if (dir == OP_TYPE_ENCAP_PROTOCOL) {
+		SEQFIFOSTORE(p, MSG, 0, 0, VLF);
+		SEQFIFOLOAD(p, MSGINSNOOP, 0, VLF | LAST2);
+	} else {
+		SEQFIFOSTORE(p, MSG, 0, 0, VLF | CONT);
+		SEQFIFOLOAD(p, MSGOUTSNOOP, 0, VLF | LAST2);
+	}
+
+	ALG_OPERATION(p, OP_ALG_ALGSEL_SNOW_F9,
+		      OP_ALG_AAI_F9,
+		      OP_ALG_AS_INITFINAL,
+		      dir == OP_TYPE_ENCAP_PROTOCOL ?
+			     ICV_CHECK_DISABLE : ICV_CHECK_ENABLE,
+		      DIR_DEC);
+
+	ALG_OPERATION(p, OP_ALG_ALGSEL_ZUCE,
+		      OP_ALG_AAI_F8,
+		      OP_ALG_AS_INITFINAL,
+		      ICV_CHECK_DISABLE,
+		      dir == OP_TYPE_ENCAP_PROTOCOL ? DIR_ENC : DIR_DEC);
+
+	if (dir == OP_TYPE_ENCAP_PROTOCOL) {
+		MOVE(p, CONTEXT2, 0, IFIFOAB1, 0, 4, LAST1 | FLUSH1 | IMMED);
+	} else {
+		SEQFIFOLOAD(p, MSG1, 4, LAST1 | FLUSH1);
+		JUMP(p, 1, LOCAL_JUMP, ALL_TRUE, CLASS1 | NOP | NIFP);
+
+		if (rta_sec_era >= RTA_SEC_ERA_6)
+			/*
+			 * For SEC ERA 6, there's a problem with the OFIFO
+			 * pointer, and thus it needs to be reset here before
+			 * moving to M0.
+			 */
+			LOAD(p, 0, DCTRL, 0, LDLEN_RST_CHA_OFIFO_PTR, IMMED);
+
+		/* Put ICV to M0 before sending it to C2 for comparison. */
+		MOVE(p, OFIFO, 0, MATH0, 0, 4, WAITCOMP | IMMED);
+
+		LOAD(p, NFIFOENTRY_STYPE_ALTSOURCE |
+		     NFIFOENTRY_DEST_CLASS2 |
+		     NFIFOENTRY_DTYPE_ICV |
+		     NFIFOENTRY_LC2 | 4, NFIFO_SZL, 0, 4, IMMED);
+		MOVE(p, MATH0, 0, ALTSOURCE, 0, 4, IMMED);
+	}
+
+	PATCH_JUMP(p, pkeyjump, keyjump);
+	return 0;
+}
+
+static inline int
+pdcp_insert_cplane_zuc_aes_op(struct program *p,
+			      bool swap __maybe_unused,
+			      struct alginfo *cipherdata,
+			      struct alginfo *authdata,
+			      unsigned int dir,
+			      unsigned char era_2_sw_hfn_ovrd __maybe_unused)
+{
+	if (rta_sec_era < RTA_SEC_ERA_5) {
+		pr_err("Invalid era for selected algorithm\n");
+		return -ENOTSUP;
+	}
+
+	if (rta_sec_era >= RTA_SEC_ERA_8) {
+		KEY(p, KEY1, cipherdata->key_enc_flags, cipherdata->key,
+				cipherdata->keylen, INLINE_KEY(cipherdata));
+		KEY(p, KEY2, authdata->key_enc_flags, authdata->key,
+				authdata->keylen, INLINE_KEY(authdata));
+
+		PROTOCOL(p, dir, OP_PCLID_LTE_PDCP_CTRL_MIXED,
+			 ((uint16_t)cipherdata->algtype << 8) |
+			 (uint16_t)authdata->algtype);
+		return 0;
+	}
+
+	SEQLOAD(p, MATH0, 7, 1, 0);
+	JUMP(p, 1, LOCAL_JUMP, ALL_TRUE, CALM);
+	if (swap == false)
+		MATHB(p, MATH0, AND, PDCP_C_PLANE_SN_MASK, MATH1, 8,
+			IFB | IMMED2);
+	else
+		MATHB(p, MATH0, AND, PDCP_C_PLANE_SN_MASK, MATH1, 8,
+			IFB | IMMED2);
+
+	MATHB(p, MATH1, SHLD, MATH1, MATH1, 8, 0);
+	MOVE(p, DESCBUF, 4, MATH2, 0, 0x08, WAITCOMP | IMMED);
+	MATHB(p, MATH1, OR, MATH2, MATH2, 8, 0);
+	SEQSTORE(p, MATH0, 7, 1, 0);
+	if (dir == OP_TYPE_ENCAP_PROTOCOL) {
+		KEY(p, KEY1, authdata->key_enc_flags, authdata->key,
+		    authdata->keylen, INLINE_KEY(authdata));
+		MOVE(p, MATH2, 0, IFIFOAB1, 0, 0x08, IMMED);
+		MOVE(p, MATH0, 7, IFIFOAB1, 0, 1, IMMED);
+
+		MATHB(p, SEQINSZ, SUB, ZERO, VSEQINSZ, 4, 0);
+		MATHB(p, VSEQINSZ, ADD, PDCP_MAC_I_LEN, VSEQOUTSZ, 4, IMMED2);
+
+		ALG_OPERATION(p, OP_ALG_ALGSEL_AES,
+			      OP_ALG_AAI_CMAC,
+			      OP_ALG_AS_INITFINAL,
+			      ICV_CHECK_DISABLE,
+			      DIR_DEC);
+		SEQFIFOLOAD(p, MSG1, 0, VLF | LAST1 | FLUSH1);
+		MOVE(p, CONTEXT1, 0, MATH3, 0, 4, WAITCOMP | IMMED);
+		LOAD(p, CLRW_RESET_CLS1_CHA |
+		     CLRW_CLR_C1KEY |
+		     CLRW_CLR_C1CTX |
+		     CLRW_CLR_C1ICV |
+		     CLRW_CLR_C1DATAS |
+		     CLRW_CLR_C1MODE,
+		     CLRW, 0, 4, IMMED);
+
+		KEY(p, KEY1, cipherdata->key_enc_flags, cipherdata->key,
+		    cipherdata->keylen, INLINE_KEY(cipherdata));
+
+		MOVE(p, MATH2, 0, CONTEXT1, 0, 8, IMMED);
+		SEQINPTR(p, 0, PDCP_NULL_MAX_FRAME_LEN, RTO);
+
+		ALG_OPERATION(p, OP_ALG_ALGSEL_ZUCE,
+			      OP_ALG_AAI_F8,
+			      OP_ALG_AS_INITFINAL,
+			      ICV_CHECK_DISABLE,
+			      DIR_ENC);
+		SEQFIFOSTORE(p, MSG, 0, 0, VLF);
+
+		SEQFIFOLOAD(p, SKIP, 1, 0);
+
+		SEQFIFOLOAD(p, MSG1, 0, VLF);
+		MOVE(p, MATH3, 0, IFIFOAB1, 0, 4, LAST1 | FLUSH1 | IMMED);
+	} else {
+		MOVE(p, MATH2, 0, CONTEXT1, 0, 8, IMMED);
+
+		MOVE(p, CONTEXT1, 0, CONTEXT2, 0, 8, IMMED);
+
+		MATHB(p, SEQINSZ, SUB, ZERO, VSEQINSZ, 4, 0);
+
+		MATHB(p, SEQINSZ, SUB, PDCP_MAC_I_LEN, VSEQOUTSZ, 4, IMMED2);
+
+		KEY(p, KEY1, cipherdata->key_enc_flags, cipherdata->key,
+		    cipherdata->keylen, INLINE_KEY(cipherdata));
+
+		MOVE(p, CONTEXT1, 0, CONTEXT2, 0, 8, IMMED);
+
+		ALG_OPERATION(p, OP_ALG_ALGSEL_ZUCE,
+			      OP_ALG_AAI_F8,
+			      OP_ALG_AS_INITFINAL,
+			      ICV_CHECK_DISABLE,
+			      DIR_DEC);
+		SEQFIFOSTORE(p, MSG, 0, 0, VLF | CONT);
+		SEQFIFOLOAD(p, MSG1, 0, VLF | LAST1 | FLUSH1);
+
+		MOVE(p, OFIFO, 0, MATH3, 0, 4, IMMED);
+
+		LOAD(p, CLRW_RESET_CLS1_CHA |
+		     CLRW_CLR_C1KEY |
+		     CLRW_CLR_C1CTX |
+		     CLRW_CLR_C1ICV |
+		     CLRW_CLR_C1DATAS |
+		     CLRW_CLR_C1MODE,
+		     CLRW, 0, 4, IMMED);
+
+		KEY(p, KEY1, authdata->key_enc_flags, authdata->key,
+		    authdata->keylen, INLINE_KEY(authdata));
+
+		SEQINPTR(p, 0, 0, SOP);
+
+		ALG_OPERATION(p, OP_ALG_ALGSEL_AES,
+			      OP_ALG_AAI_CMAC,
+			      OP_ALG_AS_INITFINAL,
+			      ICV_CHECK_ENABLE,
+			      DIR_DEC);
+
+		MATHB(p, SEQINSZ, SUB, ZERO, VSEQINSZ, 4, 0);
+
+		MOVE(p, CONTEXT2, 0, IFIFOAB1, 0, 8, IMMED);
+
+		SEQFIFOLOAD(p, MSG1, 0, VLF | LAST1 | FLUSH1);
+
+		LOAD(p, NFIFOENTRY_STYPE_ALTSOURCE |
+		     NFIFOENTRY_DEST_CLASS1 |
+		     NFIFOENTRY_DTYPE_ICV |
+		     NFIFOENTRY_LC1 |
+		     NFIFOENTRY_FC1 | 4, NFIFO_SZL, 0, 4, IMMED);
+		MOVE(p, MATH3, 0, ALTSOURCE, 0, 4, IMMED);
+	}
+
+	return 0;
+}
+
+static inline int
+pdcp_insert_uplane_15bit_op(struct program *p,
+			    bool swap __maybe_unused,
+			    struct alginfo *cipherdata,
+			    unsigned int dir)
+{
+	int op;
+	/* Insert Cipher Key */
+	KEY(p, KEY1, cipherdata->key_enc_flags, cipherdata->key,
+	    cipherdata->keylen, INLINE_KEY(cipherdata));
+
+	if (rta_sec_era >= RTA_SEC_ERA_8) {
+		PROTOCOL(p, dir, OP_PCLID_LTE_PDCP_USER,
+			 (uint16_t)cipherdata->algtype);
+		return 0;
+	}
+
+	SEQLOAD(p, MATH0, 6, 2, 0);
+	JUMP(p, 1, LOCAL_JUMP, ALL_TRUE, CALM);
+	if (swap == false)
+		MATHB(p, MATH0, AND, PDCP_U_PLANE_15BIT_SN_MASK, MATH1, 8,
+		      IFB | IMMED2);
+	else
+		MATHB(p, MATH0, AND, PDCP_U_PLANE_15BIT_SN_MASK_BE, MATH1, 8,
+		      IFB | IMMED2);
+	SEQSTORE(p, MATH0, 6, 2, 0);
+	MATHB(p, MATH1, SHLD, MATH1, MATH1, 8, 0);
+	MOVE(p, DESCBUF, 8, MATH2, 0, 8, WAITCOMP | IMMED);
+	MATHB(p, MATH1, OR, MATH2, MATH2, 8, 0);
+
+	MATHB(p, SEQINSZ, SUB, MATH3, VSEQINSZ, 4, 0);
+	MATHB(p, SEQINSZ, SUB, MATH3, VSEQOUTSZ, 4, 0);
+
+	SEQFIFOSTORE(p, MSG, 0, 0, VLF);
+
+	op = dir == OP_TYPE_ENCAP_PROTOCOL ? DIR_ENC : DIR_DEC;
+	switch (cipherdata->algtype) {
+	case PDCP_CIPHER_TYPE_SNOW:
+		MOVE(p, MATH2, 0, CONTEXT1, 0, 8, WAITCOMP | IMMED);
+		ALG_OPERATION(p, OP_ALG_ALGSEL_SNOW_F8,
+			      OP_ALG_AAI_F8,
+			      OP_ALG_AS_INITFINAL,
+			      ICV_CHECK_DISABLE,
+			      op);
+		break;
+
+	case PDCP_CIPHER_TYPE_AES:
+		MOVE(p, MATH2, 0, CONTEXT1, 0x10, 0x10, WAITCOMP | IMMED);
+		ALG_OPERATION(p, OP_ALG_ALGSEL_AES,
+			      OP_ALG_AAI_CTR,
+			      OP_ALG_AS_INITFINAL,
+			      ICV_CHECK_DISABLE,
+			      op);
+		break;
+
+	case PDCP_CIPHER_TYPE_ZUC:
+		if (rta_sec_era < RTA_SEC_ERA_5) {
+			pr_err("Invalid era for selected algorithm\n");
+			return -ENOTSUP;
+		}
+		MOVE(p, MATH2, 0, CONTEXT1, 0, 0x08, IMMED);
+		MOVE(p, MATH2, 0, CONTEXT1, 0x08, 0x08, WAITCOMP | IMMED);
+
+		ALG_OPERATION(p, OP_ALG_ALGSEL_ZUCE,
+			      OP_ALG_AAI_F8,
+			      OP_ALG_AS_INITFINAL,
+			      ICV_CHECK_DISABLE,
+			      op);
+		break;
+
+	default:
+		pr_err("%s: Invalid encrypt algorithm selected: %d\n",
+		       "pdcp_insert_uplane_15bit_op", cipherdata->algtype);
+		return -EINVAL;
+	}
+
+	SEQFIFOLOAD(p, MSG1, 0, VLF | LAST1 | FLUSH1);
+
+	return 0;
+}
+
+/*
+ * Function for inserting the snippet of code responsible for creating
+ * the HFN override code via either DPOVRD or via the input frame.
+ */
+static inline int
+insert_hfn_ov_op(struct program *p,
+		 uint32_t shift,
+		 enum pdb_type_e pdb_type,
+		 unsigned char era_2_sw_hfn_ovrd)
+{
+	uint32_t imm = PDCP_DPOVRD_HFN_OV_EN;
+	uint16_t hfn_pdb_offset;
+
+	if (rta_sec_era == RTA_SEC_ERA_2 && !era_2_sw_hfn_ovrd)
+		return 0;
+
+	switch (pdb_type) {
+	case PDCP_PDB_TYPE_NO_PDB:
+		/*
+		 * If there is no PDB, then HFN override mechanism does not
+		 * make any sense, thus in this case the function will
+		 * return the pointer to the current position in the
+		 * descriptor buffer
+		 */
+		return 0;
+
+	case PDCP_PDB_TYPE_REDUCED_PDB:
+		hfn_pdb_offset = 4;
+		break;
+
+	case PDCP_PDB_TYPE_FULL_PDB:
+		hfn_pdb_offset = 8;
+		break;
+
+	default:
+		return -EINVAL;
+	}
+
+	if (rta_sec_era > RTA_SEC_ERA_2) {
+		MATHB(p, DPOVRD, AND, imm, NONE, 8, IFB | IMMED2);
+	} else {
+		SEQLOAD(p, MATH0, 4, 4, 0);
+		JUMP(p, 1, LOCAL_JUMP, ALL_TRUE, CALM);
+		MATHB(p, MATH0, AND, imm, NONE, 8, IFB | IMMED2);
+		SEQSTORE(p, MATH0, 4, 4, 0);
+	}
+
+	if (rta_sec_era >= RTA_SEC_ERA_8)
+		JUMP(p, 6, LOCAL_JUMP, ALL_TRUE, MATH_Z);
+	else
+		JUMP(p, 5, LOCAL_JUMP, ALL_TRUE, MATH_Z);
+
+	if (rta_sec_era > RTA_SEC_ERA_2)
+		MATHB(p, DPOVRD, LSHIFT, shift, MATH0, 4, IMMED2);
+	else
+		MATHB(p, MATH0, LSHIFT, shift, MATH0, 4, IMMED2);
+
+	MATHB(p, MATH0, SHLD, MATH0, MATH0, 8, 0);
+	MOVE(p, MATH0, 0, DESCBUF, hfn_pdb_offset, 4, IMMED);
+
+	if (rta_sec_era >= RTA_SEC_ERA_8)
+		/*
+		 * For ERA8, DPOVRD could be handled by the PROTOCOL command
+		 * itself. For now, this is not done. Thus, clear DPOVRD here
+		 * to alleviate any side-effects.
+		 */
+		MATHB(p, DPOVRD, AND, ZERO, DPOVRD, 4, STL);
+
+	return 0;
+}
+
+/*
+ * PDCP Control PDB creation function
+ */
+static inline enum pdb_type_e
+cnstr_pdcp_c_plane_pdb(struct program *p,
+		       uint32_t hfn,
+		       unsigned char bearer,
+		       unsigned char direction,
+		       uint32_t hfn_threshold,
+		       struct alginfo *cipherdata,
+		       struct alginfo *authdata)
+{
+	struct pdcp_pdb pdb;
+	enum pdb_type_e
+		pdb_mask[PDCP_CIPHER_TYPE_INVALID][PDCP_AUTH_TYPE_INVALID] = {
+			{	/* NULL */
+				PDCP_PDB_TYPE_NO_PDB,		/* NULL */
+				PDCP_PDB_TYPE_FULL_PDB,		/* SNOW f9 */
+				PDCP_PDB_TYPE_FULL_PDB,		/* AES CMAC */
+				PDCP_PDB_TYPE_FULL_PDB		/* ZUC-I */
+			},
+			{	/* SNOW f8 */
+				PDCP_PDB_TYPE_FULL_PDB,		/* NULL */
+				PDCP_PDB_TYPE_FULL_PDB,		/* SNOW f9 */
+				PDCP_PDB_TYPE_REDUCED_PDB,	/* AES CMAC */
+				PDCP_PDB_TYPE_REDUCED_PDB	/* ZUC-I */
+			},
+			{	/* AES CTR */
+				PDCP_PDB_TYPE_FULL_PDB,		/* NULL */
+				PDCP_PDB_TYPE_REDUCED_PDB,	/* SNOW f9 */
+				PDCP_PDB_TYPE_FULL_PDB,		/* AES CMAC */
+				PDCP_PDB_TYPE_REDUCED_PDB	/* ZUC-I */
+			},
+			{	/* ZUC-E */
+				PDCP_PDB_TYPE_FULL_PDB,		/* NULL */
+				PDCP_PDB_TYPE_REDUCED_PDB,	/* SNOW f9 */
+				PDCP_PDB_TYPE_REDUCED_PDB,	/* AES CMAC */
+				PDCP_PDB_TYPE_FULL_PDB		/* ZUC-I */
+			},
+	};
+
+	if (rta_sec_era >= RTA_SEC_ERA_8) {
+		memset(&pdb, 0x00, sizeof(struct pdcp_pdb));
+
+		/* This is a HW issue. Bit 2 should be set to zero,
+		 * but it does not work this way. Override here.
+		 */
+		pdb.opt_res.rsvd = 0x00000002;
+
+		/* Copy relevant information from user to PDB */
+		pdb.hfn_res = hfn << PDCP_C_PLANE_PDB_HFN_SHIFT;
+		pdb.bearer_dir_res = (uint32_t)
+				((bearer << PDCP_C_PLANE_PDB_BEARER_SHIFT) |
+				 (direction << PDCP_C_PLANE_PDB_DIR_SHIFT));
+		pdb.hfn_thr_res =
+				hfn_threshold << PDCP_C_PLANE_PDB_HFN_THR_SHIFT;
+
+		/* copy PDB in descriptor*/
+		__rta_out32(p, pdb.opt_res.opt);
+		__rta_out32(p, pdb.hfn_res);
+		__rta_out32(p, pdb.bearer_dir_res);
+		__rta_out32(p, pdb.hfn_thr_res);
+
+		return PDCP_PDB_TYPE_FULL_PDB;
+	}
+
+	switch (pdb_mask[cipherdata->algtype][authdata->algtype]) {
+	case PDCP_PDB_TYPE_NO_PDB:
+		break;
+
+	case PDCP_PDB_TYPE_REDUCED_PDB:
+		__rta_out32(p, (hfn << PDCP_C_PLANE_PDB_HFN_SHIFT));
+		__rta_out32(p,
+			    (uint32_t)((bearer <<
+					PDCP_C_PLANE_PDB_BEARER_SHIFT) |
+					(direction <<
+					 PDCP_C_PLANE_PDB_DIR_SHIFT)));
+		break;
+
+	case PDCP_PDB_TYPE_FULL_PDB:
+		memset(&pdb, 0x00, sizeof(struct pdcp_pdb));
+
+		/* This is a HW issue. Bit 2 should be set to zero,
+		 * but it does not work this way. Override here.
+		 */
+		pdb.opt_res.rsvd = 0x00000002;
+
+		/* Copy relevant information from user to PDB */
+		pdb.hfn_res = hfn << PDCP_C_PLANE_PDB_HFN_SHIFT;
+		pdb.bearer_dir_res = (uint32_t)
+			((bearer << PDCP_C_PLANE_PDB_BEARER_SHIFT) |
+			 (direction << PDCP_C_PLANE_PDB_DIR_SHIFT));
+		pdb.hfn_thr_res =
+			hfn_threshold << PDCP_C_PLANE_PDB_HFN_THR_SHIFT;
+
+		/* copy PDB in descriptor*/
+		__rta_out32(p, pdb.opt_res.opt);
+		__rta_out32(p, pdb.hfn_res);
+		__rta_out32(p, pdb.bearer_dir_res);
+		__rta_out32(p, pdb.hfn_thr_res);
+
+		break;
+
+	default:
+		return PDCP_PDB_TYPE_INVALID;
+	}
+
+	return pdb_mask[cipherdata->algtype][authdata->algtype];
+}
+
+/*
+ * PDCP UPlane PDB creation function
+ */
+static inline int
+cnstr_pdcp_u_plane_pdb(struct program *p,
+		       enum pdcp_sn_size sn_size,
+		       uint32_t hfn, unsigned short bearer,
+		       unsigned short direction,
+		       uint32_t hfn_threshold)
+{
+	struct pdcp_pdb pdb;
+	/* Read options from user */
+	/* Depending on sequence number length, the HFN and HFN threshold
+	 * have different lengths.
+	 */
+	memset(&pdb, 0x00, sizeof(struct pdcp_pdb));
+
+	switch (sn_size) {
+	case PDCP_SN_SIZE_7:
+		pdb.opt_res.opt |= PDCP_U_PLANE_PDB_OPT_SHORT_SN;
+		pdb.hfn_res = hfn << PDCP_U_PLANE_PDB_SHORT_SN_HFN_SHIFT;
+		pdb.hfn_thr_res =
+			hfn_threshold<<PDCP_U_PLANE_PDB_SHORT_SN_HFN_THR_SHIFT;
+		break;
+
+	case PDCP_SN_SIZE_12:
+		pdb.opt_res.opt &= (uint32_t)(~PDCP_U_PLANE_PDB_OPT_SHORT_SN);
+		pdb.hfn_res = hfn << PDCP_U_PLANE_PDB_LONG_SN_HFN_SHIFT;
+		pdb.hfn_thr_res =
+			hfn_threshold<<PDCP_U_PLANE_PDB_LONG_SN_HFN_THR_SHIFT;
+		break;
+
+	case PDCP_SN_SIZE_15:
+		pdb.opt_res.opt = (uint32_t)(PDCP_U_PLANE_PDB_OPT_15B_SN);
+		pdb.hfn_res = hfn << PDCP_U_PLANE_PDB_15BIT_SN_HFN_SHIFT;
+		pdb.hfn_thr_res =
+			hfn_threshold<<PDCP_U_PLANE_PDB_15BIT_SN_HFN_THR_SHIFT;
+		break;
+
+	default:
+		pr_err("Invalid Sequence Number Size setting in PDB\n");
+		return -EINVAL;
+	}
+
+	pdb.bearer_dir_res = (uint32_t)
+				((bearer << PDCP_U_PLANE_PDB_BEARER_SHIFT) |
+				 (direction << PDCP_U_PLANE_PDB_DIR_SHIFT));
+
+	/* copy PDB in descriptor*/
+	__rta_out32(p, pdb.opt_res.opt);
+	__rta_out32(p, pdb.hfn_res);
+	__rta_out32(p, pdb.bearer_dir_res);
+	__rta_out32(p, pdb.hfn_thr_res);
+
+	return 0;
+}
+/**
+ * cnstr_shdsc_pdcp_c_plane_encap - Function for creating a PDCP Control Plane
+ *                                  encapsulation descriptor.
+ * @descbuf: pointer to buffer for descriptor construction
+ * @ps: if 36/40bit addressing is desired, this parameter must be true
+ * @swap: must be true when core endianness doesn't match SEC endianness
+ * @hfn: starting Hyper Frame Number to be used together with the SN from the
+ *       PDCP frames.
+ * @bearer: radio bearer ID
+ * @direction: the direction of the PDCP frame (UL/DL)
+ * @hfn_threshold: HFN value that once reached triggers a warning from SEC that
+ *                 keys should be renegotiated at the earliest convenience.
+ * @cipherdata: pointer to block cipher transform definitions
+ *              Valid algorithm values are those from cipher_type_pdcp enum.
+ * @authdata: pointer to authentication transform definitions
+ *            Valid algorithm values are those from auth_type_pdcp enum.
+ * @era_2_sw_hfn_ovrd: if software HFN override mechanism is desired for
+ *                     this descriptor. Note: Can only be used for
+ *                     SEC ERA 2.
+ * Return: size of descriptor written in words or negative number on error.
+ *         Once the function returns, the value of this parameter can be used
+ *         for reclaiming the space that wasn't used for the descriptor.
+ *
+ * Note: descbuf must be large enough to contain a full 256 byte long
+ * descriptor; after the function returns, by subtracting the actual number of
+ * bytes used, the user can reuse the remaining buffer space for other purposes.
+ */
+static inline int
+cnstr_shdsc_pdcp_c_plane_encap(uint32_t *descbuf,
+			       bool ps,
+			       bool swap,
+			       uint32_t hfn,
+			       unsigned char bearer,
+			       unsigned char direction,
+			       uint32_t hfn_threshold,
+			       struct alginfo *cipherdata,
+			       struct alginfo *authdata,
+			       unsigned char era_2_sw_hfn_ovrd)
+{
+	static int
+		(*pdcp_cp_fp[PDCP_CIPHER_TYPE_INVALID][PDCP_AUTH_TYPE_INVALID])
+			(struct program*, bool swap, struct alginfo *,
+			 struct alginfo *, unsigned int,
+			unsigned char __maybe_unused) = {
+		{	/* NULL */
+			pdcp_insert_cplane_null_op,	/* NULL */
+			pdcp_insert_cplane_int_only_op,	/* SNOW f9 */
+			pdcp_insert_cplane_int_only_op,	/* AES CMAC */
+			pdcp_insert_cplane_int_only_op	/* ZUC-I */
+		},
+		{	/* SNOW f8 */
+			pdcp_insert_cplane_enc_only_op,	/* NULL */
+			pdcp_insert_cplane_acc_op,	/* SNOW f9 */
+			pdcp_insert_cplane_snow_aes_op,	/* AES CMAC */
+			pdcp_insert_cplane_snow_zuc_op	/* ZUC-I */
+		},
+		{	/* AES CTR */
+			pdcp_insert_cplane_enc_only_op,	/* NULL */
+			pdcp_insert_cplane_aes_snow_op,	/* SNOW f9 */
+			pdcp_insert_cplane_acc_op,	/* AES CMAC */
+			pdcp_insert_cplane_aes_zuc_op	/* ZUC-I */
+		},
+		{	/* ZUC-E */
+			pdcp_insert_cplane_enc_only_op,	/* NULL */
+			pdcp_insert_cplane_zuc_snow_op,	/* SNOW f9 */
+			pdcp_insert_cplane_zuc_aes_op,	/* AES CMAC */
+			pdcp_insert_cplane_acc_op	/* ZUC-I */
+		},
+	};
+	static enum rta_share_type
+		desc_share[PDCP_CIPHER_TYPE_INVALID][PDCP_AUTH_TYPE_INVALID] = {
+		{	/* NULL */
+			SHR_WAIT,	/* NULL */
+			SHR_ALWAYS,	/* SNOW f9 */
+			SHR_ALWAYS,	/* AES CMAC */
+			SHR_ALWAYS	/* ZUC-I */
+		},
+		{	/* SNOW f8 */
+			SHR_ALWAYS,	/* NULL */
+			SHR_ALWAYS,	/* SNOW f9 */
+			SHR_WAIT,	/* AES CMAC */
+			SHR_WAIT	/* ZUC-I */
+		},
+		{	/* AES CTR */
+			SHR_ALWAYS,	/* NULL */
+			SHR_ALWAYS,	/* SNOW f9 */
+			SHR_ALWAYS,	/* AES CMAC */
+			SHR_WAIT	/* ZUC-I */
+		},
+		{	/* ZUC-E */
+			SHR_ALWAYS,	/* NULL */
+			SHR_WAIT,	/* SNOW f9 */
+			SHR_WAIT,	/* AES CMAC */
+			SHR_ALWAYS	/* ZUC-I */
+		},
+	};
+	enum pdb_type_e pdb_type;
+	struct program prg;
+	struct program *p = &prg;
+	int err;
+	LABEL(pdb_end);
+
+	if (rta_sec_era != RTA_SEC_ERA_2 && era_2_sw_hfn_ovrd) {
+		pr_err("Cannot select SW HFN override for other era than 2");
+		return -EINVAL;
+	}
+
+	PROGRAM_CNTXT_INIT(p, descbuf, 0);
+	if (swap)
+		PROGRAM_SET_BSWAP(p);
+	if (ps)
+		PROGRAM_SET_36BIT_ADDR(p);
+
+	SHR_HDR(p, desc_share[cipherdata->algtype][authdata->algtype], 0, 0);
+
+	pdb_type = cnstr_pdcp_c_plane_pdb(p,
+			hfn,
+			bearer,
+			direction,
+			hfn_threshold,
+			cipherdata,
+			authdata);
+
+	SET_LABEL(p, pdb_end);
+
+	err = insert_hfn_ov_op(p, PDCP_SN_SIZE_5, pdb_type,
+			       era_2_sw_hfn_ovrd);
+	if (err)
+		return err;
+
+	err = pdcp_cp_fp[cipherdata->algtype][authdata->algtype](p,
+		swap,
+		cipherdata,
+		authdata,
+		OP_TYPE_ENCAP_PROTOCOL,
+		era_2_sw_hfn_ovrd);
+	if (err)
+		return err;
+
+	PATCH_HDR(p, 0, pdb_end);
+
+	return PROGRAM_FINALIZE(p);
+}
+
+/**
+ * cnstr_shdsc_pdcp_c_plane_decap - Function for creating a PDCP Control Plane
+ *                                  decapsulation descriptor.
+ * @descbuf: pointer to buffer for descriptor construction
+ * @ps: if 36/40bit addressing is desired, this parameter must be true
+ * @swap: must be true when core endianness doesn't match SEC endianness
+ * @hfn: starting Hyper Frame Number to be used together with the SN from the
+ *       PDCP frames.
+ * @bearer: radio bearer ID
+ * @direction: the direction of the PDCP frame (UL/DL)
+ * @hfn_threshold: HFN value that once reached triggers a warning from SEC that
+ *                 keys should be renegotiated at the earliest convenience.
+ * @cipherdata: pointer to block cipher transform definitions
+ *              Valid algorithm values are those from cipher_type_pdcp enum.
+ * @authdata: pointer to authentication transform definitions
+ *            Valid algorithm values are those from auth_type_pdcp enum.
+ * @era_2_sw_hfn_ovrd: if software HFN override mechanism is desired for
+ *                     this descriptor. Note: Can only be used for
+ *                     SEC ERA 2.
+ *
+ * Return: size of descriptor written in words or negative number on error.
+ *         Once the function returns, the value of this parameter can be used
+ *         for reclaiming the space that wasn't used for the descriptor.
+ *
+ * Note: descbuf must be large enough to contain a full 256 byte long
+ * descriptor; after the function returns, by subtracting the actual number of
+ * bytes used, the user can reuse the remaining buffer space for other purposes.
+ */
+static inline int
+cnstr_shdsc_pdcp_c_plane_decap(uint32_t *descbuf,
+			       bool ps,
+			       bool swap,
+			       uint32_t hfn,
+			       unsigned char bearer,
+			       unsigned char direction,
+			       uint32_t hfn_threshold,
+			       struct alginfo *cipherdata,
+			       struct alginfo *authdata,
+			       unsigned char era_2_sw_hfn_ovrd)
+{
+	static int
+		(*pdcp_cp_fp[PDCP_CIPHER_TYPE_INVALID][PDCP_AUTH_TYPE_INVALID])
+			(struct program*, bool swap, struct alginfo *,
+			 struct alginfo *, unsigned int, unsigned char) = {
+		{	/* NULL */
+			pdcp_insert_cplane_null_op,	/* NULL */
+			pdcp_insert_cplane_int_only_op,	/* SNOW f9 */
+			pdcp_insert_cplane_int_only_op,	/* AES CMAC */
+			pdcp_insert_cplane_int_only_op	/* ZUC-I */
+		},
+		{	/* SNOW f8 */
+			pdcp_insert_cplane_enc_only_op,	/* NULL */
+			pdcp_insert_cplane_acc_op,	/* SNOW f9 */
+			pdcp_insert_cplane_snow_aes_op,	/* AES CMAC */
+			pdcp_insert_cplane_snow_zuc_op	/* ZUC-I */
+		},
+		{	/* AES CTR */
+			pdcp_insert_cplane_enc_only_op,	/* NULL */
+			pdcp_insert_cplane_aes_snow_op,	/* SNOW f9 */
+			pdcp_insert_cplane_acc_op,	/* AES CMAC */
+			pdcp_insert_cplane_aes_zuc_op	/* ZUC-I */
+		},
+		{	/* ZUC-E */
+			pdcp_insert_cplane_enc_only_op,	/* NULL */
+			pdcp_insert_cplane_zuc_snow_op,	/* SNOW f9 */
+			pdcp_insert_cplane_zuc_aes_op,	/* AES CMAC */
+			pdcp_insert_cplane_acc_op	/* ZUC-I */
+		},
+	};
+	static enum rta_share_type
+		desc_share[PDCP_CIPHER_TYPE_INVALID][PDCP_AUTH_TYPE_INVALID] = {
+		{	/* NULL */
+			SHR_WAIT,	/* NULL */
+			SHR_ALWAYS,	/* SNOW f9 */
+			SHR_ALWAYS,	/* AES CMAC */
+			SHR_ALWAYS	/* ZUC-I */
+		},
+		{	/* SNOW f8 */
+			SHR_ALWAYS,	/* NULL */
+			SHR_ALWAYS,	/* SNOW f9 */
+			SHR_WAIT,	/* AES CMAC */
+			SHR_WAIT	/* ZUC-I */
+		},
+		{	/* AES CTR */
+			SHR_ALWAYS,	/* NULL */
+			SHR_ALWAYS,	/* SNOW f9 */
+			SHR_ALWAYS,	/* AES CMAC */
+			SHR_WAIT	/* ZUC-I */
+		},
+		{	/* ZUC-E */
+			SHR_ALWAYS,	/* NULL */
+			SHR_WAIT,	/* SNOW f9 */
+			SHR_WAIT,	/* AES CMAC */
+			SHR_ALWAYS	/* ZUC-I */
+		},
+	};
+	enum pdb_type_e pdb_type;
+	struct program prg;
+	struct program *p = &prg;
+	int err;
+	LABEL(pdb_end);
+
+	if (rta_sec_era != RTA_SEC_ERA_2 && era_2_sw_hfn_ovrd) {
+		pr_err("Cannot select SW HFN override for other era than 2");
+		return -EINVAL;
+	}
+
+	PROGRAM_CNTXT_INIT(p, descbuf, 0);
+	if (swap)
+		PROGRAM_SET_BSWAP(p);
+	if (ps)
+		PROGRAM_SET_36BIT_ADDR(p);
+
+	SHR_HDR(p, desc_share[cipherdata->algtype][authdata->algtype], 0, 0);
+
+	pdb_type = cnstr_pdcp_c_plane_pdb(p,
+			hfn,
+			bearer,
+			direction,
+			hfn_threshold,
+			cipherdata,
+			authdata);
+
+	SET_LABEL(p, pdb_end);
+
+	err = insert_hfn_ov_op(p, PDCP_SN_SIZE_5, pdb_type,
+			       era_2_sw_hfn_ovrd);
+	if (err)
+		return err;
+
+	err = pdcp_cp_fp[cipherdata->algtype][authdata->algtype](p,
+		swap,
+		cipherdata,
+		authdata,
+		OP_TYPE_DECAP_PROTOCOL,
+		era_2_sw_hfn_ovrd);
+	if (err)
+		return err;
+
+	PATCH_HDR(p, 0, pdb_end);
+
+	return PROGRAM_FINALIZE(p);
+}
+
+/**
+ * cnstr_shdsc_pdcp_u_plane_encap - Function for creating a PDCP User Plane
+ *                                  encapsulation descriptor.
+ * @descbuf: pointer to buffer for descriptor construction
+ * @ps: if 36/40bit addressing is desired, this parameter must be true
+ * @swap: must be true when core endianness doesn't match SEC endianness
+ * @sn_size: selects Sequence Number Size: 7/12/15 bits
+ * @hfn: starting Hyper Frame Number to be used together with the SN from the
+ *       PDCP frames.
+ * @bearer: radio bearer ID
+ * @direction: the direction of the PDCP frame (UL/DL)
+ * @hfn_threshold: HFN value that once reached triggers a warning from SEC that
+ *                 keys should be renegotiated at the earliest convenience.
+ * @cipherdata: pointer to block cipher transform definitions
+ *              Valid algorithm values are those from cipher_type_pdcp enum.
+ * @era_2_sw_hfn_ovrd: if software HFN override mechanism is desired for
+ *                     this descriptor. Note: Can only be used for
+ *                     SEC ERA 2.
+ *
+ * Return: size of descriptor written in words or negative number on error.
+ *         Once the function returns, the value of this parameter can be used
+ *         for reclaiming the space that wasn't used for the descriptor.
+ *
+ * Note: descbuf must be large enough to contain a full 256 byte long
+ * descriptor; after the function returns, by subtracting the actual number of
+ * bytes used, the user can reuse the remaining buffer space for other purposes.
+ */
+static inline int
+cnstr_shdsc_pdcp_u_plane_encap(uint32_t *descbuf,
+			       bool ps,
+			       bool swap,
+			       enum pdcp_sn_size sn_size,
+			       uint32_t hfn,
+			       unsigned short bearer,
+			       unsigned short direction,
+			       uint32_t hfn_threshold,
+			       struct alginfo *cipherdata,
+			       unsigned char era_2_sw_hfn_ovrd)
+{
+	struct program prg;
+	struct program *p = &prg;
+	int err;
+	LABEL(pdb_end);
+
+	if (rta_sec_era != RTA_SEC_ERA_2 && era_2_sw_hfn_ovrd) {
+		pr_err("Cannot select SW HFN ovrd for other era than 2");
+		return -EINVAL;
+	}
+
+	PROGRAM_CNTXT_INIT(p, descbuf, 0);
+	if (swap)
+		PROGRAM_SET_BSWAP(p);
+	if (ps)
+		PROGRAM_SET_36BIT_ADDR(p);
+
+	SHR_HDR(p, SHR_ALWAYS, 0, 0);
+	if (cnstr_pdcp_u_plane_pdb(p, sn_size, hfn, bearer, direction,
+				   hfn_threshold)) {
+		pr_err("Error creating PDCP UPlane PDB\n");
+		return -EINVAL;
+	}
+	SET_LABEL(p, pdb_end);
+
+	err = insert_hfn_ov_op(p, sn_size, PDCP_PDB_TYPE_FULL_PDB,
+			       era_2_sw_hfn_ovrd);
+	if (err)
+		return err;
+
+	switch (sn_size) {
+	case PDCP_SN_SIZE_7:
+	case PDCP_SN_SIZE_12:
+		switch (cipherdata->algtype) {
+		case PDCP_CIPHER_TYPE_ZUC:
+			if (rta_sec_era < RTA_SEC_ERA_5) {
+				pr_err("Invalid era for selected algorithm\n");
+				return -ENOTSUP;
+			}
+		case PDCP_CIPHER_TYPE_AES:
+		case PDCP_CIPHER_TYPE_SNOW:
+			/* Insert Cipher Key */
+			KEY(p, KEY1, cipherdata->key_enc_flags,
+			    (uint64_t)cipherdata->key, cipherdata->keylen,
+			    INLINE_KEY(cipherdata));
+			PROTOCOL(p, OP_TYPE_ENCAP_PROTOCOL,
+				 OP_PCLID_LTE_PDCP_USER,
+				 (uint16_t)cipherdata->algtype);
+			break;
+		case PDCP_CIPHER_TYPE_NULL:
+			insert_copy_frame_op(p,
+					     cipherdata,
+					     OP_TYPE_ENCAP_PROTOCOL);
+			break;
+		default:
+			pr_err("%s: Invalid encrypt algorithm selected: %d\n",
+			       "cnstr_pcl_shdsc_pdcp_u_plane_decap",
+			       cipherdata->algtype);
+			return -EINVAL;
+		}
+		break;
+
+	case PDCP_SN_SIZE_15:
+		switch (cipherdata->algtype) {
+		case PDCP_CIPHER_TYPE_NULL:
+			insert_copy_frame_op(p,
+					     cipherdata,
+					     OP_TYPE_ENCAP_PROTOCOL);
+			break;
+
+		default:
+			err = pdcp_insert_uplane_15bit_op(p, swap, cipherdata,
+				OP_TYPE_ENCAP_PROTOCOL);
+			if (err)
+				return err;
+			break;
+		}
+		break;
+
+	case PDCP_SN_SIZE_5:
+	default:
+		pr_err("Invalid SN size selected\n");
+		return -ENOTSUP;
+	}
+
+	PATCH_HDR(p, 0, pdb_end);
+	return PROGRAM_FINALIZE(p);
+}
+
+/**
+ * cnstr_shdsc_pdcp_u_plane_decap - Function for creating a PDCP User Plane
+ *                                  decapsulation descriptor.
+ * @descbuf: pointer to buffer for descriptor construction
+ * @ps: if 36/40bit addressing is desired, this parameter must be true
+ * @swap: must be true when core endianness doesn't match SEC endianness
+ * @sn_size: selects Sequence Number Size: 7/12/15 bits
+ * @hfn: starting Hyper Frame Number to be used together with the SN from the
+ *       PDCP frames.
+ * @bearer: radio bearer ID
+ * @direction: the direction of the PDCP frame (UL/DL)
+ * @hfn_threshold: HFN value that once reached triggers a warning from SEC that
+ *                 keys should be renegotiated at the earliest convenience.
+ * @cipherdata: pointer to block cipher transform definitions
+ *              Valid algorithm values are those from cipher_type_pdcp enum.
+ * @era_2_sw_hfn_ovrd: if software HFN override mechanism is desired for
+ *                     this descriptor. Note: Can only be used for
+ *                     SEC ERA 2.
+ *
+ * Return: size of descriptor written in words or negative number on error.
+ *         Once the function returns, the value of this parameter can be used
+ *         for reclaiming the space that wasn't used for the descriptor.
+ *
+ * Note: descbuf must be large enough to contain a full 256 byte long
+ * descriptor; after the function returns, by subtracting the actual number of
+ * bytes used, the user can reuse the remaining buffer space for other purposes.
+ */
+static inline int
+cnstr_shdsc_pdcp_u_plane_decap(uint32_t *descbuf,
+			       bool ps,
+			       bool swap,
+			       enum pdcp_sn_size sn_size,
+			       uint32_t hfn,
+			       unsigned short bearer,
+			       unsigned short direction,
+			       uint32_t hfn_threshold,
+			       struct alginfo *cipherdata,
+			       unsigned char era_2_sw_hfn_ovrd)
+{
+	struct program prg;
+	struct program *p = &prg;
+	int err;
+	LABEL(pdb_end);
+
+	if (rta_sec_era != RTA_SEC_ERA_2 && era_2_sw_hfn_ovrd) {
+		pr_err("Cannot select SW HFN override for other era than 2");
+		return -EINVAL;
+	}
+
+	PROGRAM_CNTXT_INIT(p, descbuf, 0);
+	if (swap)
+		PROGRAM_SET_BSWAP(p);
+	if (ps)
+		PROGRAM_SET_36BIT_ADDR(p);
+
+	SHR_HDR(p, SHR_ALWAYS, 0, 0);
+	if (cnstr_pdcp_u_plane_pdb(p, sn_size, hfn, bearer, direction,
+				   hfn_threshold)) {
+		pr_err("Error creating PDCP UPlane PDB\n");
+		return -EINVAL;
+	}
+	SET_LABEL(p, pdb_end);
+
+	err = insert_hfn_ov_op(p, sn_size, PDCP_PDB_TYPE_FULL_PDB,
+			       era_2_sw_hfn_ovrd);
+	if (err)
+		return err;
+
+	switch (sn_size) {
+	case PDCP_SN_SIZE_7:
+	case PDCP_SN_SIZE_12:
+		switch (cipherdata->algtype) {
+		case PDCP_CIPHER_TYPE_ZUC:
+			if (rta_sec_era < RTA_SEC_ERA_5) {
+				pr_err("Invalid era for selected algorithm\n");
+				return -ENOTSUP;
+			}
+		case PDCP_CIPHER_TYPE_AES:
+		case PDCP_CIPHER_TYPE_SNOW:
+			/* Insert Cipher Key */
+			KEY(p, KEY1, cipherdata->key_enc_flags,
+			    cipherdata->key, cipherdata->keylen,
+			    INLINE_KEY(cipherdata));
+			PROTOCOL(p, OP_TYPE_DECAP_PROTOCOL,
+				 OP_PCLID_LTE_PDCP_USER,
+				 (uint16_t)cipherdata->algtype);
+			break;
+		case PDCP_CIPHER_TYPE_NULL:
+			insert_copy_frame_op(p,
+					     cipherdata,
+					     OP_TYPE_DECAP_PROTOCOL);
+			break;
+		default:
+			pr_err("%s: Invalid encrypt algorithm selected: %d\n",
+			       "cnstr_pcl_shdsc_pdcp_u_plane_decap",
+			       cipherdata->algtype);
+			return -EINVAL;
+		}
+		break;
+
+	case PDCP_SN_SIZE_15:
+		switch (cipherdata->algtype) {
+		case PDCP_CIPHER_TYPE_NULL:
+			insert_copy_frame_op(p,
+					     cipherdata,
+					     OP_TYPE_DECAP_PROTOCOL);
+			break;
+
+		default:
+			err = pdcp_insert_uplane_15bit_op(p, swap, cipherdata,
+				OP_TYPE_DECAP_PROTOCOL);
+			if (err)
+				return err;
+			break;
+		}
+		break;
+
+	case PDCP_SN_SIZE_5:
+	default:
+		pr_err("Invalid SN size selected\n");
+		return -ENOTSUP;
+	}
+
+	PATCH_HDR(p, 0, pdb_end);
+	return PROGRAM_FINALIZE(p);
+}
+
+/**
+ * cnstr_shdsc_pdcp_short_mac - Function for creating a PDCP Short MAC
+ *                              descriptor.
+ * @descbuf: pointer to buffer for descriptor construction
+ * @ps: if 36/40bit addressing is desired, this parameter must be true
+ * @swap: must be true when core endianness doesn't match SEC endianness
+ * @authdata: pointer to authentication transform definitions
+ *            Valid algorithm values are those from auth_type_pdcp enum.
+ *
+ * Return: size of descriptor written in words or negative number on error.
+ *         Once the function returns, the value of this parameter can be used
+ *         for reclaiming the space that wasn't used for the descriptor.
+ *
+ * Note: descbuf must be large enough to contain a full 256 byte long
+ * descriptor; after the function returns, by subtracting the actual number of
+ * bytes used, the user can reuse the remaining buffer space for other purposes.
+ */
+static inline int
+cnstr_shdsc_pdcp_short_mac(uint32_t *descbuf,
+			   bool ps,
+			   bool swap,
+			   struct alginfo *authdata)
+{
+	struct program prg;
+	struct program *p = &prg;
+	uint32_t iv[3] = {0, 0, 0};
+	LABEL(local_offset);
+	REFERENCE(move_cmd_read_descbuf);
+	REFERENCE(move_cmd_write_descbuf);
+
+	PROGRAM_CNTXT_INIT(p, descbuf, 0);
+	if (swap)
+		PROGRAM_SET_BSWAP(p);
+	if (ps)
+		PROGRAM_SET_36BIT_ADDR(p);
+
+	SHR_HDR(p, SHR_ALWAYS, 1, 0);
+
+	if (rta_sec_era > RTA_SEC_ERA_2) {
+		MATHB(p, SEQINSZ, SUB, ZERO, VSEQINSZ, 4, 0);
+		MATHB(p, SEQINSZ, SUB, ZERO, MATH1, 4, 0);
+	} else {
+		MATHB(p, SEQINSZ, ADD, ONE, MATH1, 4, 0);
+		MATHB(p, MATH1, SUB, ONE, MATH1, 4, 0);
+		MATHB(p, ZERO, ADD, MATH1, VSEQINSZ, 4, 0);
+		MOVE(p, MATH1, 0, MATH0, 0, 8, IMMED);
+
+		/*
+		 * Since MOVELEN is available only starting with
+		 * SEC ERA 3, use poor man's MOVELEN: create a MOVE
+		 * command dynamically by writing the length from M1 by
+		 * OR-ing the command in the M1 register and MOVE the
+		 * result into the descriptor buffer. Care must be taken
+		 * wrt. the location of the command because of SEC
+		 * pipelining. The actual MOVEs are written at the end
+		 * of the descriptor due to calculations needed on the
+		 * offset in the descriptor for the MOVE command.
+		 */
+		move_cmd_read_descbuf = MOVE(p, DESCBUF, 0, MATH0, 0, 6,
+					     IMMED);
+		move_cmd_write_descbuf = MOVE(p, MATH0, 0, DESCBUF, 0, 8,
+					      WAITCOMP | IMMED);
+	}
+	MATHB(p, ZERO, ADD, MATH1, VSEQOUTSZ, 4, 0);
+
+	switch (authdata->algtype) {
+	case PDCP_AUTH_TYPE_NULL:
+		SEQFIFOSTORE(p, MSG, 0, 0, VLF);
+		if (rta_sec_era > RTA_SEC_ERA_2) {
+			MOVE(p, AB1, 0, OFIFO, 0, MATH1, 0);
+		} else {
+			SET_LABEL(p, local_offset);
+
+			/* Shut off automatic Info FIFO entries */
+			LOAD(p, 0, DCTRL, LDOFF_DISABLE_AUTO_NFIFO, 0, IMMED);
+
+			/* Placeholder for MOVE command with length from M1
+			 * register
+			 */
+			MOVE(p, IFIFOAB1, 0, OFIFO, 0, 0, IMMED);
+
+			/* Enable automatic Info FIFO entries */
+			LOAD(p, 0, DCTRL, LDOFF_ENABLE_AUTO_NFIFO, 0, IMMED);
+		}
+
+		LOAD(p, (uintptr_t)iv, MATH0, 0, 8, IMMED | COPY);
+		SEQFIFOLOAD(p, MSG1, 0, VLF | LAST1 | LAST2 | FLUSH1);
+		SEQSTORE(p, MATH0, 0, 4, 0);
+
+		break;
+
+	case PDCP_AUTH_TYPE_SNOW:
+		iv[0] = 0xFFFFFFFF;
+		iv[1] = swap ? swab32(0x04000000) : 0x04000000;
+		iv[2] = swap ? swab32(0xF8000000) : 0xF8000000;
+
+		KEY(p, KEY2, authdata->key_enc_flags, authdata->key,
+		    authdata->keylen, INLINE_KEY(authdata));
+		LOAD(p, (uintptr_t)&iv, CONTEXT2, 0, 12, IMMED | COPY);
+		ALG_OPERATION(p, OP_ALG_ALGSEL_SNOW_F9,
+			      OP_ALG_AAI_F9,
+			      OP_ALG_AS_INITFINAL,
+			      ICV_CHECK_DISABLE,
+			      DIR_ENC);
+		SEQFIFOSTORE(p, MSG, 0, 0, VLF);
+
+		if (rta_sec_era > RTA_SEC_ERA_2) {
+			MOVE(p, AB1, 0, OFIFO, 0, MATH1, 0);
+		} else {
+			SET_LABEL(p, local_offset);
+
+
+			/* Shut off automatic Info FIFO entries */
+			LOAD(p, 0, DCTRL, LDOFF_DISABLE_AUTO_NFIFO, 0, IMMED);
+
+			/* Placeholder for MOVE command with length from M1
+			 * register
+			 */
+			MOVE(p, IFIFOAB1, 0, OFIFO, 0, 0, IMMED);
+
+			/* Enable automatic Info FIFO entries */
+			LOAD(p, 0, DCTRL, LDOFF_ENABLE_AUTO_NFIFO, 0, IMMED);
+		}
+		SEQFIFOLOAD(p, MSGINSNOOP, 0, VLF | LAST1 | LAST2 | FLUSH1);
+		SEQSTORE(p, CONTEXT2, 0, 4, 0);
+
+		break;
+
+	case PDCP_AUTH_TYPE_AES:
+		iv[0] = 0xFFFFFFFF;
+		iv[1] = swap ? swab32(0xFC000000) : 0xFC000000;
+		iv[2] = 0x00000000; /* unused */
+
+		KEY(p, KEY1, authdata->key_enc_flags, authdata->key,
+		    authdata->keylen, INLINE_KEY(authdata));
+		LOAD(p, (uintptr_t)&iv, MATH0, 0, 8, IMMED | COPY);
+		MOVE(p, MATH0, 0, IFIFOAB1, 0, 8, IMMED);
+		ALG_OPERATION(p, OP_ALG_ALGSEL_AES,
+			      OP_ALG_AAI_CMAC,
+			      OP_ALG_AS_INITFINAL,
+			      ICV_CHECK_DISABLE,
+			      DIR_ENC);
+		SEQFIFOSTORE(p, MSG, 0, 0, VLF);
+
+		if (rta_sec_era > RTA_SEC_ERA_2) {
+			MOVE(p, AB2, 0, OFIFO, 0, MATH1, 0);
+		} else {
+			SET_LABEL(p, local_offset);
+
+			/* Shut off automatic Info FIFO entries */
+			LOAD(p, 0, DCTRL, LDOFF_DISABLE_AUTO_NFIFO, 0, IMMED);
+
+			/* Placeholder for MOVE command with length from M1
+			 * register
+			 */
+			MOVE(p, IFIFOAB2, 0, OFIFO, 0, 0, IMMED);
+
+			/* Enable automatic Info FIFO entries */
+			LOAD(p, 0, DCTRL, LDOFF_ENABLE_AUTO_NFIFO, 0, IMMED);
+		}
+		SEQFIFOLOAD(p, MSGINSNOOP, 0, VLF | LAST1 | LAST2 | FLUSH1);
+		SEQSTORE(p, CONTEXT1, 0, 4, 0);
+
+		break;
+
+	case PDCP_AUTH_TYPE_ZUC:
+		if (rta_sec_era < RTA_SEC_ERA_5) {
+			pr_err("Invalid era for selected algorithm\n");
+			return -ENOTSUP;
+		}
+		iv[0] = 0xFFFFFFFF;
+		iv[1] = swap ? swab32(0xFC000000) : 0xFC000000;
+		iv[2] = 0x00000000; /* unused */
+
+		KEY(p, KEY2, authdata->key_enc_flags, authdata->key,
+		    authdata->keylen, INLINE_KEY(authdata));
+		LOAD(p, (uintptr_t)&iv, CONTEXT2, 0, 12, IMMED | COPY);
+		ALG_OPERATION(p, OP_ALG_ALGSEL_ZUCA,
+			      OP_ALG_AAI_F9,
+			      OP_ALG_AS_INITFINAL,
+			      ICV_CHECK_DISABLE,
+			      DIR_ENC);
+		SEQFIFOSTORE(p, MSG, 0, 0, VLF);
+		MOVE(p, AB1, 0, OFIFO, 0, MATH1, 0);
+		SEQFIFOLOAD(p, MSGINSNOOP, 0, VLF | LAST1 | LAST2 | FLUSH1);
+		SEQSTORE(p, CONTEXT2, 0, 4, 0);
+
+		break;
+
+	default:
+		pr_err("%s: Invalid integrity algorithm selected: %d\n",
+		       "cnstr_shdsc_pdcp_short_mac", authdata->algtype);
+		return -EINVAL;
+	}
+
+
+	if (rta_sec_era < RTA_SEC_ERA_3) {
+		PATCH_MOVE(p, move_cmd_read_descbuf, local_offset);
+		PATCH_MOVE(p, move_cmd_write_descbuf, local_offset);
+	}
+
+	return PROGRAM_FINALIZE(p);
+}
+
+#endif /* __DESC_PDCP_H__ */
-- 
2.17.1

^ permalink raw reply	[flat|nested] 41+ messages in thread

* [dpdk-dev] [PATCH v5 3/3] crypto/dpaa2_sec: support pdcp offload
  2018-10-16 10:38       ` [dpdk-dev] [PATCH v5 0/3] security: support for pdcp Akhil Goyal
  2018-10-16 10:39         ` [dpdk-dev] [PATCH v5 1/3] security: support pdcp protocol Akhil Goyal
  2018-10-16 10:39         ` [dpdk-dev] [PATCH v5 2/3] crypto/dpaa2_sec: add sample pdcp descriptor apis Akhil Goyal
@ 2018-10-16 10:39         ` Akhil Goyal
  2018-10-16 14:35         ` [dpdk-dev] [PATCH v5 0/3] security: support for pdcp Akhil Goyal
  2018-10-22  7:12         ` [dpdk-dev] [PATCH v6 " Hemant Agrawal
  4 siblings, 0 replies; 41+ messages in thread
From: Akhil Goyal @ 2018-10-16 10:39 UTC (permalink / raw)
  To: dev
  Cc: pablo.de.lara.guarch, radu.nicolau, jerin.jacob,
	narayanaprasad.athreya, Shally.Verma, Anoob.Joseph,
	Vidya.Velumuri, Hemant Agrawal, Akhil Goyal

From: Akhil Goyal <akhil.goyal@nxp.com>

PDCP session configuration for lookaside protocol offload
and data path is added.

Signed-off-by: Hemant Agrawal <hemant.agrawal@nxp.com>
Signed-off-by: Akhil Goyal <akhil.goyal@nxp.com>
---
 drivers/crypto/dpaa2_sec/dpaa2_sec_dpseci.c | 257 ++++++++++++++++++++
 drivers/crypto/dpaa2_sec/dpaa2_sec_priv.h   | 208 +++++++++++++++-
 2 files changed, 457 insertions(+), 8 deletions(-)

diff --git a/drivers/crypto/dpaa2_sec/dpaa2_sec_dpseci.c b/drivers/crypto/dpaa2_sec/dpaa2_sec_dpseci.c
index 0336d5f4b..fe769a932 100644
--- a/drivers/crypto/dpaa2_sec/dpaa2_sec_dpseci.c
+++ b/drivers/crypto/dpaa2_sec/dpaa2_sec_dpseci.c
@@ -35,6 +35,7 @@ typedef uint64_t	dma_addr_t;
 
 /* RTA header files */
 #include <hw/desc/ipsec.h>
+#include <hw/desc/pdcp.h>
 #include <hw/desc/algo.h>
 
 /* Minimum job descriptor consists of a oneword job descriptor HEADER and
@@ -74,6 +75,9 @@ build_proto_compound_fd(dpaa2_sec_session *sess,
 	struct rte_mbuf *dst_mbuf = sym_op->m_dst;
 	int retval;
 
+	if (!dst_mbuf)
+		dst_mbuf = src_mbuf;
+
 	/* Save the shared descriptor */
 	flc = &priv->flc_desc[0].flc;
 
@@ -118,6 +122,15 @@ build_proto_compound_fd(dpaa2_sec_session *sess,
 	DPAA2_SET_FD_LEN(fd, ip_fle->length);
 	DPAA2_SET_FLE_FIN(ip_fle);
 
+#ifdef ENABLE_HFN_OVERRIDE
+	if (sess->ctxt_type == DPAA2_SEC_PDCP && sess->pdcp.hfn_ovd) {
+		/*enable HFN override override */
+		DPAA2_SET_FLE_INTERNAL_JD(ip_fle, sess->pdcp.hfn_ovd);
+		DPAA2_SET_FLE_INTERNAL_JD(op_fle, sess->pdcp.hfn_ovd);
+		DPAA2_SET_FD_INTERNAL_JD(fd, sess->pdcp.hfn_ovd);
+	}
+#endif
+
 	return 0;
 
 }
@@ -1188,6 +1201,9 @@ build_sec_fd(struct rte_crypto_op *op,
 		case DPAA2_SEC_IPSEC:
 			ret = build_proto_fd(sess, op, fd, bpid);
 			break;
+		case DPAA2_SEC_PDCP:
+			ret = build_proto_compound_fd(sess, op, fd, bpid);
+			break;
 		case DPAA2_SEC_HASH_CIPHER:
 		default:
 			DPAA2_SEC_ERR("error: Unsupported session");
@@ -2551,6 +2567,243 @@ dpaa2_sec_set_ipsec_session(struct rte_cryptodev *dev,
 	return ret;
 }
 
+static int
+dpaa2_sec_set_pdcp_session(struct rte_cryptodev *dev,
+			   struct rte_security_session_conf *conf,
+			   void *sess)
+{
+	struct rte_security_pdcp_xform *pdcp_xform = &conf->pdcp;
+	struct rte_crypto_sym_xform *xform = conf->crypto_xform;
+	struct rte_crypto_auth_xform *auth_xform = NULL;
+	struct rte_crypto_cipher_xform *cipher_xform;
+	dpaa2_sec_session *session = (dpaa2_sec_session *)sess;
+	struct ctxt_priv *priv;
+	struct dpaa2_sec_dev_private *dev_priv = dev->data->dev_private;
+	struct alginfo authdata, cipherdata;
+	int bufsize = -1;
+	struct sec_flow_context *flc;
+#if RTE_BYTE_ORDER == RTE_BIG_ENDIAN
+	int swap = true;
+#else
+	int swap = false;
+#endif
+
+	PMD_INIT_FUNC_TRACE();
+
+	memset(session, 0, sizeof(dpaa2_sec_session));
+
+	priv = (struct ctxt_priv *)rte_zmalloc(NULL,
+				sizeof(struct ctxt_priv) +
+				sizeof(struct sec_flc_desc),
+				RTE_CACHE_LINE_SIZE);
+
+	if (priv == NULL) {
+		DPAA2_SEC_ERR("No memory for priv CTXT");
+		return -ENOMEM;
+	}
+
+	priv->fle_pool = dev_priv->fle_pool;
+	flc = &priv->flc_desc[0].flc;
+
+	/* find xfrm types */
+	if (xform->type == RTE_CRYPTO_SYM_XFORM_CIPHER && xform->next == NULL) {
+		cipher_xform = &xform->cipher;
+	} else if (xform->type == RTE_CRYPTO_SYM_XFORM_CIPHER &&
+		   xform->next->type == RTE_CRYPTO_SYM_XFORM_AUTH) {
+		session->ext_params.aead_ctxt.auth_cipher_text = true;
+		cipher_xform = &xform->cipher;
+		auth_xform = &xform->next->auth;
+	} else if (xform->type == RTE_CRYPTO_SYM_XFORM_AUTH &&
+		   xform->next->type == RTE_CRYPTO_SYM_XFORM_CIPHER) {
+		session->ext_params.aead_ctxt.auth_cipher_text = false;
+		cipher_xform = &xform->next->cipher;
+		auth_xform = &xform->auth;
+	} else {
+		DPAA2_SEC_ERR("Invalid crypto type");
+		return -EINVAL;
+	}
+
+	session->ctxt_type = DPAA2_SEC_PDCP;
+	if (cipher_xform) {
+		session->cipher_key.data = rte_zmalloc(NULL,
+					       cipher_xform->key.length,
+					       RTE_CACHE_LINE_SIZE);
+		if (session->cipher_key.data == NULL &&
+				cipher_xform->key.length > 0) {
+			DPAA2_SEC_ERR("No Memory for cipher key");
+			rte_free(priv);
+			return -ENOMEM;
+		}
+		session->cipher_key.length = cipher_xform->key.length;
+		memcpy(session->cipher_key.data, cipher_xform->key.data,
+			cipher_xform->key.length);
+		session->dir = (cipher_xform->op == RTE_CRYPTO_CIPHER_OP_ENCRYPT) ?
+					DIR_ENC : DIR_DEC;
+		session->cipher_alg = cipher_xform->algo;
+	} else {
+		session->cipher_key.data = NULL;
+		session->cipher_key.length = 0;
+		session->cipher_alg = RTE_CRYPTO_CIPHER_NULL;
+		session->dir = DIR_ENC;
+	}
+
+	session->pdcp.domain = pdcp_xform->domain;
+	session->pdcp.bearer = pdcp_xform->bearer;
+	session->pdcp.pkt_dir = pdcp_xform->pkt_dir;
+	session->pdcp.sn_size = pdcp_xform->sn_size;
+#ifdef ENABLE_HFN_OVERRIDE
+	session->pdcp.hfn_ovd = pdcp_xform->hfn_ovd;
+#endif
+	session->pdcp.hfn = pdcp_xform->hfn;
+	session->pdcp.hfn_threshold = pdcp_xform->hfn_threshold;
+
+	cipherdata.key = (size_t)session->cipher_key.data;
+	cipherdata.keylen = session->cipher_key.length;
+	cipherdata.key_enc_flags = 0;
+	cipherdata.key_type = RTA_DATA_IMM;
+
+	switch (session->cipher_alg) {
+	case RTE_CRYPTO_CIPHER_SNOW3G_UEA2:
+		cipherdata.algtype = PDCP_CIPHER_TYPE_SNOW;
+		break;
+	case RTE_CRYPTO_CIPHER_ZUC_EEA3:
+		cipherdata.algtype = PDCP_CIPHER_TYPE_ZUC;
+		break;
+	case RTE_CRYPTO_CIPHER_AES_CTR:
+		cipherdata.algtype = PDCP_CIPHER_TYPE_AES;
+		break;
+	case RTE_CRYPTO_CIPHER_NULL:
+		cipherdata.algtype = PDCP_CIPHER_TYPE_NULL;
+		break;
+	default:
+		DPAA2_SEC_ERR("Crypto: Undefined Cipher specified %u",
+			      session->cipher_alg);
+		goto out;
+	}
+
+	/* Auth is only applicable for control mode operation. */
+	if (pdcp_xform->domain == RTE_SECURITY_PDCP_MODE_CONTROL) {
+		if (pdcp_xform->sn_size != RTE_SECURITY_PDCP_SN_SIZE_5) {
+			DPAA2_SEC_ERR(
+				"PDCP Seq Num size should be 5 bits for cmode");
+			goto out;
+		}
+		if (auth_xform) {
+			session->auth_key.data = rte_zmalloc(NULL,
+							auth_xform->key.length,
+							RTE_CACHE_LINE_SIZE);
+			if (session->auth_key.data == NULL &&
+					auth_xform->key.length > 0) {
+				DPAA2_SEC_ERR("No Memory for auth key");
+				rte_free(session->cipher_key.data);
+				rte_free(priv);
+				return -ENOMEM;
+			}
+			session->auth_key.length = auth_xform->key.length;
+			memcpy(session->auth_key.data, auth_xform->key.data,
+					auth_xform->key.length);
+			session->auth_alg = auth_xform->algo;
+		} else {
+			session->auth_key.data = NULL;
+			session->auth_key.length = 0;
+			session->auth_alg = RTE_CRYPTO_AUTH_NULL;
+		}
+		authdata.key = (size_t)session->auth_key.data;
+		authdata.keylen = session->auth_key.length;
+		authdata.key_enc_flags = 0;
+		authdata.key_type = RTA_DATA_IMM;
+
+		switch (session->auth_alg) {
+		case RTE_CRYPTO_AUTH_SNOW3G_UIA2:
+			authdata.algtype = PDCP_AUTH_TYPE_SNOW;
+			break;
+		case RTE_CRYPTO_AUTH_ZUC_EIA3:
+			authdata.algtype = PDCP_AUTH_TYPE_ZUC;
+			break;
+		case RTE_CRYPTO_AUTH_AES_CMAC:
+			authdata.algtype = PDCP_AUTH_TYPE_AES;
+			break;
+		case RTE_CRYPTO_AUTH_NULL:
+			authdata.algtype = PDCP_AUTH_TYPE_NULL;
+			break;
+		default:
+			DPAA2_SEC_ERR("Crypto: Unsupported auth alg %u",
+				      session->auth_alg);
+			goto out;
+		}
+
+		if (session->dir == DIR_ENC)
+			bufsize = cnstr_shdsc_pdcp_c_plane_encap(
+					priv->flc_desc[0].desc, 1, swap,
+					pdcp_xform->hfn,
+					pdcp_xform->bearer,
+					pdcp_xform->pkt_dir,
+					pdcp_xform->hfn_threshold,
+					&cipherdata, &authdata,
+					0);
+		else if (session->dir == DIR_DEC)
+			bufsize = cnstr_shdsc_pdcp_c_plane_decap(
+					priv->flc_desc[0].desc, 1, swap,
+					pdcp_xform->hfn,
+					pdcp_xform->bearer,
+					pdcp_xform->pkt_dir,
+					pdcp_xform->hfn_threshold,
+					&cipherdata, &authdata,
+					0);
+	} else {
+		if (session->dir == DIR_ENC)
+			bufsize = cnstr_shdsc_pdcp_u_plane_encap(
+					priv->flc_desc[0].desc, 1, swap,
+					pdcp_xform->sn_size,
+					pdcp_xform->hfn,
+					pdcp_xform->bearer,
+					pdcp_xform->pkt_dir,
+					pdcp_xform->hfn_threshold,
+					&cipherdata, 0);
+		else if (session->dir == DIR_DEC)
+			bufsize = cnstr_shdsc_pdcp_u_plane_decap(
+					priv->flc_desc[0].desc, 1, swap,
+					pdcp_xform->sn_size,
+					pdcp_xform->hfn,
+					pdcp_xform->bearer,
+					pdcp_xform->pkt_dir,
+					pdcp_xform->hfn_threshold,
+					&cipherdata, 0);
+	}
+
+	if (bufsize < 0) {
+		DPAA2_SEC_ERR("Crypto: Invalid buffer length");
+		goto out;
+	}
+
+	/* Enable the stashing control bit */
+	DPAA2_SET_FLC_RSC(flc);
+	flc->word2_rflc_31_0 = lower_32_bits(
+			(size_t)&(((struct dpaa2_sec_qp *)
+			dev->data->queue_pairs[0])->rx_vq) | 0x14);
+	flc->word3_rflc_63_32 = upper_32_bits(
+			(size_t)&(((struct dpaa2_sec_qp *)
+			dev->data->queue_pairs[0])->rx_vq));
+
+	flc->word1_sdl = (uint8_t)bufsize;
+
+	/* Set EWS bit i.e. enable write-safe */
+	DPAA2_SET_FLC_EWS(flc);
+	/* Set BS = 1 i.e reuse input buffers as output buffers */
+	DPAA2_SET_FLC_REUSE_BS(flc);
+	/* Set FF = 10; reuse input buffers if they provide sufficient space */
+	DPAA2_SET_FLC_REUSE_FF(flc);
+
+	session->ctxt = priv;
+
+	return 0;
+out:
+	rte_free(session->auth_key.data);
+	rte_free(session->cipher_key.data);
+	rte_free(priv);
+	return -1;
+}
+
 static int
 dpaa2_sec_security_session_create(void *dev,
 				  struct rte_security_session_conf *conf,
@@ -2573,6 +2826,10 @@ dpaa2_sec_security_session_create(void *dev,
 		break;
 	case RTE_SECURITY_PROTOCOL_MACSEC:
 		return -ENOTSUP;
+	case RTE_SECURITY_PROTOCOL_PDCP:
+		ret = dpaa2_sec_set_pdcp_session(cdev, conf,
+				sess_private_data);
+		break;
 	default:
 		return -EINVAL;
 	}
diff --git a/drivers/crypto/dpaa2_sec/dpaa2_sec_priv.h b/drivers/crypto/dpaa2_sec/dpaa2_sec_priv.h
index bce9633c0..51751103d 100644
--- a/drivers/crypto/dpaa2_sec/dpaa2_sec_priv.h
+++ b/drivers/crypto/dpaa2_sec/dpaa2_sec_priv.h
@@ -137,6 +137,19 @@ struct dpaa2_sec_aead_ctxt {
 	uint8_t auth_cipher_text;       /**< Authenticate/cipher ordering */
 };
 
+/*
+ * The structure is to be filled by user for PDCP Protocol
+ */
+struct dpaa2_pdcp_ctxt {
+	enum rte_security_pdcp_domain domain; /*!< Data/Control mode*/
+	int8_t bearer;	/*!< PDCP bearer ID */
+	int8_t pkt_dir;/*!< PDCP Frame Direction 0:UL 1:DL*/
+	int8_t hfn_ovd;/*!< Overwrite HFN per packet*/
+	uint32_t hfn;	/*!< Hyper Frame Number */
+	uint32_t hfn_threshold;	/*!< HFN Threashold for key renegotiation */
+	uint8_t sn_size;	/*!< Sequence number size, 7/12/15 */
+};
+
 typedef struct dpaa2_sec_session_entry {
 	void *ctxt;
 	uint8_t ctxt_type;
@@ -160,15 +173,20 @@ typedef struct dpaa2_sec_session_entry {
 			} auth_key;
 		};
 	};
-	struct {
-		uint16_t length; /**< IV length in bytes */
-		uint16_t offset; /**< IV offset in bytes */
-	} iv;
-	uint16_t digest_length;
-	uint8_t status;
 	union {
-		struct dpaa2_sec_aead_ctxt aead_ctxt;
-	} ext_params;
+		struct {
+			struct {
+				uint16_t length; /**< IV length in bytes */
+				uint16_t offset; /**< IV offset in bytes */
+			} iv;
+			uint16_t digest_length;
+			uint8_t status;
+			union {
+				struct dpaa2_sec_aead_ctxt aead_ctxt;
+			} ext_params;
+		};
+		struct dpaa2_pdcp_ctxt pdcp;
+	};
 } dpaa2_sec_session;
 
 static const struct rte_cryptodev_capabilities dpaa2_sec_capabilities[] = {
@@ -392,6 +410,162 @@ static const struct rte_cryptodev_capabilities dpaa2_sec_capabilities[] = {
 	RTE_CRYPTODEV_END_OF_CAPABILITIES_LIST()
 };
 
+static const struct rte_cryptodev_capabilities dpaa2_pdcp_capabilities[] = {
+	{	/* SNOW 3G (UIA2) */
+		.op = RTE_CRYPTO_OP_TYPE_SYMMETRIC,
+		{.sym = {
+			.xform_type = RTE_CRYPTO_SYM_XFORM_AUTH,
+			{.auth = {
+				.algo = RTE_CRYPTO_AUTH_SNOW3G_UIA2,
+				.block_size = 16,
+				.key_size = {
+					.min = 16,
+					.max = 16,
+					.increment = 0
+				},
+				.digest_size = {
+					.min = 4,
+					.max = 4,
+					.increment = 0
+				},
+				.iv_size = {
+					.min = 16,
+					.max = 16,
+					.increment = 0
+				}
+			}, }
+		}, }
+	},
+	{	/* SNOW 3G (UEA2) */
+		.op = RTE_CRYPTO_OP_TYPE_SYMMETRIC,
+		{.sym = {
+			.xform_type = RTE_CRYPTO_SYM_XFORM_CIPHER,
+			{.cipher = {
+				.algo = RTE_CRYPTO_CIPHER_SNOW3G_UEA2,
+				.block_size = 16,
+				.key_size = {
+					.min = 16,
+					.max = 16,
+					.increment = 0
+				},
+				.iv_size = {
+					.min = 16,
+					.max = 16,
+					.increment = 0
+				}
+			}, }
+		}, }
+	},
+	{	/* AES CTR */
+		.op = RTE_CRYPTO_OP_TYPE_SYMMETRIC,
+		{.sym = {
+			.xform_type = RTE_CRYPTO_SYM_XFORM_CIPHER,
+			{.cipher = {
+				.algo = RTE_CRYPTO_CIPHER_AES_CTR,
+				.block_size = 16,
+				.key_size = {
+					.min = 16,
+					.max = 32,
+					.increment = 8
+				},
+				.iv_size = {
+					.min = 16,
+					.max = 16,
+					.increment = 0
+				}
+			}, }
+		}, }
+	},
+	{	/* NULL (AUTH) */
+		.op = RTE_CRYPTO_OP_TYPE_SYMMETRIC,
+		{.sym = {
+			.xform_type = RTE_CRYPTO_SYM_XFORM_AUTH,
+			{.auth = {
+				.algo = RTE_CRYPTO_AUTH_NULL,
+				.block_size = 1,
+				.key_size = {
+					.min = 0,
+					.max = 0,
+					.increment = 0
+				},
+				.digest_size = {
+					.min = 0,
+					.max = 0,
+					.increment = 0
+				},
+				.iv_size = { 0 }
+			}, },
+		}, },
+	},
+	{	/* NULL (CIPHER) */
+		.op = RTE_CRYPTO_OP_TYPE_SYMMETRIC,
+		{.sym = {
+			.xform_type = RTE_CRYPTO_SYM_XFORM_CIPHER,
+			{.cipher = {
+				.algo = RTE_CRYPTO_CIPHER_NULL,
+				.block_size = 1,
+				.key_size = {
+					.min = 0,
+					.max = 0,
+					.increment = 0
+				},
+				.iv_size = {
+					.min = 0,
+					.max = 0,
+					.increment = 0
+				}
+			}, },
+		}, }
+	},
+	{	/* ZUC (EEA3) */
+		.op = RTE_CRYPTO_OP_TYPE_SYMMETRIC,
+		{.sym = {
+			.xform_type = RTE_CRYPTO_SYM_XFORM_CIPHER,
+			{.cipher = {
+				.algo = RTE_CRYPTO_CIPHER_ZUC_EEA3,
+				.block_size = 16,
+				.key_size = {
+					.min = 16,
+					.max = 16,
+					.increment = 0
+				},
+				.iv_size = {
+					.min = 16,
+					.max = 16,
+					.increment = 0
+				}
+			}, }
+		}, }
+	},
+	{	/* ZUC (EIA3) */
+		.op = RTE_CRYPTO_OP_TYPE_SYMMETRIC,
+		{.sym = {
+			.xform_type = RTE_CRYPTO_SYM_XFORM_AUTH,
+			{.auth = {
+				.algo = RTE_CRYPTO_AUTH_ZUC_EIA3,
+				.block_size = 16,
+				.key_size = {
+					.min = 16,
+					.max = 16,
+					.increment = 0
+				},
+				.digest_size = {
+					.min = 4,
+					.max = 4,
+					.increment = 0
+				},
+				.iv_size = {
+					.min = 16,
+					.max = 16,
+					.increment = 0
+				}
+			}, }
+		}, }
+	},
+
+	RTE_CRYPTODEV_END_OF_CAPABILITIES_LIST()
+};
+
 static const struct rte_security_capability dpaa2_sec_security_cap[] = {
 	{ /* IPsec Lookaside Protocol offload ESP Transport Egress */
 		.action = RTE_SECURITY_ACTION_TYPE_LOOKASIDE_PROTOCOL,
@@ -415,6 +589,24 @@ static const struct rte_security_capability dpaa2_sec_security_cap[] = {
 		},
 		.crypto_capabilities = dpaa2_sec_capabilities
 	},
+	{ /* PDCP Lookaside Protocol offload Data */
+		.action = RTE_SECURITY_ACTION_TYPE_LOOKASIDE_PROTOCOL,
+		.protocol = RTE_SECURITY_PROTOCOL_PDCP,
+		.pdcp = {
+			.domain = RTE_SECURITY_PDCP_MODE_DATA,
+			.capa_flags = 0
+		},
+		.crypto_capabilities = dpaa2_pdcp_capabilities
+	},
+	{ /* PDCP Lookaside Protocol offload Control */
+		.action = RTE_SECURITY_ACTION_TYPE_LOOKASIDE_PROTOCOL,
+		.protocol = RTE_SECURITY_PROTOCOL_PDCP,
+		.pdcp = {
+			.domain = RTE_SECURITY_PDCP_MODE_CONTROL,
+			.capa_flags = 0
+		},
+		.crypto_capabilities = dpaa2_pdcp_capabilities
+	},
 	{
 		.action = RTE_SECURITY_ACTION_TYPE_NONE
 	}
-- 
2.17.1

^ permalink raw reply	[flat|nested] 41+ messages in thread

* Re: [dpdk-dev] [PATCH v5 1/3] security: support pdcp protocol
  2018-10-16 10:39         ` [dpdk-dev] [PATCH v5 1/3] security: support pdcp protocol Akhil Goyal
@ 2018-10-16 10:49           ` Joseph, Anoob
  2018-10-16 10:57             ` Akhil Goyal
  0 siblings, 1 reply; 41+ messages in thread
From: Joseph, Anoob @ 2018-10-16 10:49 UTC (permalink / raw)
  To: Akhil Goyal, dev
  Cc: pablo.de.lara.guarch, radu.nicolau, Jacob,  Jerin, Athreya,
	Narayana Prasad, Verma, Shally, Velumuri, Vidya, Hemant Agrawal

Hi Akhil,

The HFN threshold comment is still not right I guess,

> +        uint32_t hfn;
> +        /**< HFN Threshold for key renegotiation */
> +        uint32_t hfn_threshold;
The above code snippet is there in the rte_security.rst file also. You may need to fix that also.

And the following also need to be fixed,
> + * @PDCP_SN_SIZE_18: 18bit sequence number  */ enum
> +rte_security_pdcp_sn_size {
....
> +       RTE_SECURITY_PDCP_SN_SIZE_18 = 18 };

With the above changes,
Acked-by: Anoob Joseph <anoob.joseph@caviumnetworks.com>

Thanks,
Anoob
> -----Original Message-----
> From: Akhil Goyal <akhil.goyal@nxp.com>
> Sent: 16 October 2018 16:09
> To: dev@dpdk.org
> Cc: pablo.de.lara.guarch@intel.com; radu.nicolau@intel.com; Jacob, Jerin
> <Jerin.JacobKollanukkaran@cavium.com>; Athreya, Narayana Prasad
> <NarayanaPrasad.Athreya@cavium.com>; Verma, Shally
> <Shally.Verma@cavium.com>; Joseph, Anoob <Anoob.Joseph@cavium.com>;
> Velumuri, Vidya <Vidya.Velumuri@cavium.com>; Hemant Agrawal
> <hemant.agrawal@nxp.com>; Akhil Goyal <akhil.goyal@nxp.com>
> Subject: [PATCH v5 1/3] security: support pdcp protocol
> 
> External Email
> 
> From: Akhil Goyal <akhil.goyal@nxp.com>
> 
> Packet Data Convergence Protocol (PDCP) is added in rte_security for 3GPP TS
> 36.323 for LTE.
> 
> The patchset provide the structure definitions for configuring the PDCP sessions
> and relevant documentation is added.
> 
> Signed-off-by: Hemant Agrawal <hemant.agrawal@nxp.com>
> Signed-off-by: Akhil Goyal <akhil.goyal@nxp.com>
> ---
>  doc/guides/prog_guide/rte_security.rst | 107 +++++++++++++++++++++++--
>  lib/librte_security/rte_security.c     |   4 +
>  lib/librte_security/rte_security.h     |  92 +++++++++++++++++++++
>  3 files changed, 196 insertions(+), 7 deletions(-)
> 
> diff --git a/doc/guides/prog_guide/rte_security.rst
> b/doc/guides/prog_guide/rte_security.rst
> index 0812abe77..e43f1554c 100644
> --- a/doc/guides/prog_guide/rte_security.rst
> +++ b/doc/guides/prog_guide/rte_security.rst
> @@ -10,8 +10,8 @@ The security library provides a framework for management
> and provisioning  of security protocol operations offloaded to hardware based
> devices. The  library defines generic APIs to create and free security sessions
> which can  support full protocol offload as well as inline crypto operation with -
> NIC or crypto devices. The framework currently only supports the IPSec protocol
> -and associated operations, other protocols will be added in future.
> +NIC or crypto devices. The framework currently only supports the IPsec
> +and PDCP protocol and associated operations, other protocols will be added in
> future.
> 
>  Design Principles
>  -----------------
> @@ -253,6 +253,49 @@ for any protocol header addition.
>          +--------|--------+
>                   V
> 
> +PDCP Flow Diagram
> +~~~~~~~~~~~~~~~~~
> +
> +Based on 3GPP TS 36.323 Evolved Universal Terrestrial Radio Access
> +(E-UTRA); Packet Data Convergence Protocol (PDCP) specification
> +
> +.. code-block:: c
> +
> +        Transmitting PDCP Entity          Receiving PDCP Entity
> +                  |                                   ^
> +                  |                       +-----------|-----------+
> +                  V                       | In order delivery and |
> +        +---------|----------+            | Duplicate detection   |
> +        | Sequence Numbering |            |  (Data Plane only)    |
> +        +---------|----------+            +-----------|-----------+
> +                  |                                   |
> +        +---------|----------+            +-----------|----------+
> +        | Header Compression*|            | Header Decompression*|
> +        | (Data-Plane only)  |            |   (Data Plane only)  |
> +        +---------|----------+            +-----------|----------+
> +                  |                                   |
> +        +---------|-----------+           +-----------|----------+
> +        | Integrity Protection|           |Integrity Verification|
> +        | (Control Plane only)|           | (Control Plane only) |
> +        +---------|-----------+           +-----------|----------+
> +        +---------|-----------+            +----------|----------+
> +        |     Ciphering       |            |     Deciphering     |
> +        +---------|-----------+            +----------|----------+
> +        +---------|-----------+            +----------|----------+
> +        |   Add PDCP header   |            | Remove PDCP Header  |
> +        +---------|-----------+            +----------|----------+
> +                  |                                   |
> +                  +----------------->>----------------+
> +
> +
> +.. note::
> +
> +    * Header Compression and decompression are not supported currently.
> +
> +Just like IPsec, in case of PDCP also header addition/deletion, cipher/
> +de-cipher, integrity protection/verification is done based on the
> +action type chosen.
> +
>  Device Features and Capabilities
>  ---------------------------------
> 
> @@ -271,7 +314,7 @@ structure in the *DPDK API Reference*.
> 
>  Each driver (crypto or ethernet) defines its own private array of capabilities  for
> the operations it supports. Below is an example of the capabilities for a -PMD
> which supports the IPSec protocol.
> +PMD which supports the IPsec and PDCP protocol.
> 
>  .. code-block:: c
> 
> @@ -298,6 +341,24 @@ PMD which supports the IPSec protocol.
>                  },
>                  .crypto_capabilities = pmd_capabilities
>          },
> +        { /* PDCP Lookaside Protocol offload Data Plane */
> +                .action = RTE_SECURITY_ACTION_TYPE_LOOKASIDE_PROTOCOL,
> +                .protocol = RTE_SECURITY_PROTOCOL_PDCP,
> +                .pdcp = {
> +                        .domain = RTE_SECURITY_PDCP_MODE_DATA,
> +                        .capa_flags = 0
> +                },
> +                .crypto_capabilities = pmd_capabilities
> +        },
> +        { /* PDCP Lookaside Protocol offload Control */
> +                .action = RTE_SECURITY_ACTION_TYPE_LOOKASIDE_PROTOCOL,
> +                .protocol = RTE_SECURITY_PROTOCOL_PDCP,
> +                .pdcp = {
> +                        .domain = RTE_SECURITY_PDCP_MODE_CONTROL,
> +                        .capa_flags = 0
> +                },
> +                .crypto_capabilities = pmd_capabilities
> +        },
>          {
>                  .action = RTE_SECURITY_ACTION_TYPE_NONE
>          }
> @@ -429,6 +490,7 @@ Security Session configuration structure is defined as
> ``rte_security_session_co
>          union {
>                  struct rte_security_ipsec_xform ipsec;
>                  struct rte_security_macsec_xform macsec;
> +                struct rte_security_pdcp_xform pdcp;
>          };
>          /**< Configuration parameters for security session */
>          struct rte_crypto_sym_xform *crypto_xform; @@ -463,15 +525,17 @@
> The ``rte_security_session_protocol`` is defined as  .. code-block:: c
> 
>      enum rte_security_session_protocol {
> -        RTE_SECURITY_PROTOCOL_IPSEC,
> +        RTE_SECURITY_PROTOCOL_IPSEC = 1,
>          /**< IPsec Protocol */
>          RTE_SECURITY_PROTOCOL_MACSEC,
>          /**< MACSec Protocol */
> +        RTE_SECURITY_PROTOCOL_PDCP,
> +        /**< PDCP Protocol */
>      };
> 
> -Currently the library defines configuration parameters for IPSec only. For other
> -protocols like MACSec, structures and enums are defined as place holders
> which -will be updated in the future.
> +Currently the library defines configuration parameters for IPsec and PDCP only.
> +For other protocols like MACSec, structures and enums are defined as
> +place holders which will be updated in the future.
> 
>  IPsec related configuration parameters are defined in
> ``rte_security_ipsec_xform``
> 
> @@ -494,6 +558,35 @@ IPsec related configuration parameters are defined in
> ``rte_security_ipsec_xform
>          /**< Tunnel parameters, NULL for transport mode */
>      };
> 
> +PDCP related configuration parameters are defined in
> +``rte_security_pdcp_xform``
> +
> +.. code-block:: c
> +
> +    struct rte_security_pdcp_xform {
> +        int8_t bearer; /**< PDCP bearer ID */
> +        /**< Enable in order delivery, this field shall be set only if
> +         * driver/HW is capable. See RTE_SECURITY_PDCP_ORDERING_CAP.
> +         */
> +        uint8_t en_ordering;
> +        /**< Notify driver/HW to detect and remove duplicate packets.
> +         * This field should be set only when driver/hw is capable.
> +         * See RTE_SECURITY_PDCP_DUP_DETECT_CAP.
> +         */
> +        uint8_t remove_duplicates;
> +        /**< PDCP mode of operation: Control or data */
> +        enum rte_security_pdcp_domain domain;
> +        /**< PDCP Frame Direction 0:UL 1:DL */
> +        enum rte_security_pdcp_direction pkt_dir;
> +        /**< Sequence number size, 5/7/12/15/18 */
> +        enum rte_security_pdcp_sn_size sn_size;
> +        /**< Starting Hyper Frame Number to be used together with the SN
> +         * from the PDCP frames
> +         */
> +        uint32_t hfn;
> +        /**< HFN Threshold for key renegotiation */
> +        uint32_t hfn_threshold;
> +    };
> +
> 
>  Security API
>  ~~~~~~~~~~~~
> diff --git a/lib/librte_security/rte_security.c b/lib/librte_security/rte_security.c
> index 1954960a5..c6355de95 100644
> --- a/lib/librte_security/rte_security.c
> +++ b/lib/librte_security/rte_security.c
> @@ -131,6 +131,10 @@ rte_security_capability_get(struct rte_security_ctx
> *instance,
>                                         capability->ipsec.direction ==
>                                                         idx->ipsec.direction)
>                                         return capability;
> +                       } else if (idx->protocol == RTE_SECURITY_PROTOCOL_PDCP) {
> +                               if (capability->pdcp.domain ==
> +                                                       idx->pdcp.domain)
> +                                       return capability;
>                         }
>                 }
>         }
> diff --git a/lib/librte_security/rte_security.h b/lib/librte_security/rte_security.h
> index b0d1b97ee..de49017e1 100644
> --- a/lib/librte_security/rte_security.h
> +++ b/lib/librte_security/rte_security.h
> @@ -206,6 +206,66 @@ struct rte_security_macsec_xform {
>         int dummy;
>  };
> 
> +/**
> + * PDCP Mode of session
> + */
> +enum rte_security_pdcp_domain {
> +       RTE_SECURITY_PDCP_MODE_CONTROL, /**< PDCP control plane */
> +       RTE_SECURITY_PDCP_MODE_DATA,    /**< PDCP data plane */
> +};
> +
> +/** PDCP Frame direction */
> +enum rte_security_pdcp_direction {
> +       RTE_SECURITY_PDCP_UPLINK,       /**< Uplink */
> +       RTE_SECURITY_PDCP_DOWNLINK,     /**< Downlink */
> +};
> +
> +/**
> + * PDCP Sequence Number Size selectors
> + * @PDCP_SN_SIZE_5: 5bit sequence number
> + * @PDCP_SN_SIZE_7: 7bit sequence number
> + * @PDCP_SN_SIZE_12: 12bit sequence number
> + * @PDCP_SN_SIZE_15: 15bit sequence number
> + * @PDCP_SN_SIZE_18: 18bit sequence number  */ enum
> +rte_security_pdcp_sn_size {
> +       RTE_SECURITY_PDCP_SN_SIZE_5 = 5,
> +       RTE_SECURITY_PDCP_SN_SIZE_7 = 7,
> +       RTE_SECURITY_PDCP_SN_SIZE_12 = 12,
> +       RTE_SECURITY_PDCP_SN_SIZE_15 = 15,
> +       RTE_SECURITY_PDCP_SN_SIZE_18 = 18 };
> +
> +/**
> + * PDCP security association configuration data.
> + *
> + * This structure contains data required to create a PDCP security session.
> + */
> +struct rte_security_pdcp_xform {
> +       int8_t bearer;  /**< PDCP bearer ID */
> +       /**< Enable in order delivery, this field shall be set only if
> +        * driver/HW is capable. See RTE_SECURITY_PDCP_ORDERING_CAP.
> +        */
> +       uint8_t en_ordering;
> +       /**< Notify driver/HW to detect and remove duplicate packets.
> +        * This field should be set only when driver/hw is capable.
> +        * See RTE_SECURITY_PDCP_DUP_DETECT_CAP.
> +        */
> +       uint8_t remove_duplicates;
> +       /**< PDCP mode of operation: Control or data */
> +       enum rte_security_pdcp_domain domain;
> +       /**< PDCP Frame Direction 0:UL 1:DL */
> +       enum rte_security_pdcp_direction pkt_dir;
> +       /**< Sequence number size, 5/7/12/15/18 */
> +       enum rte_security_pdcp_sn_size sn_size;
> +       /**< Starting Hyper Frame Number to be used together with the SN
> +        * from the PDCP frames
> +        */
> +       uint32_t hfn;
> +       /**< HFN Threshold for key renegotiation */
> +       uint32_t hfn_threshold;
> +};
> +
>  /**
>   * Security session action type.
>   */
> @@ -232,6 +292,8 @@ enum rte_security_session_protocol {
>         /**< IPsec Protocol */
>         RTE_SECURITY_PROTOCOL_MACSEC,
>         /**< MACSec Protocol */
> +       RTE_SECURITY_PROTOCOL_PDCP,
> +       /**< PDCP Protocol */
>  };
> 
>  /**
> @@ -246,6 +308,7 @@ struct rte_security_session_conf {
>         union {
>                 struct rte_security_ipsec_xform ipsec;
>                 struct rte_security_macsec_xform macsec;
> +               struct rte_security_pdcp_xform pdcp;
>         };
>         /**< Configuration parameters for security session */
>         struct rte_crypto_sym_xform *crypto_xform; @@ -413,6 +476,10 @@
> struct rte_security_ipsec_stats {
> 
>  };
> 
> +struct rte_security_pdcp_stats {
> +       uint64_t reserved;
> +};
> +
>  struct rte_security_stats {
>         enum rte_security_session_protocol protocol;
>         /**< Security protocol to be configured */ @@ -421,6 +488,7 @@ struct
> rte_security_stats {
>         union {
>                 struct rte_security_macsec_stats macsec;
>                 struct rte_security_ipsec_stats ipsec;
> +               struct rte_security_pdcp_stats pdcp;
>         };
>  };
> 
> @@ -465,6 +533,13 @@ struct rte_security_capability {
>                         int dummy;
>                 } macsec;
>                 /**< MACsec capability */
> +               struct {
> +                       enum rte_security_pdcp_domain domain;
> +                       /** < PDCP mode of operation: Control or data */
> +                       uint32_t capa_flags;
> +                       /** < Capabilitity flags, see RTE_SECURITY_PDCP_* */
> +               } pdcp;
> +               /**< PDCP capability */
>         };
> 
>         const struct rte_cryptodev_capabilities *crypto_capabilities; @@ -474,6
> +549,19 @@ struct rte_security_capability {
>         /**< Device offload flags */
>  };
> 
> +/**< Underlying Hardware/driver which support PDCP may or may not
> +support
> + * packet ordering. Set RTE_SECURITY_PDCP_ORDERING_CAP if it support.
> + * If it is not set, driver/HW assumes packets received are in order
> + * and it will be application's responsibility to maintain ordering.
> + */
> +#define RTE_SECURITY_PDCP_ORDERING_CAP         0x00000001
> +
> +/**< Underlying Hardware/driver which support PDCP may or may not
> +detect
> + * duplicate packet. Set RTE_SECURITY_PDCP_DUP_DETECT_CAP if it support.
> + * If it is not set, driver/HW assumes there is no duplicate packet received.
> + */
> +#define RTE_SECURITY_PDCP_DUP_DETECT_CAP       0x00000002
> +
>  #define RTE_SECURITY_TX_OLOAD_NEED_MDATA       0x00000001
>  /**< HW needs metadata update, see rte_security_set_pkt_metadata().
>   */
> @@ -506,6 +594,10 @@ struct rte_security_capability_idx {
>                         enum rte_security_ipsec_sa_mode mode;
>                         enum rte_security_ipsec_sa_direction direction;
>                 } ipsec;
> +               struct {
> +                       enum rte_security_pdcp_domain domain;
> +                       uint32_t capa_flags;
> +               } pdcp;
>         };
>  };
> 
> --
> 2.17.1

^ permalink raw reply	[flat|nested] 41+ messages in thread

* Re: [dpdk-dev] [PATCH v5 1/3] security: support pdcp protocol
  2018-10-16 10:49           ` Joseph, Anoob
@ 2018-10-16 10:57             ` Akhil Goyal
  2018-10-16 11:15               ` Joseph, Anoob
  0 siblings, 1 reply; 41+ messages in thread
From: Akhil Goyal @ 2018-10-16 10:57 UTC (permalink / raw)
  To: Joseph, Anoob, dev
  Cc: pablo.de.lara.guarch, radu.nicolau, Jacob, Jerin, Athreya,
	Narayana Prasad, Verma, Shally, Velumuri, Vidya, Hemant Agrawal

Hi Anoob,

On 10/16/2018 4:19 PM, Joseph, Anoob wrote:
> Hi Akhil,
>
> The HFN threshold comment is still not right I guess,
>
>> +        uint32_t hfn;
>> +        /**< HFN Threshold for key renegotiation */
>> +        uint32_t hfn_threshold;
> The above code snippet is there in the rte_security.rst file also. You may need to fix that also.
>
> And the following also need to be fixed,

I think there is some issue in your mail client.
please check patchworks. Everything looks good to me
http://patches.dpdk.org/patch/46886/

>> + * @PDCP_SN_SIZE_18: 18bit sequence number  */ enum
>> +rte_security_pdcp_sn_size {
> ....
>> +       RTE_SECURITY_PDCP_SN_SIZE_18 = 18 };
> With the above changes,
> Acked-by: Anoob Joseph <anoob.joseph@caviumnetworks.com>
Thanks.
>
> Thanks,
> Anoob
>> -----Original Message-----
>> From: Akhil Goyal <akhil.goyal@nxp.com>
>> Sent: 16 October 2018 16:09
>> To: dev@dpdk.org
>> Cc: pablo.de.lara.guarch@intel.com; radu.nicolau@intel.com; Jacob, Jerin
>> <Jerin.JacobKollanukkaran@cavium.com>; Athreya, Narayana Prasad
>> <NarayanaPrasad.Athreya@cavium.com>; Verma, Shally
>> <Shally.Verma@cavium.com>; Joseph, Anoob <Anoob.Joseph@cavium.com>;
>> Velumuri, Vidya <Vidya.Velumuri@cavium.com>; Hemant Agrawal
>> <hemant.agrawal@nxp.com>; Akhil Goyal <akhil.goyal@nxp.com>
>> Subject: [PATCH v5 1/3] security: support pdcp protocol
>>
>> External Email
>>
>> From: Akhil Goyal <akhil.goyal@nxp.com>
>>
>> Packet Data Convergence Protocol (PDCP) is added in rte_security for 3GPP TS
>> 36.323 for LTE.
>>
>> The patchset provide the structure definitions for configuring the PDCP sessions
>> and relevant documentation is added.
>>
>> Signed-off-by: Hemant Agrawal <hemant.agrawal@nxp.com>
>> Signed-off-by: Akhil Goyal <akhil.goyal@nxp.com>
>> ---
>>   doc/guides/prog_guide/rte_security.rst | 107 +++++++++++++++++++++++--
>>   lib/librte_security/rte_security.c     |   4 +
>>   lib/librte_security/rte_security.h     |  92 +++++++++++++++++++++
>>   3 files changed, 196 insertions(+), 7 deletions(-)
>>
>> diff --git a/doc/guides/prog_guide/rte_security.rst
>> b/doc/guides/prog_guide/rte_security.rst
>> index 0812abe77..e43f1554c 100644
>> --- a/doc/guides/prog_guide/rte_security.rst
>> +++ b/doc/guides/prog_guide/rte_security.rst
>> @@ -10,8 +10,8 @@ The security library provides a framework for management
>> and provisioning  of security protocol operations offloaded to hardware based
>> devices. The  library defines generic APIs to create and free security sessions
>> which can  support full protocol offload as well as inline crypto operation with -
>> NIC or crypto devices. The framework currently only supports the IPSec protocol
>> -and associated operations, other protocols will be added in future.
>> +NIC or crypto devices. The framework currently only supports the IPsec
>> +and PDCP protocol and associated operations, other protocols will be added in
>> future.
>>
>>   Design Principles
>>   -----------------
>> @@ -253,6 +253,49 @@ for any protocol header addition.
>>           +--------|--------+
>>                    V
>>
>> +PDCP Flow Diagram
>> +~~~~~~~~~~~~~~~~~
>> +
>> +Based on 3GPP TS 36.323 Evolved Universal Terrestrial Radio Access
>> +(E-UTRA); Packet Data Convergence Protocol (PDCP) specification
>> +
>> +.. code-block:: c
>> +
>> +        Transmitting PDCP Entity          Receiving PDCP Entity
>> +                  |                                   ^
>> +                  |                       +-----------|-----------+
>> +                  V                       | In order delivery and |
>> +        +---------|----------+            | Duplicate detection   |
>> +        | Sequence Numbering |            |  (Data Plane only)    |
>> +        +---------|----------+            +-----------|-----------+
>> +                  |                                   |
>> +        +---------|----------+            +-----------|----------+
>> +        | Header Compression*|            | Header Decompression*|
>> +        | (Data-Plane only)  |            |   (Data Plane only)  |
>> +        +---------|----------+            +-----------|----------+
>> +                  |                                   |
>> +        +---------|-----------+           +-----------|----------+
>> +        | Integrity Protection|           |Integrity Verification|
>> +        | (Control Plane only)|           | (Control Plane only) |
>> +        +---------|-----------+           +-----------|----------+
>> +        +---------|-----------+            +----------|----------+
>> +        |     Ciphering       |            |     Deciphering     |
>> +        +---------|-----------+            +----------|----------+
>> +        +---------|-----------+            +----------|----------+
>> +        |   Add PDCP header   |            | Remove PDCP Header  |
>> +        +---------|-----------+            +----------|----------+
>> +                  |                                   |
>> +                  +----------------->>----------------+
>> +
>> +
>> +.. note::
>> +
>> +    * Header Compression and decompression are not supported currently.
>> +
>> +Just like IPsec, in case of PDCP also header addition/deletion, cipher/
>> +de-cipher, integrity protection/verification is done based on the
>> +action type chosen.
>> +
>>   Device Features and Capabilities
>>   ---------------------------------
>>
>> @@ -271,7 +314,7 @@ structure in the *DPDK API Reference*.
>>
>>   Each driver (crypto or ethernet) defines its own private array of capabilities  for
>> the operations it supports. Below is an example of the capabilities for a -PMD
>> which supports the IPSec protocol.
>> +PMD which supports the IPsec and PDCP protocol.
>>
>>   .. code-block:: c
>>
>> @@ -298,6 +341,24 @@ PMD which supports the IPSec protocol.
>>                   },
>>                   .crypto_capabilities = pmd_capabilities
>>           },
>> +        { /* PDCP Lookaside Protocol offload Data Plane */
>> +                .action = RTE_SECURITY_ACTION_TYPE_LOOKASIDE_PROTOCOL,
>> +                .protocol = RTE_SECURITY_PROTOCOL_PDCP,
>> +                .pdcp = {
>> +                        .domain = RTE_SECURITY_PDCP_MODE_DATA,
>> +                        .capa_flags = 0
>> +                },
>> +                .crypto_capabilities = pmd_capabilities
>> +        },
>> +        { /* PDCP Lookaside Protocol offload Control */
>> +                .action = RTE_SECURITY_ACTION_TYPE_LOOKASIDE_PROTOCOL,
>> +                .protocol = RTE_SECURITY_PROTOCOL_PDCP,
>> +                .pdcp = {
>> +                        .domain = RTE_SECURITY_PDCP_MODE_CONTROL,
>> +                        .capa_flags = 0
>> +                },
>> +                .crypto_capabilities = pmd_capabilities
>> +        },
>>           {
>>                   .action = RTE_SECURITY_ACTION_TYPE_NONE
>>           }
>> @@ -429,6 +490,7 @@ Security Session configuration structure is defined as
>> ``rte_security_session_co
>>           union {
>>                   struct rte_security_ipsec_xform ipsec;
>>                   struct rte_security_macsec_xform macsec;
>> +                struct rte_security_pdcp_xform pdcp;
>>           };
>>           /**< Configuration parameters for security session */
>>           struct rte_crypto_sym_xform *crypto_xform; @@ -463,15 +525,17 @@
>> The ``rte_security_session_protocol`` is defined as  .. code-block:: c
>>
>>       enum rte_security_session_protocol {
>> -        RTE_SECURITY_PROTOCOL_IPSEC,
>> +        RTE_SECURITY_PROTOCOL_IPSEC = 1,
>>           /**< IPsec Protocol */
>>           RTE_SECURITY_PROTOCOL_MACSEC,
>>           /**< MACSec Protocol */
>> +        RTE_SECURITY_PROTOCOL_PDCP,
>> +        /**< PDCP Protocol */
>>       };
>>
>> -Currently the library defines configuration parameters for IPSec only. For other
>> -protocols like MACSec, structures and enums are defined as place holders
>> which -will be updated in the future.
>> +Currently the library defines configuration parameters for IPsec and PDCP only.
>> +For other protocols like MACSec, structures and enums are defined as
>> +place holders which will be updated in the future.
>>
>>   IPsec related configuration parameters are defined in
>> ``rte_security_ipsec_xform``
>>
>> @@ -494,6 +558,35 @@ IPsec related configuration parameters are defined in
>> ``rte_security_ipsec_xform
>>           /**< Tunnel parameters, NULL for transport mode */
>>       };
>>
>> +PDCP related configuration parameters are defined in
>> +``rte_security_pdcp_xform``
>> +
>> +.. code-block:: c
>> +
>> +    struct rte_security_pdcp_xform {
>> +        int8_t bearer; /**< PDCP bearer ID */
>> +        /**< Enable in order delivery, this field shall be set only if
>> +         * driver/HW is capable. See RTE_SECURITY_PDCP_ORDERING_CAP.
>> +         */
>> +        uint8_t en_ordering;
>> +        /**< Notify driver/HW to detect and remove duplicate packets.
>> +         * This field should be set only when driver/hw is capable.
>> +         * See RTE_SECURITY_PDCP_DUP_DETECT_CAP.
>> +         */
>> +        uint8_t remove_duplicates;
>> +        /**< PDCP mode of operation: Control or data */
>> +        enum rte_security_pdcp_domain domain;
>> +        /**< PDCP Frame Direction 0:UL 1:DL */
>> +        enum rte_security_pdcp_direction pkt_dir;
>> +        /**< Sequence number size, 5/7/12/15/18 */
>> +        enum rte_security_pdcp_sn_size sn_size;
>> +        /**< Starting Hyper Frame Number to be used together with the SN
>> +         * from the PDCP frames
>> +         */
>> +        uint32_t hfn;
>> +        /**< HFN Threshold for key renegotiation */
>> +        uint32_t hfn_threshold;
>> +    };
>> +
>>
>>   Security API
>>   ~~~~~~~~~~~~
>> diff --git a/lib/librte_security/rte_security.c b/lib/librte_security/rte_security.c
>> index 1954960a5..c6355de95 100644
>> --- a/lib/librte_security/rte_security.c
>> +++ b/lib/librte_security/rte_security.c
>> @@ -131,6 +131,10 @@ rte_security_capability_get(struct rte_security_ctx
>> *instance,
>>                                          capability->ipsec.direction ==
>>                                                          idx->ipsec.direction)
>>                                          return capability;
>> +                       } else if (idx->protocol == RTE_SECURITY_PROTOCOL_PDCP) {
>> +                               if (capability->pdcp.domain ==
>> +                                                       idx->pdcp.domain)
>> +                                       return capability;
>>                          }
>>                  }
>>          }
>> diff --git a/lib/librte_security/rte_security.h b/lib/librte_security/rte_security.h
>> index b0d1b97ee..de49017e1 100644
>> --- a/lib/librte_security/rte_security.h
>> +++ b/lib/librte_security/rte_security.h
>> @@ -206,6 +206,66 @@ struct rte_security_macsec_xform {
>>          int dummy;
>>   };
>>
>> +/**
>> + * PDCP Mode of session
>> + */
>> +enum rte_security_pdcp_domain {
>> +       RTE_SECURITY_PDCP_MODE_CONTROL, /**< PDCP control plane */
>> +       RTE_SECURITY_PDCP_MODE_DATA,    /**< PDCP data plane */
>> +};
>> +
>> +/** PDCP Frame direction */
>> +enum rte_security_pdcp_direction {
>> +       RTE_SECURITY_PDCP_UPLINK,       /**< Uplink */
>> +       RTE_SECURITY_PDCP_DOWNLINK,     /**< Downlink */
>> +};
>> +
>> +/**
>> + * PDCP Sequence Number Size selectors
>> + * @PDCP_SN_SIZE_5: 5bit sequence number
>> + * @PDCP_SN_SIZE_7: 7bit sequence number
>> + * @PDCP_SN_SIZE_12: 12bit sequence number
>> + * @PDCP_SN_SIZE_15: 15bit sequence number
>> + * @PDCP_SN_SIZE_18: 18bit sequence number  */ enum
>> +rte_security_pdcp_sn_size {
>> +       RTE_SECURITY_PDCP_SN_SIZE_5 = 5,
>> +       RTE_SECURITY_PDCP_SN_SIZE_7 = 7,
>> +       RTE_SECURITY_PDCP_SN_SIZE_12 = 12,
>> +       RTE_SECURITY_PDCP_SN_SIZE_15 = 15,
>> +       RTE_SECURITY_PDCP_SN_SIZE_18 = 18 };
>> +
>> +/**
>> + * PDCP security association configuration data.
>> + *
>> + * This structure contains data required to create a PDCP security session.
>> + */
>> +struct rte_security_pdcp_xform {
>> +       int8_t bearer;  /**< PDCP bearer ID */
>> +       /**< Enable in order delivery, this field shall be set only if
>> +        * driver/HW is capable. See RTE_SECURITY_PDCP_ORDERING_CAP.
>> +        */
>> +       uint8_t en_ordering;
>> +       /**< Notify driver/HW to detect and remove duplicate packets.
>> +        * This field should be set only when driver/hw is capable.
>> +        * See RTE_SECURITY_PDCP_DUP_DETECT_CAP.
>> +        */
>> +       uint8_t remove_duplicates;
>> +       /**< PDCP mode of operation: Control or data */
>> +       enum rte_security_pdcp_domain domain;
>> +       /**< PDCP Frame Direction 0:UL 1:DL */
>> +       enum rte_security_pdcp_direction pkt_dir;
>> +       /**< Sequence number size, 5/7/12/15/18 */
>> +       enum rte_security_pdcp_sn_size sn_size;
>> +       /**< Starting Hyper Frame Number to be used together with the SN
>> +        * from the PDCP frames
>> +        */
>> +       uint32_t hfn;
>> +       /**< HFN Threshold for key renegotiation */
>> +       uint32_t hfn_threshold;
>> +};
>> +
>>   /**
>>    * Security session action type.
>>    */
>> @@ -232,6 +292,8 @@ enum rte_security_session_protocol {
>>          /**< IPsec Protocol */
>>          RTE_SECURITY_PROTOCOL_MACSEC,
>>          /**< MACSec Protocol */
>> +       RTE_SECURITY_PROTOCOL_PDCP,
>> +       /**< PDCP Protocol */
>>   };
>>
>>   /**
>> @@ -246,6 +308,7 @@ struct rte_security_session_conf {
>>          union {
>>                  struct rte_security_ipsec_xform ipsec;
>>                  struct rte_security_macsec_xform macsec;
>> +               struct rte_security_pdcp_xform pdcp;
>>          };
>>          /**< Configuration parameters for security session */
>>          struct rte_crypto_sym_xform *crypto_xform; @@ -413,6 +476,10 @@
>> struct rte_security_ipsec_stats {
>>
>>   };
>>
>> +struct rte_security_pdcp_stats {
>> +       uint64_t reserved;
>> +};
>> +
>>   struct rte_security_stats {
>>          enum rte_security_session_protocol protocol;
>>          /**< Security protocol to be configured */ @@ -421,6 +488,7 @@ struct
>> rte_security_stats {
>>          union {
>>                  struct rte_security_macsec_stats macsec;
>>                  struct rte_security_ipsec_stats ipsec;
>> +               struct rte_security_pdcp_stats pdcp;
>>          };
>>   };
>>
>> @@ -465,6 +533,13 @@ struct rte_security_capability {
>>                          int dummy;
>>                  } macsec;
>>                  /**< MACsec capability */
>> +               struct {
>> +                       enum rte_security_pdcp_domain domain;
>> +                       /** < PDCP mode of operation: Control or data */
>> +                       uint32_t capa_flags;
>> +                       /** < Capabilitity flags, see RTE_SECURITY_PDCP_* */
>> +               } pdcp;
>> +               /**< PDCP capability */
>>          };
>>
>>          const struct rte_cryptodev_capabilities *crypto_capabilities; @@ -474,6
>> +549,19 @@ struct rte_security_capability {
>>          /**< Device offload flags */
>>   };
>>
>> +/**< Underlying Hardware/driver which support PDCP may or may not
>> +support
>> + * packet ordering. Set RTE_SECURITY_PDCP_ORDERING_CAP if it support.
>> + * If it is not set, driver/HW assumes packets received are in order
>> + * and it will be application's responsibility to maintain ordering.
>> + */
>> +#define RTE_SECURITY_PDCP_ORDERING_CAP         0x00000001
>> +
>> +/**< Underlying Hardware/driver which support PDCP may or may not
>> +detect
>> + * duplicate packet. Set RTE_SECURITY_PDCP_DUP_DETECT_CAP if it support.
>> + * If it is not set, driver/HW assumes there is no duplicate packet received.
>> + */
>> +#define RTE_SECURITY_PDCP_DUP_DETECT_CAP       0x00000002
>> +
>>   #define RTE_SECURITY_TX_OLOAD_NEED_MDATA       0x00000001
>>   /**< HW needs metadata update, see rte_security_set_pkt_metadata().
>>    */
>> @@ -506,6 +594,10 @@ struct rte_security_capability_idx {
>>                          enum rte_security_ipsec_sa_mode mode;
>>                          enum rte_security_ipsec_sa_direction direction;
>>                  } ipsec;
>> +               struct {
>> +                       enum rte_security_pdcp_domain domain;
>> +                       uint32_t capa_flags;
>> +               } pdcp;
>>          };
>>   };
>>
>> --
>> 2.17.1


^ permalink raw reply	[flat|nested] 41+ messages in thread

* Re: [dpdk-dev] [PATCH v5 1/3] security: support pdcp protocol
  2018-10-16 10:57             ` Akhil Goyal
@ 2018-10-16 11:15               ` Joseph, Anoob
  2018-10-16 12:25                 ` Akhil Goyal
  0 siblings, 1 reply; 41+ messages in thread
From: Joseph, Anoob @ 2018-10-16 11:15 UTC (permalink / raw)
  To: Akhil Goyal, dev
  Cc: pablo.de.lara.guarch, radu.nicolau, Jacob,  Jerin, Athreya,
	Narayana Prasad, Verma, Shally, Velumuri, Vidya, Hemant Agrawal

Hi Akhil,

Sorry. I missed this before,

> >> +    struct rte_security_pdcp_xform {
> >> +        int8_t bearer; /**< PDCP bearer ID */
> >> +        /**< Enable in order delivery, this field shall be set only if
> >> +         * driver/HW is capable. See RTE_SECURITY_PDCP_ORDERING_CAP.
> >> +         */
> >> +        uint8_t en_ordering;
> >> +        /**< Notify driver/HW to detect and remove duplicate packets.
> >> +         * This field should be set only when driver/hw is capable.
> >> +         * See RTE_SECURITY_PDCP_DUP_DETECT_CAP.
> >> +         */
> >> +        uint8_t remove_duplicates;
> >> +        /**< PDCP mode of operation: Control or data */
> >> +        enum rte_security_pdcp_domain domain;
> >> +        /**< PDCP Frame Direction 0:UL 1:DL */
> >> +        enum rte_security_pdcp_direction pkt_dir;
> >> +        /**< Sequence number size, 5/7/12/15/18 */
> >> +        enum rte_security_pdcp_sn_size sn_size;
> >> +        /**< Starting Hyper Frame Number to be used together with the SN
> >> +         * from the PDCP frames
> >> +         */
> >> +        uint32_t hfn;
> >> +        /**< HFN Threshold for key renegotiation */
> >> +        uint32_t hfn_threshold;
> >> +    };

Don't you need to use /** (or /*) instead of /**< when the comment is before the member? I think the first member ('int8_t bearer') would have it right. Rest could end up wrong. Can you try building the docs and see if it's coming off well. If it's coming off well, you can proceed with applying the patch.

I think the same issue is observed if you go through the following doc,
https://doc.dpdk.org/api/structrte__security__ipsec__sa__options.html

Check for the description of field copy_df in rte_security.h

Thanks,
Anoob

> -----Original Message-----
> From: Akhil Goyal <akhil.goyal@nxp.com>
> Sent: 16 October 2018 16:27
> To: Joseph, Anoob <Anoob.Joseph@cavium.com>; dev@dpdk.org
> Cc: pablo.de.lara.guarch@intel.com; radu.nicolau@intel.com; Jacob, Jerin
> <Jerin.JacobKollanukkaran@cavium.com>; Athreya, Narayana Prasad
> <NarayanaPrasad.Athreya@cavium.com>; Verma, Shally
> <Shally.Verma@cavium.com>; Velumuri, Vidya <Vidya.Velumuri@cavium.com>;
> Hemant Agrawal <hemant.agrawal@nxp.com>
> Subject: Re: [dpdk-dev] [PATCH v5 1/3] security: support pdcp protocol
> 
> External Email
> 
> Hi Anoob,
> 
> On 10/16/2018 4:19 PM, Joseph, Anoob wrote:
> > Hi Akhil,
> >
> > The HFN threshold comment is still not right I guess,
> >
> >> +        uint32_t hfn;
> >> +        /**< HFN Threshold for key renegotiation */
> >> +        uint32_t hfn_threshold;
> > The above code snippet is there in the rte_security.rst file also. You may need
> to fix that also.
> >
> > And the following also need to be fixed,
> 
> I think there is some issue in your mail client.
> please check patchworks. Everything looks good to me
> http://patches.dpdk.org/patch/46886/
> 
> >> + * @PDCP_SN_SIZE_18: 18bit sequence number  */ enum
> >> +rte_security_pdcp_sn_size {
> > ....
> >> +       RTE_SECURITY_PDCP_SN_SIZE_18 = 18 };
> > With the above changes,
> > Acked-by: Anoob Joseph <anoob.joseph@caviumnetworks.com>
> Thanks.
> >
> > Thanks,
> > Anoob
> >> -----Original Message-----
> >> From: Akhil Goyal <akhil.goyal@nxp.com>
> >> Sent: 16 October 2018 16:09
> >> To: dev@dpdk.org
> >> Cc: pablo.de.lara.guarch@intel.com; radu.nicolau@intel.com; Jacob,
> >> Jerin <Jerin.JacobKollanukkaran@cavium.com>; Athreya, Narayana Prasad
> >> <NarayanaPrasad.Athreya@cavium.com>; Verma, Shally
> >> <Shally.Verma@cavium.com>; Joseph, Anoob
> <Anoob.Joseph@cavium.com>;
> >> Velumuri, Vidya <Vidya.Velumuri@cavium.com>; Hemant Agrawal
> >> <hemant.agrawal@nxp.com>; Akhil Goyal <akhil.goyal@nxp.com>
> >> Subject: [PATCH v5 1/3] security: support pdcp protocol
> >>
> >> External Email
> >>
> >> From: Akhil Goyal <akhil.goyal@nxp.com>
> >>
> >> Packet Data Convergence Protocol (PDCP) is added in rte_security for
> >> 3GPP TS
> >> 36.323 for LTE.
> >>
> >> The patchset provide the structure definitions for configuring the
> >> PDCP sessions and relevant documentation is added.
> >>
> >> Signed-off-by: Hemant Agrawal <hemant.agrawal@nxp.com>
> >> Signed-off-by: Akhil Goyal <akhil.goyal@nxp.com>
> >> ---
> >>   doc/guides/prog_guide/rte_security.rst | 107 +++++++++++++++++++++++--
> >>   lib/librte_security/rte_security.c     |   4 +
> >>   lib/librte_security/rte_security.h     |  92 +++++++++++++++++++++
> >>   3 files changed, 196 insertions(+), 7 deletions(-)
> >>
> >> diff --git a/doc/guides/prog_guide/rte_security.rst
> >> b/doc/guides/prog_guide/rte_security.rst
> >> index 0812abe77..e43f1554c 100644
> >> --- a/doc/guides/prog_guide/rte_security.rst
> >> +++ b/doc/guides/prog_guide/rte_security.rst
> >> @@ -10,8 +10,8 @@ The security library provides a framework for
> >> management and provisioning  of security protocol operations
> >> offloaded to hardware based devices. The  library defines generic
> >> APIs to create and free security sessions which can  support full
> >> protocol offload as well as inline crypto operation with - NIC or
> >> crypto devices. The framework currently only supports the IPSec protocol -
> and associated operations, other protocols will be added in future.
> >> +NIC or crypto devices. The framework currently only supports the
> >> +IPsec and PDCP protocol and associated operations, other protocols
> >> +will be added in
> >> future.
> >>
> >>   Design Principles
> >>   -----------------
> >> @@ -253,6 +253,49 @@ for any protocol header addition.
> >>           +--------|--------+
> >>                    V
> >>
> >> +PDCP Flow Diagram
> >> +~~~~~~~~~~~~~~~~~
> >> +
> >> +Based on 3GPP TS 36.323 Evolved Universal Terrestrial Radio Access
> >> +(E-UTRA); Packet Data Convergence Protocol (PDCP) specification
> >> +
> >> +.. code-block:: c
> >> +
> >> +        Transmitting PDCP Entity          Receiving PDCP Entity
> >> +                  |                                   ^
> >> +                  |                       +-----------|-----------+
> >> +                  V                       | In order delivery and |
> >> +        +---------|----------+            | Duplicate detection   |
> >> +        | Sequence Numbering |            |  (Data Plane only)    |
> >> +        +---------|----------+            +-----------|-----------+
> >> +                  |                                   |
> >> +        +---------|----------+            +-----------|----------+
> >> +        | Header Compression*|            | Header Decompression*|
> >> +        | (Data-Plane only)  |            |   (Data Plane only)  |
> >> +        +---------|----------+            +-----------|----------+
> >> +                  |                                   |
> >> +        +---------|-----------+           +-----------|----------+
> >> +        | Integrity Protection|           |Integrity Verification|
> >> +        | (Control Plane only)|           | (Control Plane only) |
> >> +        +---------|-----------+           +-----------|----------+
> >> +        +---------|-----------+            +----------|----------+
> >> +        |     Ciphering       |            |     Deciphering     |
> >> +        +---------|-----------+            +----------|----------+
> >> +        +---------|-----------+            +----------|----------+
> >> +        |   Add PDCP header   |            | Remove PDCP Header  |
> >> +        +---------|-----------+            +----------|----------+
> >> +                  |                                   |
> >> +                  +----------------->>----------------+
> >> +
> >> +
> >> +.. note::
> >> +
> >> +    * Header Compression and decompression are not supported currently.
> >> +
> >> +Just like IPsec, in case of PDCP also header addition/deletion,
> >> +cipher/ de-cipher, integrity protection/verification is done based
> >> +on the action type chosen.
> >> +
> >>   Device Features and Capabilities
> >>   ---------------------------------
> >>
> >> @@ -271,7 +314,7 @@ structure in the *DPDK API Reference*.
> >>
> >>   Each driver (crypto or ethernet) defines its own private array of
> >> capabilities  for the operations it supports. Below is an example of
> >> the capabilities for a -PMD which supports the IPSec protocol.
> >> +PMD which supports the IPsec and PDCP protocol.
> >>
> >>   .. code-block:: c
> >>
> >> @@ -298,6 +341,24 @@ PMD which supports the IPSec protocol.
> >>                   },
> >>                   .crypto_capabilities = pmd_capabilities
> >>           },
> >> +        { /* PDCP Lookaside Protocol offload Data Plane */
> >> +                .action = RTE_SECURITY_ACTION_TYPE_LOOKASIDE_PROTOCOL,
> >> +                .protocol = RTE_SECURITY_PROTOCOL_PDCP,
> >> +                .pdcp = {
> >> +                        .domain = RTE_SECURITY_PDCP_MODE_DATA,
> >> +                        .capa_flags = 0
> >> +                },
> >> +                .crypto_capabilities = pmd_capabilities
> >> +        },
> >> +        { /* PDCP Lookaside Protocol offload Control */
> >> +                .action = RTE_SECURITY_ACTION_TYPE_LOOKASIDE_PROTOCOL,
> >> +                .protocol = RTE_SECURITY_PROTOCOL_PDCP,
> >> +                .pdcp = {
> >> +                        .domain = RTE_SECURITY_PDCP_MODE_CONTROL,
> >> +                        .capa_flags = 0
> >> +                },
> >> +                .crypto_capabilities = pmd_capabilities
> >> +        },
> >>           {
> >>                   .action = RTE_SECURITY_ACTION_TYPE_NONE
> >>           }
> >> @@ -429,6 +490,7 @@ Security Session configuration structure is
> >> defined as ``rte_security_session_co
> >>           union {
> >>                   struct rte_security_ipsec_xform ipsec;
> >>                   struct rte_security_macsec_xform macsec;
> >> +                struct rte_security_pdcp_xform pdcp;
> >>           };
> >>           /**< Configuration parameters for security session */
> >>           struct rte_crypto_sym_xform *crypto_xform; @@ -463,15
> >> +525,17 @@ The ``rte_security_session_protocol`` is defined as  ..
> >> code-block:: c
> >>
> >>       enum rte_security_session_protocol {
> >> -        RTE_SECURITY_PROTOCOL_IPSEC,
> >> +        RTE_SECURITY_PROTOCOL_IPSEC = 1,
> >>           /**< IPsec Protocol */
> >>           RTE_SECURITY_PROTOCOL_MACSEC,
> >>           /**< MACSec Protocol */
> >> +        RTE_SECURITY_PROTOCOL_PDCP,
> >> +        /**< PDCP Protocol */
> >>       };
> >>
> >> -Currently the library defines configuration parameters for IPSec
> >> only. For other -protocols like MACSec, structures and enums are
> >> defined as place holders which -will be updated in the future.
> >> +Currently the library defines configuration parameters for IPsec and PDCP
> only.
> >> +For other protocols like MACSec, structures and enums are defined as
> >> +place holders which will be updated in the future.
> >>
> >>   IPsec related configuration parameters are defined in
> >> ``rte_security_ipsec_xform``
> >>
> >> @@ -494,6 +558,35 @@ IPsec related configuration parameters are
> >> defined in ``rte_security_ipsec_xform
> >>           /**< Tunnel parameters, NULL for transport mode */
> >>       };
> >>
> >> +PDCP related configuration parameters are defined in
> >> +``rte_security_pdcp_xform``
> >> +
> >> +.. code-block:: c
> >> +
> >> +    struct rte_security_pdcp_xform {
> >> +        int8_t bearer; /**< PDCP bearer ID */
> >> +        /**< Enable in order delivery, this field shall be set only if
> >> +         * driver/HW is capable. See RTE_SECURITY_PDCP_ORDERING_CAP.
> >> +         */
> >> +        uint8_t en_ordering;
> >> +        /**< Notify driver/HW to detect and remove duplicate packets.
> >> +         * This field should be set only when driver/hw is capable.
> >> +         * See RTE_SECURITY_PDCP_DUP_DETECT_CAP.
> >> +         */
> >> +        uint8_t remove_duplicates;
> >> +        /**< PDCP mode of operation: Control or data */
> >> +        enum rte_security_pdcp_domain domain;
> >> +        /**< PDCP Frame Direction 0:UL 1:DL */
> >> +        enum rte_security_pdcp_direction pkt_dir;
> >> +        /**< Sequence number size, 5/7/12/15/18 */
> >> +        enum rte_security_pdcp_sn_size sn_size;
> >> +        /**< Starting Hyper Frame Number to be used together with the SN
> >> +         * from the PDCP frames
> >> +         */
> >> +        uint32_t hfn;
> >> +        /**< HFN Threshold for key renegotiation */
> >> +        uint32_t hfn_threshold;
> >> +    };
> >> +
> >>
> >>   Security API
> >>   ~~~~~~~~~~~~
> >> diff --git a/lib/librte_security/rte_security.c
> >> b/lib/librte_security/rte_security.c
> >> index 1954960a5..c6355de95 100644
> >> --- a/lib/librte_security/rte_security.c
> >> +++ b/lib/librte_security/rte_security.c
> >> @@ -131,6 +131,10 @@ rte_security_capability_get(struct
> >> rte_security_ctx *instance,
> >>                                          capability->ipsec.direction ==
> >>                                                          idx->ipsec.direction)
> >>                                          return capability;
> >> +                       } else if (idx->protocol == RTE_SECURITY_PROTOCOL_PDCP) {
> >> +                               if (capability->pdcp.domain ==
> >> +                                                       idx->pdcp.domain)
> >> +                                       return capability;
> >>                          }
> >>                  }
> >>          }
> >> diff --git a/lib/librte_security/rte_security.h
> >> b/lib/librte_security/rte_security.h
> >> index b0d1b97ee..de49017e1 100644
> >> --- a/lib/librte_security/rte_security.h
> >> +++ b/lib/librte_security/rte_security.h
> >> @@ -206,6 +206,66 @@ struct rte_security_macsec_xform {
> >>          int dummy;
> >>   };
> >>
> >> +/**
> >> + * PDCP Mode of session
> >> + */
> >> +enum rte_security_pdcp_domain {
> >> +       RTE_SECURITY_PDCP_MODE_CONTROL, /**< PDCP control plane */
> >> +       RTE_SECURITY_PDCP_MODE_DATA,    /**< PDCP data plane */
> >> +};
> >> +
> >> +/** PDCP Frame direction */
> >> +enum rte_security_pdcp_direction {
> >> +       RTE_SECURITY_PDCP_UPLINK,       /**< Uplink */
> >> +       RTE_SECURITY_PDCP_DOWNLINK,     /**< Downlink */
> >> +};
> >> +
> >> +/**
> >> + * PDCP Sequence Number Size selectors
> >> + * @PDCP_SN_SIZE_5: 5bit sequence number
> >> + * @PDCP_SN_SIZE_7: 7bit sequence number
> >> + * @PDCP_SN_SIZE_12: 12bit sequence number
> >> + * @PDCP_SN_SIZE_15: 15bit sequence number
> >> + * @PDCP_SN_SIZE_18: 18bit sequence number  */ enum
> >> +rte_security_pdcp_sn_size {
> >> +       RTE_SECURITY_PDCP_SN_SIZE_5 = 5,
> >> +       RTE_SECURITY_PDCP_SN_SIZE_7 = 7,
> >> +       RTE_SECURITY_PDCP_SN_SIZE_12 = 12,
> >> +       RTE_SECURITY_PDCP_SN_SIZE_15 = 15,
> >> +       RTE_SECURITY_PDCP_SN_SIZE_18 = 18 };
> >> +
> >> +/**
> >> + * PDCP security association configuration data.
> >> + *
> >> + * This structure contains data required to create a PDCP security session.
> >> + */
> >> +struct rte_security_pdcp_xform {
> >> +       int8_t bearer;  /**< PDCP bearer ID */
> >> +       /**< Enable in order delivery, this field shall be set only if
> >> +        * driver/HW is capable. See RTE_SECURITY_PDCP_ORDERING_CAP.
> >> +        */
> >> +       uint8_t en_ordering;
> >> +       /**< Notify driver/HW to detect and remove duplicate packets.
> >> +        * This field should be set only when driver/hw is capable.
> >> +        * See RTE_SECURITY_PDCP_DUP_DETECT_CAP.
> >> +        */
> >> +       uint8_t remove_duplicates;
> >> +       /**< PDCP mode of operation: Control or data */
> >> +       enum rte_security_pdcp_domain domain;
> >> +       /**< PDCP Frame Direction 0:UL 1:DL */
> >> +       enum rte_security_pdcp_direction pkt_dir;
> >> +       /**< Sequence number size, 5/7/12/15/18 */
> >> +       enum rte_security_pdcp_sn_size sn_size;
> >> +       /**< Starting Hyper Frame Number to be used together with the SN
> >> +        * from the PDCP frames
> >> +        */
> >> +       uint32_t hfn;
> >> +       /**< HFN Threshold for key renegotiation */
> >> +       uint32_t hfn_threshold;
> >> +};
> >> +
> >>   /**
> >>    * Security session action type.
> >>    */
> >> @@ -232,6 +292,8 @@ enum rte_security_session_protocol {
> >>          /**< IPsec Protocol */
> >>          RTE_SECURITY_PROTOCOL_MACSEC,
> >>          /**< MACSec Protocol */
> >> +       RTE_SECURITY_PROTOCOL_PDCP,
> >> +       /**< PDCP Protocol */
> >>   };
> >>
> >>   /**
> >> @@ -246,6 +308,7 @@ struct rte_security_session_conf {
> >>          union {
> >>                  struct rte_security_ipsec_xform ipsec;
> >>                  struct rte_security_macsec_xform macsec;
> >> +               struct rte_security_pdcp_xform pdcp;
> >>          };
> >>          /**< Configuration parameters for security session */
> >>          struct rte_crypto_sym_xform *crypto_xform; @@ -413,6 +476,10
> >> @@ struct rte_security_ipsec_stats {
> >>
> >>   };
> >>
> >> +struct rte_security_pdcp_stats {
> >> +       uint64_t reserved;
> >> +};
> >> +
> >>   struct rte_security_stats {
> >>          enum rte_security_session_protocol protocol;
> >>          /**< Security protocol to be configured */ @@ -421,6 +488,7
> >> @@ struct rte_security_stats {
> >>          union {
> >>                  struct rte_security_macsec_stats macsec;
> >>                  struct rte_security_ipsec_stats ipsec;
> >> +               struct rte_security_pdcp_stats pdcp;
> >>          };
> >>   };
> >>
> >> @@ -465,6 +533,13 @@ struct rte_security_capability {
> >>                          int dummy;
> >>                  } macsec;
> >>                  /**< MACsec capability */
> >> +               struct {
> >> +                       enum rte_security_pdcp_domain domain;
> >> +                       /** < PDCP mode of operation: Control or data */
> >> +                       uint32_t capa_flags;
> >> +                       /** < Capabilitity flags, see RTE_SECURITY_PDCP_* */
> >> +               } pdcp;
> >> +               /**< PDCP capability */
> >>          };
> >>
> >>          const struct rte_cryptodev_capabilities
> >> *crypto_capabilities; @@ -474,6
> >> +549,19 @@ struct rte_security_capability {
> >>          /**< Device offload flags */
> >>   };
> >>
> >> +/**< Underlying Hardware/driver which support PDCP may or may not
> >> +support
> >> + * packet ordering. Set RTE_SECURITY_PDCP_ORDERING_CAP if it support.
> >> + * If it is not set, driver/HW assumes packets received are in order
> >> + * and it will be application's responsibility to maintain ordering.
> >> + */
> >> +#define RTE_SECURITY_PDCP_ORDERING_CAP         0x00000001
> >> +
> >> +/**< Underlying Hardware/driver which support PDCP may or may not
> >> +detect
> >> + * duplicate packet. Set RTE_SECURITY_PDCP_DUP_DETECT_CAP if it
> support.
> >> + * If it is not set, driver/HW assumes there is no duplicate packet received.
> >> + */
> >> +#define RTE_SECURITY_PDCP_DUP_DETECT_CAP       0x00000002
> >> +
> >>   #define RTE_SECURITY_TX_OLOAD_NEED_MDATA       0x00000001
> >>   /**< HW needs metadata update, see rte_security_set_pkt_metadata().
> >>    */
> >> @@ -506,6 +594,10 @@ struct rte_security_capability_idx {
> >>                          enum rte_security_ipsec_sa_mode mode;
> >>                          enum rte_security_ipsec_sa_direction direction;
> >>                  } ipsec;
> >> +               struct {
> >> +                       enum rte_security_pdcp_domain domain;
> >> +                       uint32_t capa_flags;
> >> +               } pdcp;
> >>          };
> >>   };
> >>
> >> --
> >> 2.17.1


^ permalink raw reply	[flat|nested] 41+ messages in thread

* Re: [dpdk-dev] [PATCH v5 1/3] security: support pdcp protocol
  2018-10-16 11:15               ` Joseph, Anoob
@ 2018-10-16 12:25                 ` Akhil Goyal
  0 siblings, 0 replies; 41+ messages in thread
From: Akhil Goyal @ 2018-10-16 12:25 UTC (permalink / raw)
  To: Joseph, Anoob, dev
  Cc: pablo.de.lara.guarch, radu.nicolau, Jacob, Jerin, Athreya,
	Narayana Prasad, Verma, Shally, Velumuri, Vidya, Hemant Agrawal



On 10/16/2018 4:45 PM, Joseph, Anoob wrote:
> Don't you need to use /** (or /*) instead of /**< when the comment is before the member? I think the first member ('int8_t bearer') would have it right. Rest could end up wrong. Can you try building the docs and see if it's coming off well. If it's coming off well, you can proceed with applying the patch.
Thanks for notifying this.
Will correct it while applying.


^ permalink raw reply	[flat|nested] 41+ messages in thread

* Re: [dpdk-dev] [PATCH v5 0/3] security: support for pdcp
  2018-10-16 10:38       ` [dpdk-dev] [PATCH v5 0/3] security: support for pdcp Akhil Goyal
                           ` (2 preceding siblings ...)
  2018-10-16 10:39         ` [dpdk-dev] [PATCH v5 3/3] crypto/dpaa2_sec: support pdcp offload Akhil Goyal
@ 2018-10-16 14:35         ` Akhil Goyal
  2018-10-18 14:40           ` Thomas Monjalon
  2018-10-22  7:12         ` [dpdk-dev] [PATCH v6 " Hemant Agrawal
  4 siblings, 1 reply; 41+ messages in thread
From: Akhil Goyal @ 2018-10-16 14:35 UTC (permalink / raw)
  To: dev
  Cc: pablo.de.lara.guarch, radu.nicolau, jerin.jacob,
	narayanaprasad.athreya, Shally.Verma, Anoob.Joseph,
	Vidya.Velumuri, Hemant Agrawal



On 10/16/2018 4:08 PM, Akhil Goyal wrote:
> From: Akhil Goyal <akhil.goyal@nxp.com>
>
> Security library currently only has support for IPSec protocol.
> This patchset defines structures for pdcp protocol in rte_security
> and provide a sample driver implementation for lookaside protocol
> offload to support PDCP.
>
> Changes in v5:
> - corrected comments in xform structure.
>
> changes in v4:
> - added capability and setting for packet ordering and duplicate
> detection.
> - some fixes in driver.
>
> changes in v3:
> removed checkpatch warnings.
>
> changes in v2:
> - removed hfn override. Will be added later when it is supported
> - added seq number size = 18bits
> - coding style issues corrected in pdcp.h
> - updated documentation for specifying the 3GPP specification reference
> - removed some duplicate code in dpaa2_sec_dpseci.c
>
>
> Akhil Goyal (3):
>    security: support pdcp protocol
>    crypto/dpaa2_sec: add sample pdcp descriptor apis
>    crypto/dpaa2_sec: support pdcp offload
>
>   doc/guides/prog_guide/rte_security.rst      |  107 +-
>   drivers/crypto/dpaa2_sec/dpaa2_sec_dpseci.c |  257 ++
>   drivers/crypto/dpaa2_sec/dpaa2_sec_priv.h   |  208 +-
>   drivers/crypto/dpaa2_sec/hw/desc.h          |    2 +-
>   drivers/crypto/dpaa2_sec/hw/desc/pdcp.h     | 2796 +++++++++++++++++++
>   lib/librte_security/rte_security.c          |    4 +
>   lib/librte_security/rte_security.h          |   92 +
>   7 files changed, 3450 insertions(+), 16 deletions(-)
>   create mode 100644 drivers/crypto/dpaa2_sec/hw/desc/pdcp.h
>
Patchset applied to dpdk-next-crypto

minor modification as suggested by Anoob is done.

^ permalink raw reply	[flat|nested] 41+ messages in thread

* Re: [dpdk-dev] [PATCH v5 0/3] security: support for pdcp
  2018-10-16 14:35         ` [dpdk-dev] [PATCH v5 0/3] security: support for pdcp Akhil Goyal
@ 2018-10-18 14:40           ` Thomas Monjalon
  2018-10-22  7:10             ` Hemant Agrawal
  0 siblings, 1 reply; 41+ messages in thread
From: Thomas Monjalon @ 2018-10-18 14:40 UTC (permalink / raw)
  To: Akhil Goyal
  Cc: dev, pablo.de.lara.guarch, radu.nicolau, jerin.jacob,
	narayanaprasad.athreya, Shally.Verma, Anoob.Joseph,
	Vidya.Velumuri, Hemant Agrawal

16/10/2018 16:35, Akhil Goyal:
> > Akhil Goyal (3):
> >    security: support pdcp protocol
> >    crypto/dpaa2_sec: add sample pdcp descriptor apis
> >    crypto/dpaa2_sec: support pdcp offload
> >
> >   doc/guides/prog_guide/rte_security.rst      |  107 +-
> >   drivers/crypto/dpaa2_sec/dpaa2_sec_dpseci.c |  257 ++
> >   drivers/crypto/dpaa2_sec/dpaa2_sec_priv.h   |  208 +-
> >   drivers/crypto/dpaa2_sec/hw/desc.h          |    2 +-
> >   drivers/crypto/dpaa2_sec/hw/desc/pdcp.h     | 2796 +++++++++++++++++++
> >   lib/librte_security/rte_security.c          |    4 +
> >   lib/librte_security/rte_security.h          |   92 +
> >   7 files changed, 3450 insertions(+), 16 deletions(-)
> >   create mode 100644 drivers/crypto/dpaa2_sec/hw/desc/pdcp.h
> >
> Patchset applied to dpdk-next-crypto
> 
> minor modification as suggested by Anoob is done.

This patchset won't be part of the pull in master because of 2 issues:

- clang error:
drivers/crypto/dpaa2_sec/dpaa2_sec_dpseci.c:2759:18: fatal error:
implicit conversion from enumeration type 'enum rte_security_pdcp_sn_size'
to different enumeration type 'enum pdcp_sn_size'

- doxygen error:
rte_security.h:225: warning: Found unknown command `\PDCP_SN_SIZE_5'
rte_security.h:226: warning: Found unknown command `\PDCP_SN_SIZE_7'
rte_security.h:227: warning: Found unknown command `\PDCP_SN_SIZE_12'
rte_security.h:228: warning: Found unknown command `\PDCP_SN_SIZE_15'
rte_security.h:229: warning: Found unknown command `\PDCP_SN_SIZE_18'

I think these doxygen comments can be removed.

^ permalink raw reply	[flat|nested] 41+ messages in thread

* Re: [dpdk-dev] [PATCH v5 0/3] security: support for pdcp
  2018-10-18 14:40           ` Thomas Monjalon
@ 2018-10-22  7:10             ` Hemant Agrawal
  0 siblings, 0 replies; 41+ messages in thread
From: Hemant Agrawal @ 2018-10-22  7:10 UTC (permalink / raw)
  To: Thomas Monjalon, Akhil Goyal
  Cc: dev, pablo.de.lara.guarch, radu.nicolau, jerin.jacob,
	narayanaprasad.athreya, Shally.Verma, Anoob.Joseph,
	Vidya.Velumuri



On 10/18/2018 8:10 PM, Thomas Monjalon wrote:
> 16/10/2018 16:35, Akhil Goyal:
>>> Akhil Goyal (3):
>>>     security: support pdcp protocol
>>>     crypto/dpaa2_sec: add sample pdcp descriptor apis
>>>     crypto/dpaa2_sec: support pdcp offload
>>>
>>>    doc/guides/prog_guide/rte_security.rst      |  107 +-
>>>    drivers/crypto/dpaa2_sec/dpaa2_sec_dpseci.c |  257 ++
>>>    drivers/crypto/dpaa2_sec/dpaa2_sec_priv.h   |  208 +-
>>>    drivers/crypto/dpaa2_sec/hw/desc.h          |    2 +-
>>>    drivers/crypto/dpaa2_sec/hw/desc/pdcp.h     | 2796 +++++++++++++++++++
>>>    lib/librte_security/rte_security.c          |    4 +
>>>    lib/librte_security/rte_security.h          |   92 +
>>>    7 files changed, 3450 insertions(+), 16 deletions(-)
>>>    create mode 100644 drivers/crypto/dpaa2_sec/hw/desc/pdcp.h
>>>
>> Patchset applied to dpdk-next-crypto
>>
>> minor modification as suggested by Anoob is done.
> This patchset won't be part of the pull in master because of 2 issues:
>
> - clang error:
> drivers/crypto/dpaa2_sec/dpaa2_sec_dpseci.c:2759:18: fatal error:
> implicit conversion from enumeration type 'enum rte_security_pdcp_sn_size'
> to different enumeration type 'enum pdcp_sn_size'
Got it.  I am sending the fix (Akhil is on leave).
> - doxygen error:
> rte_security.h:225: warning: Found unknown command `\PDCP_SN_SIZE_5'
> rte_security.h:226: warning: Found unknown command `\PDCP_SN_SIZE_7'
> rte_security.h:227: warning: Found unknown command `\PDCP_SN_SIZE_12'
> rte_security.h:228: warning: Found unknown command `\PDCP_SN_SIZE_15'
> rte_security.h:229: warning: Found unknown command `\PDCP_SN_SIZE_18'
>
> I think these doxygen comments can be removed.
>
>
I am fixing the comment and placing them at right place. The whole file 
has comment for structures, so it is better that we define these as well.

^ permalink raw reply	[flat|nested] 41+ messages in thread

* [dpdk-dev] [PATCH v6 0/3] security: support for pdcp
  2018-10-16 10:38       ` [dpdk-dev] [PATCH v5 0/3] security: support for pdcp Akhil Goyal
                           ` (3 preceding siblings ...)
  2018-10-16 14:35         ` [dpdk-dev] [PATCH v5 0/3] security: support for pdcp Akhil Goyal
@ 2018-10-22  7:12         ` Hemant Agrawal
  2018-10-22  7:12           ` [dpdk-dev] [PATCH v6 1/3] security: support pdcp protocol Hemant Agrawal
                             ` (2 more replies)
  4 siblings, 3 replies; 41+ messages in thread
From: Hemant Agrawal @ 2018-10-22  7:12 UTC (permalink / raw)
  To: dev
  Cc: thomas, pablo.de.lara.guarch, radu.nicolau, jerin.jacob,
	narayanaprasad.athreya, Shally.Verma, Anoob.Joseph,
	Vidya.Velumuri, akhil.goyal

Security library currently only has support for IPSec protocol.
This patchset defines structures for pdcp protocol in rte_security and provide a sample driver implementation for lookaside protocol offload to support PDCP.

Changes in v6:
- fix doxygen and clang compilation errors

Changes in v5:
- corrected comments in xform structure.

changes in v4:
- added capability and setting for packet ordering and duplicate detection.
- some fixes in driver.

changes in v3:
removed checkpatch warnings.

changes in v2:
- removed hfn override. Will be added later when it is supported
- added seq number size = 18bits
- coding style issues corrected in pdcp.h
- updated documentation for specifying the 3GPP specification reference
- removed some duplicate code in dpaa2_sec_dpseci.c


Akhil Goyal (3):
  security: support pdcp protocol
  crypto/dpaa2_sec: add sample pdcp descriptor apis
  crypto/dpaa2_sec: support pdcp offload

 doc/guides/prog_guide/rte_security.rst      |  107 +-
 drivers/crypto/dpaa2_sec/dpaa2_sec_dpseci.c |  258 +++
 drivers/crypto/dpaa2_sec/dpaa2_sec_priv.h   |  208 +-
 drivers/crypto/dpaa2_sec/hw/desc.h          |    2 +-
 drivers/crypto/dpaa2_sec/hw/desc/pdcp.h     | 2796 +++++++++++++++++++++++++++
 lib/librte_security/rte_security.c          |    4 +
 lib/librte_security/rte_security.h          |   90 +
 7 files changed, 3449 insertions(+), 16 deletions(-)
 create mode 100644 drivers/crypto/dpaa2_sec/hw/desc/pdcp.h

-- 
2.7.4

^ permalink raw reply	[flat|nested] 41+ messages in thread

* [dpdk-dev] [PATCH v6 1/3] security: support pdcp protocol
  2018-10-22  7:12         ` [dpdk-dev] [PATCH v6 " Hemant Agrawal
@ 2018-10-22  7:12           ` Hemant Agrawal
  2018-10-22  7:12           ` [dpdk-dev] [PATCH v6 2/3] crypto/dpaa2_sec: add sample pdcp descriptor apis Hemant Agrawal
  2018-10-22  7:12           ` [dpdk-dev] [PATCH v6 3/3] crypto/dpaa2_sec: support pdcp offload Hemant Agrawal
  2 siblings, 0 replies; 41+ messages in thread
From: Hemant Agrawal @ 2018-10-22  7:12 UTC (permalink / raw)
  To: dev
  Cc: thomas, pablo.de.lara.guarch, radu.nicolau, jerin.jacob,
	narayanaprasad.athreya, Shally.Verma, Anoob.Joseph,
	Vidya.Velumuri, akhil.goyal

From: Akhil Goyal <akhil.goyal@nxp.com>

Packet Data Convergence Protocol (PDCP) is added in rte_security
for 3GPP TS 36.323 for LTE.

The patchset provide the structure definitions for configuring the
PDCP sessions and relevant documentation is added.

Signed-off-by: Hemant Agrawal <hemant.agrawal@nxp.com>
Signed-off-by: Akhil Goyal <akhil.goyal@nxp.com>
Acked-by: Anoob Joseph <anoob.joseph@caviumnetworks.com>
---
 doc/guides/prog_guide/rte_security.rst | 107 ++++++++++++++++++++++++++++++---
 lib/librte_security/rte_security.c     |   4 ++
 lib/librte_security/rte_security.h     |  90 +++++++++++++++++++++++++++
 3 files changed, 194 insertions(+), 7 deletions(-)

diff --git a/doc/guides/prog_guide/rte_security.rst b/doc/guides/prog_guide/rte_security.rst
index 0812abe..6c7d8ee 100644
--- a/doc/guides/prog_guide/rte_security.rst
+++ b/doc/guides/prog_guide/rte_security.rst
@@ -10,8 +10,8 @@ The security library provides a framework for management and provisioning
 of security protocol operations offloaded to hardware based devices. The
 library defines generic APIs to create and free security sessions which can
 support full protocol offload as well as inline crypto operation with
-NIC or crypto devices. The framework currently only supports the IPSec protocol
-and associated operations, other protocols will be added in future.
+NIC or crypto devices. The framework currently only supports the IPsec and PDCP
+protocol and associated operations, other protocols will be added in future.
 
 Design Principles
 -----------------
@@ -253,6 +253,49 @@ for any protocol header addition.
         +--------|--------+
                  V
 
+PDCP Flow Diagram
+~~~~~~~~~~~~~~~~~
+
+Based on 3GPP TS 36.323 Evolved Universal Terrestrial Radio Access (E-UTRA);
+Packet Data Convergence Protocol (PDCP) specification
+
+.. code-block:: c
+
+        Transmitting PDCP Entity          Receiving PDCP Entity
+                  |                                   ^
+                  |                       +-----------|-----------+
+                  V                       | In order delivery and |
+        +---------|----------+            | Duplicate detection   |
+        | Sequence Numbering |            |  (Data Plane only)    |
+        +---------|----------+            +-----------|-----------+
+                  |                                   |
+        +---------|----------+            +-----------|----------+
+        | Header Compression*|            | Header Decompression*|
+        | (Data-Plane only)  |            |   (Data Plane only)  |
+        +---------|----------+            +-----------|----------+
+                  |                                   |
+        +---------|-----------+           +-----------|----------+
+        | Integrity Protection|           |Integrity Verification|
+        | (Control Plane only)|           | (Control Plane only) |
+        +---------|-----------+           +-----------|----------+
+        +---------|-----------+            +----------|----------+
+        |     Ciphering       |            |     Deciphering     |
+        +---------|-----------+            +----------|----------+
+        +---------|-----------+            +----------|----------+
+        |   Add PDCP header   |            | Remove PDCP Header  |
+        +---------|-----------+            +----------|----------+
+                  |                                   |
+                  +----------------->>----------------+
+
+
+.. note::
+
+    * Header Compression and decompression are not supported currently.
+
+Just like IPsec, in case of PDCP also header addition/deletion, cipher/
+de-cipher, integrity protection/verification is done based on the action
+type chosen.
+
 Device Features and Capabilities
 ---------------------------------
 
@@ -271,7 +314,7 @@ structure in the *DPDK API Reference*.
 
 Each driver (crypto or ethernet) defines its own private array of capabilities
 for the operations it supports. Below is an example of the capabilities for a
-PMD which supports the IPSec protocol.
+PMD which supports the IPsec and PDCP protocol.
 
 .. code-block:: c
 
@@ -298,6 +341,24 @@ PMD which supports the IPSec protocol.
                 },
                 .crypto_capabilities = pmd_capabilities
         },
+        { /* PDCP Lookaside Protocol offload Data Plane */
+                .action = RTE_SECURITY_ACTION_TYPE_LOOKASIDE_PROTOCOL,
+                .protocol = RTE_SECURITY_PROTOCOL_PDCP,
+                .pdcp = {
+                        .domain = RTE_SECURITY_PDCP_MODE_DATA,
+                        .capa_flags = 0
+                },
+                .crypto_capabilities = pmd_capabilities
+        },
+        { /* PDCP Lookaside Protocol offload Control */
+                .action = RTE_SECURITY_ACTION_TYPE_LOOKASIDE_PROTOCOL,
+                .protocol = RTE_SECURITY_PROTOCOL_PDCP,
+                .pdcp = {
+                        .domain = RTE_SECURITY_PDCP_MODE_CONTROL,
+                        .capa_flags = 0
+                },
+                .crypto_capabilities = pmd_capabilities
+        },
         {
                 .action = RTE_SECURITY_ACTION_TYPE_NONE
         }
@@ -429,6 +490,7 @@ Security Session configuration structure is defined as ``rte_security_session_co
         union {
                 struct rte_security_ipsec_xform ipsec;
                 struct rte_security_macsec_xform macsec;
+                struct rte_security_pdcp_xform pdcp;
         };
         /**< Configuration parameters for security session */
         struct rte_crypto_sym_xform *crypto_xform;
@@ -463,15 +525,17 @@ The ``rte_security_session_protocol`` is defined as
 .. code-block:: c
 
     enum rte_security_session_protocol {
-        RTE_SECURITY_PROTOCOL_IPSEC,
+        RTE_SECURITY_PROTOCOL_IPSEC = 1,
         /**< IPsec Protocol */
         RTE_SECURITY_PROTOCOL_MACSEC,
         /**< MACSec Protocol */
+        RTE_SECURITY_PROTOCOL_PDCP,
+        /**< PDCP Protocol */
     };
 
-Currently the library defines configuration parameters for IPSec only. For other
-protocols like MACSec, structures and enums are defined as place holders which
-will be updated in the future.
+Currently the library defines configuration parameters for IPsec and PDCP only.
+For other protocols like MACSec, structures and enums are defined as place holders
+which will be updated in the future.
 
 IPsec related configuration parameters are defined in ``rte_security_ipsec_xform``
 
@@ -494,6 +558,35 @@ IPsec related configuration parameters are defined in ``rte_security_ipsec_xform
         /**< Tunnel parameters, NULL for transport mode */
     };
 
+PDCP related configuration parameters are defined in ``rte_security_pdcp_xform``
+
+.. code-block:: c
+
+    struct rte_security_pdcp_xform {
+        int8_t bearer;	/**< PDCP bearer ID */
+        /**< Enable in order delivery, this field shall be set only if
+         * driver/HW is capable. See RTE_SECURITY_PDCP_ORDERING_CAP.
+         */
+        uint8_t en_ordering;
+        /**< Notify driver/HW to detect and remove duplicate packets.
+         * This field should be set only when driver/hw is capable.
+         * See RTE_SECURITY_PDCP_DUP_DETECT_CAP.
+         */
+        uint8_t remove_duplicates;
+        /**< PDCP mode of operation: Control or data */
+        enum rte_security_pdcp_domain domain;
+        /**< PDCP Frame Direction 0:UL 1:DL */
+        enum rte_security_pdcp_direction pkt_dir;
+        /**< Sequence number size, 5/7/12/15/18 */
+        enum rte_security_pdcp_sn_size sn_size;
+        /**< Starting Hyper Frame Number to be used together with the SN
+         * from the PDCP frames
+         */
+        uint32_t hfn;
+        /**< HFN Threshold for key renegotiation */
+        uint32_t hfn_threshold;
+    };
+
 
 Security API
 ~~~~~~~~~~~~
diff --git a/lib/librte_security/rte_security.c b/lib/librte_security/rte_security.c
index 1954960..c6355de 100644
--- a/lib/librte_security/rte_security.c
+++ b/lib/librte_security/rte_security.c
@@ -131,6 +131,10 @@ rte_security_capability_get(struct rte_security_ctx *instance,
 					capability->ipsec.direction ==
 							idx->ipsec.direction)
 					return capability;
+			} else if (idx->protocol == RTE_SECURITY_PROTOCOL_PDCP) {
+				if (capability->pdcp.domain ==
+							idx->pdcp.domain)
+					return capability;
 			}
 		}
 	}
diff --git a/lib/librte_security/rte_security.h b/lib/librte_security/rte_security.h
index b0d1b97..a60e9d7 100644
--- a/lib/librte_security/rte_security.h
+++ b/lib/librte_security/rte_security.h
@@ -207,6 +207,64 @@ struct rte_security_macsec_xform {
 };
 
 /**
+ * PDCP Mode of session
+ */
+enum rte_security_pdcp_domain {
+	RTE_SECURITY_PDCP_MODE_CONTROL,	/**< PDCP control plane */
+	RTE_SECURITY_PDCP_MODE_DATA,	/**< PDCP data plane */
+};
+
+/** PDCP Frame direction */
+enum rte_security_pdcp_direction {
+	RTE_SECURITY_PDCP_UPLINK,	/**< Uplink */
+	RTE_SECURITY_PDCP_DOWNLINK,	/**< Downlink */
+};
+
+/** PDCP Sequence Number Size selectors */
+enum rte_security_pdcp_sn_size {
+	RTE_SECURITY_PDCP_SN_SIZE_5 = 5,
+	/**< PDCP_SN_SIZE_5: 5bit sequence number */
+	RTE_SECURITY_PDCP_SN_SIZE_7 = 7,
+	/**< PDCP_SN_SIZE_7: 7bit sequence number */
+	RTE_SECURITY_PDCP_SN_SIZE_12 = 12,
+	/**< PDCP_SN_SIZE_12: 12bit sequence number */
+	RTE_SECURITY_PDCP_SN_SIZE_15 = 15,
+	/**< PDCP_SN_SIZE_15: 15bit sequence number */
+	RTE_SECURITY_PDCP_SN_SIZE_18 = 18
+	/**< PDCP_SN_SIZE_18: 18bit sequence number */
+};
+
+/**
+ * PDCP security association configuration data.
+ *
+ * This structure contains data required to create a PDCP security session.
+ */
+struct rte_security_pdcp_xform {
+	int8_t bearer;	/**< PDCP bearer ID */
+	uint8_t en_ordering;
+	/**< Enable in order delivery, this field shall be set only if
+	 * driver/HW is capable. See RTE_SECURITY_PDCP_ORDERING_CAP.
+	 */
+	uint8_t remove_duplicates;
+	/**< Notify driver/HW to detect and remove duplicate packets.
+	 * This field should be set only when driver/hw is capable.
+	 * See RTE_SECURITY_PDCP_DUP_DETECT_CAP.
+	 */
+	enum rte_security_pdcp_domain domain;
+	/**< PDCP mode of operation: Control or data */
+	enum rte_security_pdcp_direction pkt_dir;
+	/**< PDCP Frame Direction 0:UL 1:DL */
+	enum rte_security_pdcp_sn_size sn_size;
+	/**< Sequence number size, 5/7/12/15/18 */
+	uint32_t hfn;
+	/**< Starting Hyper Frame Number to be used together with the SN
+	 * from the PDCP frames
+	 */
+	uint32_t hfn_threshold;
+	/**< HFN Threshold for key renegotiation */
+};
+
+/**
  * Security session action type.
  */
 enum rte_security_session_action_type {
@@ -232,6 +290,8 @@ enum rte_security_session_protocol {
 	/**< IPsec Protocol */
 	RTE_SECURITY_PROTOCOL_MACSEC,
 	/**< MACSec Protocol */
+	RTE_SECURITY_PROTOCOL_PDCP,
+	/**< PDCP Protocol */
 };
 
 /**
@@ -246,6 +306,7 @@ struct rte_security_session_conf {
 	union {
 		struct rte_security_ipsec_xform ipsec;
 		struct rte_security_macsec_xform macsec;
+		struct rte_security_pdcp_xform pdcp;
 	};
 	/**< Configuration parameters for security session */
 	struct rte_crypto_sym_xform *crypto_xform;
@@ -413,6 +474,10 @@ struct rte_security_ipsec_stats {
 
 };
 
+struct rte_security_pdcp_stats {
+	uint64_t reserved;
+};
+
 struct rte_security_stats {
 	enum rte_security_session_protocol protocol;
 	/**< Security protocol to be configured */
@@ -421,6 +486,7 @@ struct rte_security_stats {
 	union {
 		struct rte_security_macsec_stats macsec;
 		struct rte_security_ipsec_stats ipsec;
+		struct rte_security_pdcp_stats pdcp;
 	};
 };
 
@@ -465,6 +531,13 @@ struct rte_security_capability {
 			int dummy;
 		} macsec;
 		/**< MACsec capability */
+		struct {
+			enum rte_security_pdcp_domain domain;
+			/** < PDCP mode of operation: Control or data */
+			uint32_t capa_flags;
+			/** < Capabilitity flags, see RTE_SECURITY_PDCP_* */
+		} pdcp;
+		/**< PDCP capability */
 	};
 
 	const struct rte_cryptodev_capabilities *crypto_capabilities;
@@ -474,6 +547,19 @@ struct rte_security_capability {
 	/**< Device offload flags */
 };
 
+/**< Underlying Hardware/driver which support PDCP may or may not support
+ * packet ordering. Set RTE_SECURITY_PDCP_ORDERING_CAP if it support.
+ * If it is not set, driver/HW assumes packets received are in order
+ * and it will be application's responsibility to maintain ordering.
+ */
+#define RTE_SECURITY_PDCP_ORDERING_CAP		0x00000001
+
+/**< Underlying Hardware/driver which support PDCP may or may not detect
+ * duplicate packet. Set RTE_SECURITY_PDCP_DUP_DETECT_CAP if it support.
+ * If it is not set, driver/HW assumes there is no duplicate packet received.
+ */
+#define RTE_SECURITY_PDCP_DUP_DETECT_CAP	0x00000002
+
 #define RTE_SECURITY_TX_OLOAD_NEED_MDATA	0x00000001
 /**< HW needs metadata update, see rte_security_set_pkt_metadata().
  */
@@ -506,6 +592,10 @@ struct rte_security_capability_idx {
 			enum rte_security_ipsec_sa_mode mode;
 			enum rte_security_ipsec_sa_direction direction;
 		} ipsec;
+		struct {
+			enum rte_security_pdcp_domain domain;
+			uint32_t capa_flags;
+		} pdcp;
 	};
 };
 
-- 
2.7.4

^ permalink raw reply	[flat|nested] 41+ messages in thread

* [dpdk-dev] [PATCH v6 2/3] crypto/dpaa2_sec: add sample pdcp descriptor apis
  2018-10-22  7:12         ` [dpdk-dev] [PATCH v6 " Hemant Agrawal
  2018-10-22  7:12           ` [dpdk-dev] [PATCH v6 1/3] security: support pdcp protocol Hemant Agrawal
@ 2018-10-22  7:12           ` Hemant Agrawal
  2018-10-22  7:12           ` [dpdk-dev] [PATCH v6 3/3] crypto/dpaa2_sec: support pdcp offload Hemant Agrawal
  2 siblings, 0 replies; 41+ messages in thread
From: Hemant Agrawal @ 2018-10-22  7:12 UTC (permalink / raw)
  To: dev
  Cc: thomas, pablo.de.lara.guarch, radu.nicolau, jerin.jacob,
	narayanaprasad.athreya, Shally.Verma, Anoob.Joseph,
	Vidya.Velumuri, akhil.goyal, Horia Geanta Neag, Alex Porosanu

From: Akhil Goyal <akhil.goyal@nxp.com>

DPAA2 SEC platform can support look aside protocol
offload for PDCP protocol.

The relevant APIs for configuring the hardware for PDCP
is added for various modes and crypto algorithms.

Signed-off-by: Hemant Agrawal <hemant.agrawal@nxp.com>
Signed-off-by: Horia Geanta Neag <horia.geanta@nxp.com>
Signed-off-by: Alex Porosanu <alexandru.porosanu@nxp.com>
Signed-off-by: Akhil Goyal <akhil.goyal@nxp.com>
---
 drivers/crypto/dpaa2_sec/hw/desc.h      |    2 +-
 drivers/crypto/dpaa2_sec/hw/desc/pdcp.h | 2796 +++++++++++++++++++++++++++++++
 2 files changed, 2797 insertions(+), 1 deletion(-)
 create mode 100644 drivers/crypto/dpaa2_sec/hw/desc/pdcp.h

diff --git a/drivers/crypto/dpaa2_sec/hw/desc.h b/drivers/crypto/dpaa2_sec/hw/desc.h
index ca94ea3..5d99dd8 100644
--- a/drivers/crypto/dpaa2_sec/hw/desc.h
+++ b/drivers/crypto/dpaa2_sec/hw/desc.h
@@ -868,7 +868,7 @@
 #define OP_PCL_LTE_MIXED_AUTH_SHIFT	0
 #define OP_PCL_LTE_MIXED_AUTH_MASK	(3 << OP_PCL_LTE_MIXED_AUTH_SHIFT)
 #define OP_PCL_LTE_MIXED_ENC_SHIFT	8
-#define OP_PCL_LTE_MIXED_ENC_MASK	(3 < OP_PCL_LTE_MIXED_ENC_SHIFT)
+#define OP_PCL_LTE_MIXED_ENC_MASK	(3 << OP_PCL_LTE_MIXED_ENC_SHIFT)
 #define OP_PCL_LTE_MIXED_AUTH_NULL	(OP_PCL_LTE_NULL << \
 					 OP_PCL_LTE_MIXED_AUTH_SHIFT)
 #define OP_PCL_LTE_MIXED_AUTH_SNOW	(OP_PCL_LTE_SNOW << \
diff --git a/drivers/crypto/dpaa2_sec/hw/desc/pdcp.h b/drivers/crypto/dpaa2_sec/hw/desc/pdcp.h
new file mode 100644
index 0000000..719ef60
--- /dev/null
+++ b/drivers/crypto/dpaa2_sec/hw/desc/pdcp.h
@@ -0,0 +1,2796 @@
+/*
+ * Copyright 2008-2013 Freescale Semiconductor, Inc.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause or GPL-2.0+
+ */
+
+#ifndef __DESC_PDCP_H__
+#define __DESC_PDCP_H__
+
+#include "hw/rta.h"
+#include "common.h"
+
+/**
+ * DOC: PDCP Shared Descriptor Constructors
+ *
+ * Shared descriptors for PDCP protocol.
+ */
+
+/**
+ * PDCP_NULL_MAX_FRAME_LEN - The maximum frame frame length that is supported by
+ *                           PDCP NULL protocol.
+ */
+#define PDCP_NULL_MAX_FRAME_LEN		0x00002FFF
+
+/**
+ * PDCP_MAC_I_LEN - The length of the MAC-I for PDCP protocol operation
+ */
+#define PDCP_MAC_I_LEN			0x00000004
+
+/**
+ * PDCP_MAX_FRAME_LEN_STATUS - The status returned in FD status/command field in
+ *                             case the input frame is larger than
+ *                             PDCP_NULL_MAX_FRAME_LEN.
+ */
+#define PDCP_MAX_FRAME_LEN_STATUS	0xF1
+
+/**
+ * PDCP_C_PLANE_SN_MASK - This mask is used in the PDCP descriptors for
+ *                        extracting the sequence number (SN) from the PDCP
+ *                        Control Plane header. For PDCP Control Plane, the SN
+ *                        is constant (5 bits) as opposed to PDCP Data Plane
+ *                        (7/12/15 bits).
+ */
+#define PDCP_C_PLANE_SN_MASK		0x1F000000
+#define PDCP_C_PLANE_SN_MASK_BE		0x0000001F
+
+/**
+ * PDCP_U_PLANE_15BIT_SN_MASK - This mask is used in the PDCP descriptors for
+ *                              extracting the sequence number (SN) from the
+ *                              PDCP User Plane header. For PDCP Control Plane,
+ *                              the SN is constant (5 bits) as opposed to PDCP
+ *                              Data Plane (7/12/15 bits).
+ */
+#define PDCP_U_PLANE_15BIT_SN_MASK	0xFF7F0000
+#define PDCP_U_PLANE_15BIT_SN_MASK_BE	0x00007FFF
+
+/**
+ * PDCP_BEARER_MASK - This mask is used masking out the bearer for PDCP
+ *                    processing with SNOW f9 in LTE.
+ *
+ * The value on which this mask is applied is formatted as below:
+ *     Count-C (32 bit) | Bearer (5 bit) | Direction (1 bit) | 0 (26 bits)
+ *
+ * Applying this mask is done for creating the upper 64 bits of the IV needed
+ * for SNOW f9.
+ *
+ * The lower 32 bits of the mask are used for masking the direction for AES
+ * CMAC IV.
+ */
+#define PDCP_BEARER_MASK		0x00000004FFFFFFFFull
+#define PDCP_BEARER_MASK_BE		0xFFFFFFFF04000000ull
+
+/**
+ * PDCP_DIR_MASK - This mask is used masking out the direction for PDCP
+ *                 processing with SNOW f9 in LTE.
+ *
+ * The value on which this mask is applied is formatted as below:
+ *     Bearer (5 bit) | Direction (1 bit) | 0 (26 bits)
+ *
+ * Applying this mask is done for creating the lower 32 bits of the IV needed
+ * for SNOW f9.
+ *
+ * The upper 32 bits of the mask are used for masking the direction for AES
+ * CMAC IV.
+ */
+#define PDCP_DIR_MASK			0x00000000000000F8ull
+#define PDCP_DIR_MASK_BE			0xF800000000000000ull
+
+/**
+ * PDCP_NULL_INT_MAC_I_VAL - The value of the PDCP PDU MAC-I in case NULL
+ *                           integrity is used.
+ */
+
+#define PDCP_NULL_INT_MAC_I_VAL		0x00000000
+
+/**
+ * PDCP_NULL_INT_ICV_CHECK_FAILED_STATUS - The status used to report ICV check
+ *                                         failed in case of NULL integrity
+ *                                         Control Plane processing.
+ */
+#define PDCP_NULL_INT_ICV_CHECK_FAILED_STATUS	0x0A
+/**
+ * PDCP_DPOVRD_HFN_OV_EN - Value to be used in the FD status/cmd field to
+ *                         indicate the HFN override mechanism is active for the
+ *                         frame.
+ */
+#define PDCP_DPOVRD_HFN_OV_EN		0x80000000
+
+/**
+ * PDCP_P4080REV2_HFN_OV_BUFLEN - The length in bytes of the supplementary space
+ *                                that must be provided by the user at the
+ *                                beginning of the input frame buffer for
+ *                                P4080 REV 2.
+ *
+ * The format of the frame buffer is the following:
+ *
+ *  |<---PDCP_P4080REV2_HFN_OV_BUFLEN-->|
+ * //===================================||============||==============\\
+ * || PDCP_DPOVRD_HFN_OV_EN | HFN value || PDCP Header|| PDCP Payload ||
+ * \\===================================||============||==============//
+ *
+ * If HFN override mechanism is not desired, then the MSB of the first 4 bytes
+ * must be set to 0b.
+ */
+#define PDCP_P4080REV2_HFN_OV_BUFLEN	4
+
+/**
+ * enum cipher_type_pdcp - Type selectors for cipher types in PDCP protocol OP
+ *                         instructions.
+ * @PDCP_CIPHER_TYPE_NULL: NULL
+ * @PDCP_CIPHER_TYPE_SNOW: SNOW F8
+ * @PDCP_CIPHER_TYPE_AES: AES
+ * @PDCP_CIPHER_TYPE_ZUC: ZUCE
+ * @PDCP_CIPHER_TYPE_INVALID: invalid option
+ */
+enum cipher_type_pdcp {
+	PDCP_CIPHER_TYPE_NULL,
+	PDCP_CIPHER_TYPE_SNOW,
+	PDCP_CIPHER_TYPE_AES,
+	PDCP_CIPHER_TYPE_ZUC,
+	PDCP_CIPHER_TYPE_INVALID
+};
+
+/**
+ * enum auth_type_pdcp - Type selectors for integrity types in PDCP protocol OP
+ *                       instructions.
+ * @PDCP_AUTH_TYPE_NULL: NULL
+ * @PDCP_AUTH_TYPE_SNOW: SNOW F9
+ * @PDCP_AUTH_TYPE_AES: AES CMAC
+ * @PDCP_AUTH_TYPE_ZUC: ZUCA
+ * @PDCP_AUTH_TYPE_INVALID: invalid option
+ */
+enum auth_type_pdcp {
+	PDCP_AUTH_TYPE_NULL,
+	PDCP_AUTH_TYPE_SNOW,
+	PDCP_AUTH_TYPE_AES,
+	PDCP_AUTH_TYPE_ZUC,
+	PDCP_AUTH_TYPE_INVALID
+};
+
+/**
+ * enum pdcp_dir - Type selectors for direction for PDCP protocol
+ * @PDCP_DIR_UPLINK: uplink direction
+ * @PDCP_DIR_DOWNLINK: downlink direction
+ * @PDCP_DIR_INVALID: invalid option
+ */
+enum pdcp_dir {
+	PDCP_DIR_UPLINK = 0,
+	PDCP_DIR_DOWNLINK = 1,
+	PDCP_DIR_INVALID
+};
+
+/**
+ * enum pdcp_plane - PDCP domain selectors
+ * @PDCP_CONTROL_PLANE: Control Plane
+ * @PDCP_DATA_PLANE: Data Plane
+ * @PDCP_SHORT_MAC: Short MAC
+ */
+enum pdcp_plane {
+	PDCP_CONTROL_PLANE,
+	PDCP_DATA_PLANE,
+	PDCP_SHORT_MAC
+};
+
+/**
+ * enum pdcp_sn_size - Sequence Number Size selectors for PDCP protocol
+ * @PDCP_SN_SIZE_5: 5bit sequence number
+ * @PDCP_SN_SIZE_7: 7bit sequence number
+ * @PDCP_SN_SIZE_12: 12bit sequence number
+ * @PDCP_SN_SIZE_15: 15bit sequence number
+ * @PDCP_SN_SIZE_18: 18bit sequence number
+ */
+enum pdcp_sn_size {
+	PDCP_SN_SIZE_5 = 5,
+	PDCP_SN_SIZE_7 = 7,
+	PDCP_SN_SIZE_12 = 12,
+	PDCP_SN_SIZE_15 = 15
+};
+
+/*
+ * PDCP Control Plane Protocol Data Blocks
+ */
+#define PDCP_C_PLANE_PDB_HFN_SHIFT		5
+#define PDCP_C_PLANE_PDB_BEARER_SHIFT		27
+#define PDCP_C_PLANE_PDB_DIR_SHIFT		26
+#define PDCP_C_PLANE_PDB_HFN_THR_SHIFT		5
+
+#define PDCP_U_PLANE_PDB_OPT_SHORT_SN		0x2
+#define PDCP_U_PLANE_PDB_OPT_15B_SN		0x4
+#define PDCP_U_PLANE_PDB_SHORT_SN_HFN_SHIFT	7
+#define PDCP_U_PLANE_PDB_LONG_SN_HFN_SHIFT	12
+#define PDCP_U_PLANE_PDB_15BIT_SN_HFN_SHIFT	15
+#define PDCP_U_PLANE_PDB_BEARER_SHIFT		27
+#define PDCP_U_PLANE_PDB_DIR_SHIFT		26
+#define PDCP_U_PLANE_PDB_SHORT_SN_HFN_THR_SHIFT	7
+#define PDCP_U_PLANE_PDB_LONG_SN_HFN_THR_SHIFT	12
+#define PDCP_U_PLANE_PDB_15BIT_SN_HFN_THR_SHIFT	15
+
+struct pdcp_pdb {
+	union {
+		uint32_t opt;
+		uint32_t rsvd;
+	} opt_res;
+	uint32_t hfn_res;	/* HyperFrame number,(27, 25 or 21 bits),
+				 * left aligned & right-padded with zeros.
+				 */
+	uint32_t bearer_dir_res;/* Bearer(5 bits), packet direction (1 bit),
+				 * left aligned & right-padded with zeros.
+				 */
+	uint32_t hfn_thr_res;	/* HyperFrame number threshold (27, 25 or 21
+				 * bits), left aligned & right-padded with
+				 * zeros.
+				 */
+};
+
+/*
+ * PDCP internal PDB types
+ */
+enum pdb_type_e {
+	PDCP_PDB_TYPE_NO_PDB,
+	PDCP_PDB_TYPE_FULL_PDB,
+	PDCP_PDB_TYPE_REDUCED_PDB,
+	PDCP_PDB_TYPE_INVALID
+};
+
+/*
+ * Function for appending the portion of a PDCP Control Plane shared descriptor
+ * which performs NULL encryption and integrity (i.e. copies the input frame
+ * to the output frame, appending 32 bits of zeros at the end (MAC-I for
+ * NULL integrity).
+ */
+static inline int
+pdcp_insert_cplane_null_op(struct program *p,
+			   bool swap __maybe_unused,
+			   struct alginfo *cipherdata __maybe_unused,
+			   struct alginfo *authdata __maybe_unused,
+			   unsigned int dir,
+			   unsigned char era_2_sw_hfn_ovrd __maybe_unused)
+{
+	LABEL(local_offset);
+	REFERENCE(move_cmd_read_descbuf);
+	REFERENCE(move_cmd_write_descbuf);
+
+	if (rta_sec_era > RTA_SEC_ERA_2) {
+		MATHB(p, SEQINSZ, ADD, ZERO, VSEQINSZ, 4, 0);
+		if (dir == OP_TYPE_ENCAP_PROTOCOL)
+			MATHB(p, SEQINSZ, ADD, PDCP_MAC_I_LEN, VSEQOUTSZ, 4,
+			      IMMED2);
+		else
+			MATHB(p, SEQINSZ, SUB, PDCP_MAC_I_LEN, VSEQOUTSZ, 4,
+			      IMMED2);
+	} else {
+		MATHB(p, SEQINSZ, ADD, ONE, VSEQINSZ, 4, 0);
+		MATHB(p, VSEQINSZ, SUB, ONE, VSEQINSZ, 4, 0);
+
+		if (dir == OP_TYPE_ENCAP_PROTOCOL) {
+			MATHB(p, SEQINSZ, ADD, PDCP_MAC_I_LEN, VSEQOUTSZ, 4,
+			      IMMED2);
+			MATHB(p, VSEQINSZ, SUB, ONE, MATH0, 4, 0);
+		} else {
+			MATHB(p, VSEQINSZ, SUB, PDCP_MAC_I_LEN, VSEQINSZ, 4,
+			      IMMED2);
+			MATHB(p, SEQINSZ, SUB, PDCP_MAC_I_LEN, VSEQOUTSZ, 4,
+			      IMMED2);
+			MATHB(p, VSEQOUTSZ, SUB, ONE, MATH0, 4, 0);
+		}
+
+		MATHB(p, MATH0, ADD, ONE, MATH0, 4, 0);
+
+		/*
+		 * Since MOVELEN is available only starting with
+		 * SEC ERA 3, use poor man's MOVELEN: create a MOVE
+		 * command dynamically by writing the length from M1 by
+		 * OR-ing the command in the M1 register and MOVE the
+		 * result into the descriptor buffer. Care must be taken
+		 * wrt. the location of the command because of SEC
+		 * pipelining. The actual MOVEs are written at the end
+		 * of the descriptor due to calculations needed on the
+		 * offset in the descriptor for the MOVE command.
+		 */
+		move_cmd_read_descbuf = MOVE(p, DESCBUF, 0, MATH0, 0, 6,
+					     IMMED);
+		move_cmd_write_descbuf = MOVE(p, MATH0, 0, DESCBUF, 0, 8,
+					      WAITCOMP | IMMED);
+	}
+	MATHB(p, VSEQINSZ, SUB, PDCP_NULL_MAX_FRAME_LEN, NONE, 4,
+	      IMMED2);
+	JUMP(p, PDCP_MAX_FRAME_LEN_STATUS, HALT_STATUS, ALL_FALSE, MATH_N);
+
+	if (rta_sec_era > RTA_SEC_ERA_2) {
+		if (dir == OP_TYPE_ENCAP_PROTOCOL)
+			MATHB(p, VSEQINSZ, ADD, ZERO, MATH0, 4, 0);
+		else
+			MATHB(p, VSEQOUTSZ, ADD, ZERO, MATH0, 4, 0);
+	}
+	SEQFIFOSTORE(p, MSG, 0, 0, VLF);
+	SEQFIFOLOAD(p, MSG1, 0, VLF | LAST1 | FLUSH1);
+
+	if (rta_sec_era > RTA_SEC_ERA_2) {
+		MOVE(p, AB1, 0, OFIFO, 0, MATH0, 0);
+	} else {
+		SET_LABEL(p, local_offset);
+
+		/* Shut off automatic Info FIFO entries */
+		LOAD(p, 0, DCTRL, LDOFF_DISABLE_AUTO_NFIFO, 0, IMMED);
+		/* Placeholder for MOVE command with length from M1 register */
+		MOVE(p, IFIFOAB1, 0, OFIFO, 0, 0, IMMED);
+		/* Enable automatic Info FIFO entries */
+		LOAD(p, 0, DCTRL, LDOFF_ENABLE_AUTO_NFIFO, 0, IMMED);
+	}
+
+	if (dir == OP_TYPE_ENCAP_PROTOCOL) {
+		MATHB(p, MATH1, XOR, MATH1, MATH0, 8, 0);
+		MOVE(p, MATH0, 0, OFIFO, 0, 4, IMMED);
+	}
+
+	if (rta_sec_era < RTA_SEC_ERA_3) {
+		PATCH_MOVE(p, move_cmd_read_descbuf, local_offset);
+		PATCH_MOVE(p, move_cmd_write_descbuf, local_offset);
+	}
+
+	return 0;
+}
+
+static inline int
+insert_copy_frame_op(struct program *p,
+		     struct alginfo *cipherdata __maybe_unused,
+		     unsigned int dir __maybe_unused)
+{
+	LABEL(local_offset);
+	REFERENCE(move_cmd_read_descbuf);
+	REFERENCE(move_cmd_write_descbuf);
+
+	if (rta_sec_era > RTA_SEC_ERA_2) {
+		MATHB(p, SEQINSZ, ADD, ZERO, VSEQINSZ,  4, 0);
+		MATHB(p, SEQINSZ, ADD, ZERO, VSEQOUTSZ,  4, 0);
+	} else {
+		MATHB(p, SEQINSZ, ADD, ONE, VSEQINSZ,  4, 0);
+		MATHB(p, VSEQINSZ, SUB, ONE, VSEQINSZ,  4, 0);
+		MATHB(p, SEQINSZ, ADD, ONE, VSEQOUTSZ,  4, 0);
+		MATHB(p, VSEQOUTSZ, SUB, ONE, VSEQOUTSZ,  4, 0);
+		MATHB(p, VSEQINSZ, SUB, ONE, MATH0,  4, 0);
+		MATHB(p, MATH0, ADD, ONE, MATH0,  4, 0);
+
+		/*
+		 * Since MOVELEN is available only starting with
+		 * SEC ERA 3, use poor man's MOVELEN: create a MOVE
+		 * command dynamically by writing the length from M1 by
+		 * OR-ing the command in the M1 register and MOVE the
+		 * result into the descriptor buffer. Care must be taken
+		 * wrt. the location of the command because of SEC
+		 * pipelining. The actual MOVEs are written at the end
+		 * of the descriptor due to calculations needed on the
+		 * offset in the descriptor for the MOVE command.
+		 */
+		move_cmd_read_descbuf = MOVE(p, DESCBUF, 0, MATH0, 0, 6,
+					     IMMED);
+		move_cmd_write_descbuf = MOVE(p, MATH0, 0, DESCBUF, 0, 8,
+					      WAITCOMP | IMMED);
+	}
+	MATHB(p, SEQINSZ, SUB, PDCP_NULL_MAX_FRAME_LEN, NONE,  4,
+	      IFB | IMMED2);
+	JUMP(p, PDCP_MAX_FRAME_LEN_STATUS, HALT_STATUS, ALL_FALSE, MATH_N);
+
+	if (rta_sec_era > RTA_SEC_ERA_2)
+		MATHB(p, VSEQINSZ, ADD, ZERO, MATH0,  4, 0);
+
+	SEQFIFOLOAD(p, MSG1, 0, VLF | LAST1 | FLUSH1);
+	if (rta_sec_era > RTA_SEC_ERA_2) {
+		MOVE(p, AB1, 0, OFIFO, 0, MATH0, 0);
+	} else {
+		SET_LABEL(p, local_offset);
+
+		/* Shut off automatic Info FIFO entries */
+		LOAD(p, 0, DCTRL, LDOFF_DISABLE_AUTO_NFIFO, 0, IMMED);
+
+		/* Placeholder for MOVE command with length from M0 register */
+		MOVE(p, IFIFOAB1, 0, OFIFO, 0, 0, IMMED);
+
+		/* Enable automatic Info FIFO entries */
+		LOAD(p, 0, DCTRL, LDOFF_ENABLE_AUTO_NFIFO, 0, IMMED);
+	}
+
+	SEQFIFOSTORE(p, MSG, 0, 0, VLF);
+
+	if (rta_sec_era < RTA_SEC_ERA_3) {
+		PATCH_MOVE(p, move_cmd_read_descbuf, local_offset);
+		PATCH_MOVE(p, move_cmd_write_descbuf, local_offset);
+	}
+	return 0;
+}
+
+static inline int
+pdcp_insert_cplane_int_only_op(struct program *p,
+			       bool swap __maybe_unused,
+			       struct alginfo *cipherdata __maybe_unused,
+			       struct alginfo *authdata, unsigned int dir,
+			       unsigned char era_2_sw_hfn_ovrd)
+{
+	LABEL(local_offset);
+	REFERENCE(move_cmd_read_descbuf);
+	REFERENCE(move_cmd_write_descbuf);
+
+	switch (authdata->algtype) {
+	case PDCP_AUTH_TYPE_SNOW:
+		/* Insert Auth Key */
+		KEY(p, KEY2, authdata->key_enc_flags, authdata->key,
+		    authdata->keylen, INLINE_KEY(authdata));
+		SEQLOAD(p, MATH0, 7, 1, 0);
+		JUMP(p, 1, LOCAL_JUMP, ALL_TRUE, CALM);
+
+		if (rta_sec_era > RTA_SEC_ERA_2 ||
+		    (rta_sec_era == RTA_SEC_ERA_2 &&
+				   era_2_sw_hfn_ovrd == 0)) {
+			SEQINPTR(p, 0, 1, RTO);
+		} else {
+			SEQINPTR(p, 0, 5, RTO);
+			SEQFIFOLOAD(p, SKIP, 4, 0);
+		}
+
+		if (swap == false) {
+			MATHB(p, MATH0, AND, PDCP_C_PLANE_SN_MASK, MATH1,  8,
+			      IFB | IMMED2);
+			MATHB(p, MATH1, SHLD, MATH1, MATH1,  8, 0);
+
+			MOVEB(p, DESCBUF, 8, MATH2, 0, 8, WAITCOMP | IMMED);
+
+			MATHB(p, MATH2, AND, PDCP_BEARER_MASK, MATH2, 8,
+			      IMMED2);
+			MOVEB(p, DESCBUF, 0x0C, MATH3, 0, 4, WAITCOMP | IMMED);
+			MATHB(p, MATH3, AND, PDCP_DIR_MASK, MATH3, 8, IMMED2);
+			MATHB(p, MATH1, OR, MATH2, MATH2, 8, 0);
+			MOVEB(p, MATH2, 0, CONTEXT2, 0, 0x0C, WAITCOMP | IMMED);
+		} else {
+			MATHB(p, MATH0, AND, PDCP_C_PLANE_SN_MASK_BE, MATH1,  8,
+			      IFB | IMMED2);
+			MATHB(p, MATH1, SHLD, MATH1, MATH1,  8, 0);
+
+			MOVE(p, DESCBUF, 8, MATH2, 0, 8, WAITCOMP | IMMED);
+			MATHB(p, MATH2, AND, PDCP_BEARER_MASK_BE, MATH2, 8,
+			      IMMED2);
+
+			MOVE(p, DESCBUF, 0x0C, MATH3, 0, 4, WAITCOMP | IMMED);
+			MATHB(p, MATH3, AND, PDCP_DIR_MASK_BE, MATH3, 8,
+			      IMMED2);
+			MATHB(p, MATH1, OR, MATH2, MATH2, 8, 0);
+			MOVE(p, MATH2, 0, CONTEXT2, 0, 0x0C, WAITCOMP | IMMED);
+		}
+
+		if (dir == OP_TYPE_DECAP_PROTOCOL) {
+			MATHB(p, SEQINSZ, SUB, PDCP_MAC_I_LEN, MATH1, 4,
+			      IMMED2);
+		} else {
+			if (rta_sec_era > RTA_SEC_ERA_2) {
+				MATHB(p, SEQINSZ, SUB, ZERO, MATH1, 4,
+				      0);
+			} else {
+				MATHB(p, SEQINSZ, ADD, ONE, MATH1, 4,
+				      0);
+				MATHB(p, MATH1, SUB, ONE, MATH1, 4,
+				      0);
+			}
+		}
+
+		if (rta_sec_era > RTA_SEC_ERA_2) {
+			MATHB(p, MATH1, SUB, ZERO, VSEQINSZ, 4, 0);
+			MATHB(p, MATH1, SUB, ZERO, VSEQOUTSZ, 4, 0);
+		} else {
+			MATHB(p, ZERO, ADD, MATH1, VSEQINSZ, 4, 0);
+			MATHB(p, ZERO, ADD, MATH1, VSEQOUTSZ, 4, 0);
+
+			/*
+			 * Since MOVELEN is available only starting with
+			 * SEC ERA 3, use poor man's MOVELEN: create a MOVE
+			 * command dynamically by writing the length from M1 by
+			 * OR-ing the command in the M1 register and MOVE the
+			 * result into the descriptor buffer. Care must be taken
+			 * wrt. the location of the command because of SEC
+			 * pipelining. The actual MOVEs are written at the end
+			 * of the descriptor due to calculations needed on the
+			 * offset in the descriptor for the MOVE command.
+			 */
+			move_cmd_read_descbuf = MOVE(p, DESCBUF, 0, MATH1, 0, 6,
+						     IMMED);
+			move_cmd_write_descbuf = MOVE(p, MATH1, 0, DESCBUF, 0,
+						      8, WAITCOMP | IMMED);
+		}
+
+		SEQFIFOSTORE(p, MSG, 0, 0, VLF);
+		ALG_OPERATION(p, OP_ALG_ALGSEL_SNOW_F9, OP_ALG_AAI_F9,
+			      OP_ALG_AS_INITFINAL,
+			      dir == OP_TYPE_ENCAP_PROTOCOL ?
+				     ICV_CHECK_DISABLE : ICV_CHECK_ENABLE,
+			      DIR_ENC);
+
+		if (rta_sec_era > RTA_SEC_ERA_2) {
+			SEQFIFOLOAD(p, MSGINSNOOP, 0,
+				    VLF | LAST1 | LAST2 | FLUSH1);
+			MOVE(p, AB1, 0, OFIFO, 0, MATH1, 0);
+		} else {
+			SEQFIFOLOAD(p, MSGINSNOOP, 0,
+				    VLF | LAST1 | LAST2 | FLUSH1);
+			SET_LABEL(p, local_offset);
+
+			/* Shut off automatic Info FIFO entries */
+			LOAD(p, 0, DCTRL, LDOFF_DISABLE_AUTO_NFIFO, 0, IMMED);
+			/*
+			 * Placeholder for MOVE command with length from M1
+			 * register
+			 */
+			MOVE(p, IFIFOAB1, 0, OFIFO, 0, 0, IMMED);
+			/* Enable automatic Info FIFO entries */
+			LOAD(p, 0, DCTRL, LDOFF_ENABLE_AUTO_NFIFO, 0, IMMED);
+		}
+
+		if (dir == OP_TYPE_DECAP_PROTOCOL)
+			SEQFIFOLOAD(p, ICV2, 4, LAST2);
+		else
+			SEQSTORE(p, CONTEXT2, 0, 4, 0);
+
+		break;
+
+	case PDCP_AUTH_TYPE_AES:
+		/* Insert Auth Key */
+		KEY(p, KEY1, authdata->key_enc_flags, authdata->key,
+		    authdata->keylen, INLINE_KEY(authdata));
+		SEQLOAD(p, MATH0, 7, 1, 0);
+		JUMP(p, 1, LOCAL_JUMP, ALL_TRUE, CALM);
+		if (rta_sec_era > RTA_SEC_ERA_2 ||
+		    (rta_sec_era == RTA_SEC_ERA_2 &&
+		     era_2_sw_hfn_ovrd == 0)) {
+			SEQINPTR(p, 0, 1, RTO);
+		} else {
+			SEQINPTR(p, 0, 5, RTO);
+			SEQFIFOLOAD(p, SKIP, 4, 0);
+		}
+
+		if (swap == false) {
+			MATHB(p, MATH0, AND, PDCP_C_PLANE_SN_MASK, MATH1, 8,
+			      IFB | IMMED2);
+			MATHB(p, MATH1, SHLD, MATH1, MATH1, 8, 0);
+
+			MOVEB(p, DESCBUF, 8, MATH2, 0, 8, WAITCOMP | IMMED);
+			MATHB(p, MATH1, OR, MATH2, MATH2, 8, 0);
+			MOVEB(p, MATH2, 0, IFIFOAB1, 0, 8, IMMED);
+		} else {
+			MATHB(p, MATH0, AND, PDCP_C_PLANE_SN_MASK_BE, MATH1, 8,
+			      IFB | IMMED2);
+			MATHB(p, MATH1, SHLD, MATH1, MATH1, 8, 0);
+
+			MOVE(p, DESCBUF, 8, MATH2, 0, 8, WAITCOMP | IMMED);
+			MATHB(p, MATH1, OR, MATH2, MATH2, 8, 0);
+			MOVE(p, MATH2, 0, IFIFOAB1, 0, 8, IMMED);
+		}
+
+		if (dir == OP_TYPE_DECAP_PROTOCOL) {
+			MATHB(p, SEQINSZ, SUB, PDCP_MAC_I_LEN, MATH1, 4,
+			      IMMED2);
+		} else {
+			if (rta_sec_era > RTA_SEC_ERA_2) {
+				MATHB(p, SEQINSZ, SUB, ZERO, MATH1, 4,
+				      0);
+			} else {
+				MATHB(p, SEQINSZ, ADD, ONE, MATH1, 4,
+				      0);
+				MATHB(p, MATH1, SUB, ONE, MATH1, 4,
+				      0);
+			}
+		}
+
+		if (rta_sec_era > RTA_SEC_ERA_2) {
+			MATHB(p, MATH1, SUB, ZERO, VSEQINSZ, 4, 0);
+			MATHB(p, MATH1, SUB, ZERO, VSEQOUTSZ, 4, 0);
+		} else {
+			MATHB(p, ZERO, ADD, MATH1, VSEQINSZ, 4, 0);
+			MATHB(p, ZERO, ADD, MATH1, VSEQOUTSZ, 4, 0);
+
+			/*
+			 * Since MOVELEN is available only starting with
+			 * SEC ERA 3, use poor man's MOVELEN: create a MOVE
+			 * command dynamically by writing the length from M1 by
+			 * OR-ing the command in the M1 register and MOVE the
+			 * result into the descriptor buffer. Care must be taken
+			 * wrt. the location of the command because of SEC
+			 * pipelining. The actual MOVEs are written at the end
+			 * of the descriptor due to calculations needed on the
+			 * offset in the descriptor for the MOVE command.
+			 */
+			move_cmd_read_descbuf = MOVE(p, DESCBUF, 0, MATH1, 0, 6,
+						     IMMED);
+			move_cmd_write_descbuf = MOVE(p, MATH1, 0, DESCBUF, 0,
+						      8, WAITCOMP | IMMED);
+		}
+		SEQFIFOSTORE(p, MSG, 0, 0, VLF);
+		ALG_OPERATION(p, OP_ALG_ALGSEL_AES,
+			      OP_ALG_AAI_CMAC,
+			      OP_ALG_AS_INITFINAL,
+			      dir == OP_TYPE_ENCAP_PROTOCOL ?
+				     ICV_CHECK_DISABLE : ICV_CHECK_ENABLE,
+			      DIR_ENC);
+
+		if (rta_sec_era > RTA_SEC_ERA_2) {
+			MOVE(p, AB2, 0, OFIFO, 0, MATH1, 0);
+			SEQFIFOLOAD(p, MSGINSNOOP, 0,
+				    VLF | LAST1 | LAST2 | FLUSH1);
+		} else {
+			SEQFIFOLOAD(p, MSGINSNOOP, 0,
+				    VLF | LAST1 | LAST2 | FLUSH1);
+			SET_LABEL(p, local_offset);
+
+			/* Shut off automatic Info FIFO entries */
+			LOAD(p, 0, DCTRL, LDOFF_DISABLE_AUTO_NFIFO, 0, IMMED);
+
+			/*
+			 * Placeholder for MOVE command with length from
+			 * M1 register
+			 */
+			MOVE(p, IFIFOAB2, 0, OFIFO, 0, 0, IMMED);
+
+			/* Enable automatic Info FIFO entries */
+			LOAD(p, 0, DCTRL, LDOFF_ENABLE_AUTO_NFIFO, 0, IMMED);
+		}
+
+		if (dir == OP_TYPE_DECAP_PROTOCOL)
+			SEQFIFOLOAD(p, ICV1, 4, LAST1 | FLUSH1);
+		else
+			SEQSTORE(p, CONTEXT1, 0, 4, 0);
+
+		break;
+
+	case PDCP_AUTH_TYPE_ZUC:
+		if (rta_sec_era < RTA_SEC_ERA_5) {
+			pr_err("Invalid era for selected algorithm\n");
+			return -ENOTSUP;
+		}
+		/* Insert Auth Key */
+		KEY(p, KEY2, authdata->key_enc_flags, authdata->key,
+		    authdata->keylen, INLINE_KEY(authdata));
+		SEQLOAD(p, MATH0, 7, 1, 0);
+		JUMP(p, 1, LOCAL_JUMP, ALL_TRUE, CALM);
+		SEQINPTR(p, 0, 1, RTO);
+		if (swap == false) {
+			MATHB(p, MATH0, AND, PDCP_C_PLANE_SN_MASK, MATH1, 8,
+			      IFB | IMMED2);
+			MATHB(p, MATH1, SHLD, MATH1, MATH1, 8, 0);
+
+			MOVEB(p, DESCBUF, 8, MATH2, 0, 8, WAITCOMP | IMMED);
+			MATHB(p, MATH1, OR, MATH2, MATH2, 8, 0);
+			MOVEB(p, MATH2, 0, CONTEXT2, 0, 8, IMMED);
+
+		} else {
+			MATHB(p, MATH0, AND, PDCP_C_PLANE_SN_MASK_BE, MATH1, 8,
+			      IFB | IMMED2);
+			MATHB(p, MATH1, SHLD, MATH1, MATH1, 8, 0);
+
+			MOVE(p, DESCBUF, 8, MATH2, 0, 8, WAITCOMP | IMMED);
+			MATHB(p, MATH1, OR, MATH2, MATH2, 8, 0);
+			MOVE(p, MATH2, 0, CONTEXT2, 0, 8, IMMED);
+		}
+		if (dir == OP_TYPE_DECAP_PROTOCOL)
+			MATHB(p, SEQINSZ, SUB, PDCP_MAC_I_LEN, MATH1, 4,
+			      IMMED2);
+		else
+			MATHB(p, SEQINSZ, SUB, ZERO, MATH1, 4, 0);
+
+		MATHB(p, MATH1, SUB, ZERO, VSEQINSZ, 4, 0);
+		MATHB(p, MATH1, SUB, ZERO, VSEQOUTSZ, 4, 0);
+		SEQFIFOSTORE(p, MSG, 0, 0, VLF);
+		ALG_OPERATION(p, OP_ALG_ALGSEL_ZUCA,
+			      OP_ALG_AAI_F9,
+			      OP_ALG_AS_INITFINAL,
+			      dir == OP_TYPE_ENCAP_PROTOCOL ?
+				     ICV_CHECK_DISABLE : ICV_CHECK_ENABLE,
+			      DIR_ENC);
+		SEQFIFOLOAD(p, MSGINSNOOP, 0, VLF | LAST1 | LAST2 | FLUSH1);
+		MOVE(p, AB1, 0, OFIFO, 0, MATH1, 0);
+
+		if (dir == OP_TYPE_DECAP_PROTOCOL)
+			SEQFIFOLOAD(p, ICV2, 4, LAST2);
+		else
+			SEQSTORE(p, CONTEXT2, 0, 4, 0);
+
+		break;
+
+	default:
+		pr_err("%s: Invalid integrity algorithm selected: %d\n",
+		       "pdcp_insert_cplane_int_only_op", authdata->algtype);
+		return -EINVAL;
+	}
+
+	if (rta_sec_era < RTA_SEC_ERA_3) {
+		PATCH_MOVE(p, move_cmd_read_descbuf, local_offset);
+		PATCH_MOVE(p, move_cmd_write_descbuf, local_offset);
+	}
+
+	return 0;
+}
+
+static inline int
+pdcp_insert_cplane_enc_only_op(struct program *p,
+			       bool swap __maybe_unused,
+			       struct alginfo *cipherdata,
+			       struct alginfo *authdata __maybe_unused,
+			       unsigned int dir,
+			       unsigned char era_2_sw_hfn_ovrd __maybe_unused)
+{
+	/* Insert Cipher Key */
+	KEY(p, KEY1, cipherdata->key_enc_flags, cipherdata->key,
+	    cipherdata->keylen, INLINE_KEY(cipherdata));
+
+	if (rta_sec_era >= RTA_SEC_ERA_8) {
+		PROTOCOL(p, dir, OP_PCLID_LTE_PDCP_CTRL_MIXED,
+				(uint16_t)cipherdata->algtype << 8);
+		return 0;
+	}
+
+	SEQLOAD(p, MATH0, 7, 1, 0);
+	JUMP(p, 1, LOCAL_JUMP, ALL_TRUE, CALM);
+	if (swap == false)
+		MATHB(p, MATH0, AND, PDCP_C_PLANE_SN_MASK, MATH1, 8,
+			IFB | IMMED2);
+	else
+		MATHB(p, MATH0, AND, PDCP_C_PLANE_SN_MASK_BE, MATH1, 8,
+			IFB | IMMED2);
+	SEQSTORE(p, MATH0, 7, 1, 0);
+	MATHB(p, MATH1, SHLD, MATH1, MATH1, 8, 0);
+	MOVE(p, DESCBUF, 8, MATH2, 0, 8, WAITCOMP | IMMED);
+	MATHB(p, MATH1, OR, MATH2, MATH2, 8, 0);
+
+	switch (cipherdata->algtype) {
+	case PDCP_CIPHER_TYPE_SNOW:
+		MOVE(p, MATH2, 0, CONTEXT1, 0, 8, WAITCOMP | IMMED);
+
+		if (rta_sec_era > RTA_SEC_ERA_2) {
+			MATHB(p, SEQINSZ, SUB, ZERO, VSEQINSZ, 4, 0);
+		} else {
+			MATHB(p, SEQINSZ, SUB, ONE, MATH1, 4, 0);
+			MATHB(p, MATH1, ADD, ONE, VSEQINSZ, 4, 0);
+		}
+
+		if (dir == OP_TYPE_ENCAP_PROTOCOL)
+			MATHB(p, SEQINSZ, ADD, PDCP_MAC_I_LEN, VSEQOUTSZ, 4,
+			      IMMED2);
+		else
+			MATHB(p, SEQINSZ, SUB, PDCP_MAC_I_LEN, VSEQOUTSZ, 4,
+			      IMMED2);
+		SEQFIFOSTORE(p, MSG, 0, 0, VLF | CONT);
+		ALG_OPERATION(p, OP_ALG_ALGSEL_SNOW_F8,
+			      OP_ALG_AAI_F8,
+			      OP_ALG_AS_INITFINAL, ICV_CHECK_DISABLE,
+			      dir == OP_TYPE_ENCAP_PROTOCOL ?
+					DIR_ENC : DIR_DEC);
+		break;
+
+	case PDCP_CIPHER_TYPE_AES:
+		MOVE(p, MATH2, 0, CONTEXT1, 0x10, 0x10, WAITCOMP | IMMED);
+
+		if (rta_sec_era > RTA_SEC_ERA_2) {
+			MATHB(p, SEQINSZ, SUB, ZERO, VSEQINSZ, 4, 0);
+		} else {
+			MATHB(p, SEQINSZ, SUB, ONE, MATH1, 4, 0);
+			MATHB(p, MATH1, ADD, ONE, VSEQINSZ, 4, 0);
+		}
+
+		if (dir == OP_TYPE_ENCAP_PROTOCOL)
+			MATHB(p, SEQINSZ, ADD, PDCP_MAC_I_LEN, VSEQOUTSZ, 4,
+			      IMMED2);
+		else
+			MATHB(p, SEQINSZ, SUB, PDCP_MAC_I_LEN, VSEQOUTSZ, 4,
+			      IMMED2);
+
+		SEQFIFOSTORE(p, MSG, 0, 0, VLF | CONT);
+		ALG_OPERATION(p, OP_ALG_ALGSEL_AES,
+			      OP_ALG_AAI_CTR,
+			      OP_ALG_AS_INITFINAL,
+			      ICV_CHECK_DISABLE,
+			      dir == OP_TYPE_ENCAP_PROTOCOL ?
+					DIR_ENC : DIR_DEC);
+		break;
+
+	case PDCP_CIPHER_TYPE_ZUC:
+		if (rta_sec_era < RTA_SEC_ERA_5) {
+			pr_err("Invalid era for selected algorithm\n");
+			return -ENOTSUP;
+		}
+
+		MOVE(p, MATH2, 0, CONTEXT1, 0, 0x08, IMMED);
+		MOVE(p, MATH2, 0, CONTEXT1, 0x08, 0x08, WAITCOMP | IMMED);
+		MATHB(p, SEQINSZ, SUB, ZERO, VSEQINSZ, 4, 0);
+		if (dir == OP_TYPE_ENCAP_PROTOCOL)
+			MATHB(p, SEQINSZ, ADD, PDCP_MAC_I_LEN, VSEQOUTSZ, 4,
+			      IMMED2);
+		else
+			MATHB(p, SEQINSZ, SUB, PDCP_MAC_I_LEN, VSEQOUTSZ, 4,
+			      IMMED2);
+
+		SEQFIFOSTORE(p, MSG, 0, 0, VLF | CONT);
+		ALG_OPERATION(p, OP_ALG_ALGSEL_ZUCE,
+			      OP_ALG_AAI_F8,
+			      OP_ALG_AS_INITFINAL,
+			      ICV_CHECK_DISABLE,
+			      dir == OP_TYPE_ENCAP_PROTOCOL ?
+					DIR_ENC : DIR_DEC);
+		break;
+
+	default:
+		pr_err("%s: Invalid encrypt algorithm selected: %d\n",
+		       "pdcp_insert_cplane_enc_only_op", cipherdata->algtype);
+		return -EINVAL;
+	}
+
+	if (dir == OP_TYPE_ENCAP_PROTOCOL) {
+		SEQFIFOLOAD(p, MSG1, 0, VLF);
+		FIFOLOAD(p, MSG1, PDCP_NULL_INT_MAC_I_VAL, 4,
+			 LAST1 | FLUSH1 | IMMED);
+	} else {
+		SEQFIFOLOAD(p, MSG1, 0, VLF | LAST1 | FLUSH1);
+		MOVE(p, OFIFO, 0, MATH1, 4, PDCP_MAC_I_LEN, WAITCOMP | IMMED);
+		MATHB(p, MATH1, XOR, PDCP_NULL_INT_MAC_I_VAL, NONE, 4, IMMED2);
+		JUMP(p, PDCP_NULL_INT_ICV_CHECK_FAILED_STATUS,
+		     HALT_STATUS, ALL_FALSE, MATH_Z);
+	}
+
+	return 0;
+}
+
+static inline int
+pdcp_insert_cplane_acc_op(struct program *p,
+			  bool swap __maybe_unused,
+			  struct alginfo *cipherdata,
+			  struct alginfo *authdata,
+			  unsigned int dir,
+			  unsigned char era_2_hfn_ovrd __maybe_unused)
+{
+	/* Insert Auth Key */
+	KEY(p, KEY2, authdata->key_enc_flags, authdata->key, authdata->keylen,
+	    INLINE_KEY(authdata));
+
+	/* Insert Cipher Key */
+	KEY(p, KEY1, cipherdata->key_enc_flags, cipherdata->key,
+	    cipherdata->keylen, INLINE_KEY(cipherdata));
+	PROTOCOL(p, dir, OP_PCLID_LTE_PDCP_CTRL, (uint16_t)cipherdata->algtype);
+
+	return 0;
+}
+
+static inline int
+pdcp_insert_cplane_snow_aes_op(struct program *p,
+			       bool swap __maybe_unused,
+			       struct alginfo *cipherdata,
+			       struct alginfo *authdata,
+			       unsigned int dir,
+			       unsigned char era_2_sw_hfn_ovrd)
+{
+	LABEL(back_to_sd_offset);
+	LABEL(end_desc);
+	LABEL(local_offset);
+	LABEL(jump_to_beginning);
+	LABEL(fifo_load_mac_i_offset);
+	REFERENCE(seqin_ptr_read);
+	REFERENCE(seqin_ptr_write);
+	REFERENCE(seq_out_read);
+	REFERENCE(jump_back_to_sd_cmd);
+	REFERENCE(move_mac_i_to_desc_buf);
+
+	if (rta_sec_era >= RTA_SEC_ERA_8) {
+		KEY(p, KEY1, cipherdata->key_enc_flags, cipherdata->key,
+				cipherdata->keylen, INLINE_KEY(cipherdata));
+		KEY(p, KEY2, authdata->key_enc_flags, authdata->key,
+				authdata->keylen, INLINE_KEY(authdata));
+
+		PROTOCOL(p, dir, OP_PCLID_LTE_PDCP_CTRL_MIXED,
+			 ((uint16_t)cipherdata->algtype << 8) |
+			 (uint16_t)authdata->algtype);
+
+		return 0;
+	}
+
+	SEQLOAD(p, MATH0, 7, 1, 0);
+	JUMP(p, 1, LOCAL_JUMP, ALL_TRUE, CALM);
+	if (swap == false)
+		MATHB(p, MATH0, AND, PDCP_C_PLANE_SN_MASK, MATH1, 8,
+			IFB | IMMED2);
+	else
+		MATHB(p, MATH0, AND, PDCP_C_PLANE_SN_MASK_BE, MATH1, 8,
+			IFB | IMMED2);
+	MATHB(p, MATH1, SHLD, MATH1, MATH1, 8, 0);
+	MOVE(p, DESCBUF, 4, MATH2, 0, 0x08, WAITCOMP | IMMED);
+	MATHB(p, MATH1, OR, MATH2, MATH2, 8, 0);
+	SEQSTORE(p, MATH0, 7, 1, 0);
+	if (dir == OP_TYPE_ENCAP_PROTOCOL) {
+		if (rta_sec_era > RTA_SEC_ERA_2 ||
+		    (rta_sec_era == RTA_SEC_ERA_2 &&
+				   era_2_sw_hfn_ovrd == 0)) {
+			SEQINPTR(p, 0, 1, RTO);
+		} else {
+			SEQINPTR(p, 0, 5, RTO);
+			SEQFIFOLOAD(p, SKIP, 4, 0);
+		}
+		KEY(p, KEY1, authdata->key_enc_flags, authdata->key,
+		    authdata->keylen, INLINE_KEY(authdata));
+		MOVE(p, MATH2, 0, IFIFOAB1, 0, 0x08, IMMED);
+
+		if (rta_sec_era > RTA_SEC_ERA_2) {
+			MATHB(p, SEQINSZ, SUB, ZERO, VSEQINSZ, 4, 0);
+			MATHB(p, SEQINSZ, SUB, ZERO, MATH1, 4, 0);
+			MATHB(p, VSEQINSZ, ADD, PDCP_MAC_I_LEN - 1, VSEQOUTSZ,
+			      4, IMMED2);
+		} else {
+			MATHB(p, SEQINSZ, SUB, MATH3, VSEQINSZ, 4, 0);
+			MATHB(p, VSEQINSZ, ADD, PDCP_MAC_I_LEN - 1, VSEQOUTSZ,
+			      4, IMMED2);
+			/*
+			 * Note: Although the calculations below might seem a
+			 * little off, the logic is the following:
+			 *
+			 * - SEQ IN PTR RTO below needs the full length of the
+			 *   frame; in case of P4080_REV_2_HFN_OV_WORKAROUND,
+			 *   this means the length of the frame to be processed
+			 *   + 4 bytes (the HFN override flag and value).
+			 *   The length of the frame to be processed minus 1
+			 *   byte is in the VSIL register (because
+			 *   VSIL = SIL + 3, due to 1 byte, the header being
+			 *   already written by the SEQ STORE above). So for
+			 *   calculating the length to use in RTO, I add one
+			 *   to the VSIL value in order to obtain the total
+			 *   frame length. This helps in case of P4080 which
+			 *   can have the value 0 as an operand in a MATH
+			 *   command only as SRC1 When the HFN override
+			 *   workaround is not enabled, the length of the
+			 *   frame is given by the SIL register; the
+			 *   calculation is similar to the one in the SEC 4.2
+			 *   and SEC 5.3 cases.
+			 */
+			if (era_2_sw_hfn_ovrd)
+				MATHB(p, VSEQOUTSZ, ADD, ONE, MATH1, 4,
+				      0);
+			else
+				MATHB(p, SEQINSZ, ADD, MATH3, MATH1, 4,
+				      0);
+		}
+		/*
+		 * Placeholder for filling the length in
+		 * SEQIN PTR RTO below
+		 */
+		seqin_ptr_read = MOVE(p, DESCBUF, 0, MATH1, 0, 6, IMMED);
+		seqin_ptr_write = MOVE(p, MATH1, 0, DESCBUF, 0, 8,
+				       WAITCOMP | IMMED);
+		ALG_OPERATION(p, OP_ALG_ALGSEL_AES,
+			      OP_ALG_AAI_CMAC,
+			      OP_ALG_AS_INITFINAL,
+			      ICV_CHECK_DISABLE,
+			      DIR_DEC);
+		SEQFIFOLOAD(p, MSG1, 0, VLF | LAST1 | FLUSH1);
+		MOVE(p, CONTEXT1, 0, MATH3, 0, 4, WAITCOMP | IMMED);
+		if (rta_sec_era <= RTA_SEC_ERA_3)
+			LOAD(p, CLRW_CLR_C1KEY |
+			     CLRW_CLR_C1CTX |
+			     CLRW_CLR_C1ICV |
+			     CLRW_CLR_C1DATAS |
+			     CLRW_CLR_C1MODE,
+			     CLRW, 0, 4, IMMED);
+		else
+			LOAD(p, CLRW_RESET_CLS1_CHA |
+			     CLRW_CLR_C1KEY |
+			     CLRW_CLR_C1CTX |
+			     CLRW_CLR_C1ICV |
+			     CLRW_CLR_C1DATAS |
+			     CLRW_CLR_C1MODE,
+			     CLRW, 0, 4, IMMED);
+
+		if (rta_sec_era <= RTA_SEC_ERA_3)
+			LOAD(p, CCTRL_RESET_CHA_ALL, CCTRL, 0, 4, IMMED);
+
+		KEY(p, KEY1, cipherdata->key_enc_flags, cipherdata->key,
+		    cipherdata->keylen, INLINE_KEY(cipherdata));
+		SET_LABEL(p, local_offset);
+		MOVE(p, MATH2, 0, CONTEXT1, 0, 8, IMMED);
+		SEQINPTR(p, 0, 0, RTO);
+
+		if (rta_sec_era == RTA_SEC_ERA_2 && era_2_sw_hfn_ovrd) {
+			SEQFIFOLOAD(p, SKIP, 5, 0);
+			MATHB(p, SEQINSZ, ADD, ONE, SEQINSZ, 4, 0);
+		}
+
+		MATHB(p, SEQINSZ, SUB, ONE, VSEQINSZ, 4, 0);
+		ALG_OPERATION(p, OP_ALG_ALGSEL_SNOW_F8,
+			      OP_ALG_AAI_F8,
+			      OP_ALG_AS_INITFINAL,
+			      ICV_CHECK_DISABLE,
+			      DIR_ENC);
+		SEQFIFOSTORE(p, MSG, 0, 0, VLF);
+
+		if (rta_sec_era > RTA_SEC_ERA_2 ||
+		    (rta_sec_era == RTA_SEC_ERA_2 &&
+				   era_2_sw_hfn_ovrd == 0))
+			SEQFIFOLOAD(p, SKIP, 1, 0);
+
+		SEQFIFOLOAD(p, MSG1, 0, VLF);
+		MOVE(p, MATH3, 0, IFIFOAB1, 0, 4, LAST1 | FLUSH1 | IMMED);
+		PATCH_MOVE(p, seqin_ptr_read, local_offset);
+		PATCH_MOVE(p, seqin_ptr_write, local_offset);
+	} else {
+		MOVE(p, MATH2, 0, CONTEXT1, 0, 8, IMMED);
+
+		if (rta_sec_era >= RTA_SEC_ERA_5)
+			MOVE(p, CONTEXT1, 0, CONTEXT2, 0, 8, IMMED);
+
+		if (rta_sec_era > RTA_SEC_ERA_2)
+			MATHB(p, SEQINSZ, SUB, ZERO, VSEQINSZ, 4, 0);
+		else
+			MATHB(p, SEQINSZ, SUB, MATH3, VSEQINSZ, 4, 0);
+
+		MATHB(p, SEQINSZ, SUB, PDCP_MAC_I_LEN, VSEQOUTSZ, 4, IMMED2);
+/*
+ * TODO: To be changed when proper support is added in RTA (can't load a
+ * command that is also written by RTA (or patch it for that matter).
+ * Change when proper RTA support is added.
+ */
+		if (p->ps)
+			WORD(p, 0x168B0004);
+		else
+			WORD(p, 0x16880404);
+
+		jump_back_to_sd_cmd = JUMP(p, 0, LOCAL_JUMP, ALL_TRUE, 0);
+		/*
+		 * Placeholder for command reading  the SEQ OUT command in
+		 * JD. Done for rereading the decrypted data and performing
+		 * the integrity check
+		 */
+/*
+ * TODO: RTA currently doesn't support patching of length of a MOVE command
+ * Thus, it is inserted as a raw word, as per PS setting.
+ */
+		if (p->ps)
+			seq_out_read = MOVE(p, DESCBUF, 0, MATH1, 0, 20,
+					    WAITCOMP | IMMED);
+		else
+			seq_out_read = MOVE(p, DESCBUF, 0, MATH1, 0, 16,
+					    WAITCOMP | IMMED);
+
+		MATHB(p, MATH1, XOR, CMD_SEQ_IN_PTR ^ CMD_SEQ_OUT_PTR, MATH1, 4,
+		      IMMED2);
+		/* Placeholder for overwriting the SEQ IN  with SEQ OUT */
+/*
+ * TODO: RTA currently doesn't support patching of length of a MOVE command
+ * Thus, it is inserted as a raw word, as per PS setting.
+ */
+		if (p->ps)
+			MOVE(p, MATH1, 0, DESCBUF, 0, 24, IMMED);
+		else
+			MOVE(p, MATH1, 0, DESCBUF, 0, 20, IMMED);
+
+		KEY(p, KEY1, cipherdata->key_enc_flags, cipherdata->key,
+		    cipherdata->keylen, INLINE_KEY(cipherdata));
+
+		if (rta_sec_era >= RTA_SEC_ERA_4)
+			MOVE(p, CONTEXT1, 0, CONTEXT2, 0, 8, IMMED);
+		else
+			MOVE(p, CONTEXT1, 0, MATH3, 0, 8, IMMED);
+
+		ALG_OPERATION(p, OP_ALG_ALGSEL_SNOW_F8,
+			      OP_ALG_AAI_F8,
+			      OP_ALG_AS_INITFINAL,
+			      ICV_CHECK_DISABLE,
+			      DIR_DEC);
+		SEQFIFOSTORE(p, MSG, 0, 0, VLF | CONT);
+		SEQFIFOLOAD(p, MSG1, 0, VLF | LAST1 | FLUSH1);
+
+		if (rta_sec_era <= RTA_SEC_ERA_3)
+			move_mac_i_to_desc_buf = MOVE(p, OFIFO, 0, DESCBUF, 0,
+						      4, WAITCOMP | IMMED);
+		else
+			MOVE(p, OFIFO, 0, MATH3, 0, 4, IMMED);
+
+		if (rta_sec_era <= RTA_SEC_ERA_3)
+			LOAD(p, CCTRL_RESET_CHA_ALL, CCTRL, 0, 4, IMMED);
+		else
+			LOAD(p, CLRW_RESET_CLS1_CHA |
+			     CLRW_CLR_C1KEY |
+			     CLRW_CLR_C1CTX |
+			     CLRW_CLR_C1ICV |
+			     CLRW_CLR_C1DATAS |
+			     CLRW_CLR_C1MODE,
+			     CLRW, 0, 4, IMMED);
+
+		KEY(p, KEY1, authdata->key_enc_flags, authdata->key,
+		    authdata->keylen, INLINE_KEY(authdata));
+		/*
+		 * Placeholder for jump in SD for executing the new SEQ IN PTR
+		 * command (which is actually the old SEQ OUT PTR command
+		 * copied over from JD.
+		 */
+		SET_LABEL(p, jump_to_beginning);
+		JUMP(p, 1 - jump_to_beginning, LOCAL_JUMP, ALL_TRUE, 0);
+		SET_LABEL(p, back_to_sd_offset);
+		ALG_OPERATION(p, OP_ALG_ALGSEL_AES,
+			      OP_ALG_AAI_CMAC,
+			      OP_ALG_AS_INITFINAL,
+			      ICV_CHECK_ENABLE,
+			      DIR_DEC);
+
+		/* Read the # of bytes written in the output buffer + 1 (HDR) */
+		MATHB(p, VSEQOUTSZ, ADD, ONE, VSEQINSZ, 4, 0);
+
+		if (rta_sec_era <= RTA_SEC_ERA_3)
+			MOVE(p, MATH3, 0, IFIFOAB1, 0, 8, IMMED);
+		else
+			MOVE(p, CONTEXT2, 0, IFIFOAB1, 0, 8, IMMED);
+
+		if (rta_sec_era == RTA_SEC_ERA_2 && era_2_sw_hfn_ovrd)
+			SEQFIFOLOAD(p, SKIP, 4, 0);
+
+		SEQFIFOLOAD(p, MSG1, 0, VLF | LAST1 | FLUSH1);
+
+		if (rta_sec_era >= RTA_SEC_ERA_4) {
+			LOAD(p, NFIFOENTRY_STYPE_ALTSOURCE |
+			     NFIFOENTRY_DEST_CLASS1 |
+			     NFIFOENTRY_DTYPE_ICV |
+			     NFIFOENTRY_LC1 |
+			     NFIFOENTRY_FC1 | 4, NFIFO_SZL, 0, 4, IMMED);
+			MOVE(p, MATH3, 0, ALTSOURCE, 0, 4, IMMED);
+		} else {
+			SET_LABEL(p, fifo_load_mac_i_offset);
+			FIFOLOAD(p, ICV1, fifo_load_mac_i_offset, 4,
+				 LAST1 | FLUSH1 | IMMED);
+		}
+
+		SET_LABEL(p, end_desc);
+
+		if (!p->ps) {
+			PATCH_MOVE(p, seq_out_read, end_desc + 1);
+			PATCH_JUMP(p, jump_back_to_sd_cmd,
+				   back_to_sd_offset + jump_back_to_sd_cmd - 5);
+
+			if (rta_sec_era <= RTA_SEC_ERA_3)
+				PATCH_MOVE(p, move_mac_i_to_desc_buf,
+					   fifo_load_mac_i_offset + 1);
+		} else {
+			PATCH_MOVE(p, seq_out_read, end_desc + 2);
+			PATCH_JUMP(p, jump_back_to_sd_cmd,
+				   back_to_sd_offset + jump_back_to_sd_cmd - 5);
+
+			if (rta_sec_era <= RTA_SEC_ERA_3)
+				PATCH_MOVE(p, move_mac_i_to_desc_buf,
+					   fifo_load_mac_i_offset + 1);
+		}
+	}
+
+	return 0;
+}
+
+static inline int
+pdcp_insert_cplane_aes_snow_op(struct program *p,
+			       bool swap __maybe_unused,
+			       struct alginfo *cipherdata,
+			       struct alginfo *authdata,
+			       unsigned int dir,
+			       unsigned char era_2_sw_hfn_ovrd __maybe_unused)
+{
+	KEY(p, KEY1, cipherdata->key_enc_flags, cipherdata->key,
+	    cipherdata->keylen, INLINE_KEY(cipherdata));
+	KEY(p, KEY2, authdata->key_enc_flags, authdata->key, authdata->keylen,
+	    INLINE_KEY(authdata));
+
+	if (rta_sec_era >= RTA_SEC_ERA_8) {
+		PROTOCOL(p, dir, OP_PCLID_LTE_PDCP_CTRL_MIXED,
+			 ((uint16_t)cipherdata->algtype << 8) |
+			 (uint16_t)authdata->algtype);
+
+		return 0;
+	}
+
+	if (dir == OP_TYPE_ENCAP_PROTOCOL)
+		MATHB(p, SEQINSZ, SUB, ONE, VSEQINSZ, 4, 0);
+
+	SEQLOAD(p, MATH0, 7, 1, 0);
+	JUMP(p, 1, LOCAL_JUMP, ALL_TRUE, CALM);
+	MOVE(p, MATH0, 7, IFIFOAB2, 0, 1, IMMED);
+	if (swap == false)
+		MATHB(p, MATH0, AND, PDCP_C_PLANE_SN_MASK, MATH1, 8,
+			IFB | IMMED2);
+	else
+		MATHB(p, MATH0, AND, PDCP_C_PLANE_SN_MASK_BE, MATH1, 8,
+			IFB | IMMED2);
+
+	SEQSTORE(p, MATH0, 7, 1, 0);
+	MATHB(p, MATH1, SHLD, MATH1, MATH1, 8, 0);
+	MOVE(p, DESCBUF, 4, MATH2, 0, 8, WAITCOMP | IMMED);
+	MATHB(p, MATH1, OR, MATH2, MATH1, 8, 0);
+	MOVE(p, MATH1, 0, CONTEXT1, 16, 8, IMMED);
+	MOVE(p, MATH1, 0, CONTEXT2, 0, 4, IMMED);
+	if (swap == false) {
+		MATHB(p, MATH1, AND, lower_32_bits(PDCP_BEARER_MASK), MATH2, 4,
+			IMMED2);
+		MATHB(p, MATH1, AND, upper_32_bits(PDCP_DIR_MASK), MATH3, 4,
+			IMMED2);
+	} else {
+		MATHB(p, MATH1, AND, lower_32_bits(PDCP_BEARER_MASK_BE), MATH2,
+			4, IMMED2);
+		MATHB(p, MATH1, AND, upper_32_bits(PDCP_DIR_MASK_BE), MATH3,
+			4, IMMED2);
+	}
+	MATHB(p, MATH3, SHLD, MATH3, MATH3, 8, 0);
+	MOVE(p, MATH2, 4, OFIFO, 0, 12, IMMED);
+	MOVE(p, OFIFO, 0, CONTEXT2, 4, 12, IMMED);
+	if (dir == OP_TYPE_ENCAP_PROTOCOL) {
+		MATHB(p, SEQINSZ, ADD, PDCP_MAC_I_LEN, VSEQOUTSZ, 4, IMMED2);
+	} else {
+		MATHB(p, SEQINSZ, SUB, PDCP_MAC_I_LEN, MATH1, 4, IMMED2);
+
+		MATHB(p, ZERO, ADD, MATH1, VSEQOUTSZ, 4, 0);
+		MATHB(p, ZERO, ADD, MATH1, VSEQINSZ, 4, 0);
+	}
+
+	if (dir == OP_TYPE_ENCAP_PROTOCOL)
+		SEQFIFOSTORE(p, MSG, 0, 0, VLF);
+	else
+		SEQFIFOSTORE(p, MSG, 0, 0, VLF | CONT);
+
+	ALG_OPERATION(p, OP_ALG_ALGSEL_SNOW_F9,
+		      OP_ALG_AAI_F9,
+		      OP_ALG_AS_INITFINAL,
+		      dir == OP_TYPE_ENCAP_PROTOCOL ?
+			     ICV_CHECK_DISABLE : ICV_CHECK_ENABLE,
+		      DIR_DEC);
+	ALG_OPERATION(p, OP_ALG_ALGSEL_AES,
+		      OP_ALG_AAI_CTR,
+		      OP_ALG_AS_INITFINAL,
+		      ICV_CHECK_DISABLE,
+		      dir == OP_TYPE_ENCAP_PROTOCOL ? DIR_ENC : DIR_DEC);
+
+	if (dir == OP_TYPE_ENCAP_PROTOCOL) {
+		SEQFIFOLOAD(p, MSGINSNOOP, 0, VLF | LAST2);
+		MOVE(p, CONTEXT2, 0, IFIFOAB1, 0, 4, LAST1 | FLUSH1 | IMMED);
+	} else {
+		SEQFIFOLOAD(p, MSGOUTSNOOP, 0, VLF | LAST2);
+		SEQFIFOLOAD(p, MSG1, 4, LAST1 | FLUSH1);
+		JUMP(p, 1, LOCAL_JUMP, ALL_TRUE, CLASS1 | NOP | NIFP);
+
+		if (rta_sec_era >= RTA_SEC_ERA_6)
+			LOAD(p, 0, DCTRL, 0, LDLEN_RST_CHA_OFIFO_PTR, IMMED);
+
+		MOVE(p, OFIFO, 0, MATH0, 0, 4, WAITCOMP | IMMED);
+
+		NFIFOADD(p, IFIFO, ICV2, 4, LAST2);
+
+		if (rta_sec_era <= RTA_SEC_ERA_2) {
+			/* Shut off automatic Info FIFO entries */
+			LOAD(p, 0, DCTRL, LDOFF_DISABLE_AUTO_NFIFO, 0, IMMED);
+			MOVE(p, MATH0, 0, IFIFOAB2, 0, 4, WAITCOMP | IMMED);
+		} else {
+			MOVE(p, MATH0, 0, IFIFO, 0, 4, WAITCOMP | IMMED);
+		}
+	}
+
+	return 0;
+}
+
+static inline int
+pdcp_insert_cplane_snow_zuc_op(struct program *p,
+			       bool swap __maybe_unused,
+			       struct alginfo *cipherdata,
+			       struct alginfo *authdata,
+			       unsigned int dir,
+			       unsigned char era_2_sw_hfn_ovrd __maybe_unused)
+{
+	LABEL(keyjump);
+	REFERENCE(pkeyjump);
+
+	if (rta_sec_era < RTA_SEC_ERA_5) {
+		pr_err("Invalid era for selected algorithm\n");
+		return -ENOTSUP;
+	}
+
+	pkeyjump = JUMP(p, keyjump, LOCAL_JUMP, ALL_TRUE, SHRD | SELF | BOTH);
+	KEY(p, KEY1, cipherdata->key_enc_flags, cipherdata->key,
+	    cipherdata->keylen, INLINE_KEY(cipherdata));
+	KEY(p, KEY2, authdata->key_enc_flags, authdata->key, authdata->keylen,
+	    INLINE_KEY(authdata));
+
+	SET_LABEL(p, keyjump);
+
+	if (rta_sec_era >= RTA_SEC_ERA_8) {
+		PROTOCOL(p, dir, OP_PCLID_LTE_PDCP_CTRL_MIXED,
+			 ((uint16_t)cipherdata->algtype << 8) |
+			 (uint16_t)authdata->algtype);
+		return 0;
+	}
+
+	SEQLOAD(p, MATH0, 7, 1, 0);
+	JUMP(p, 1, LOCAL_JUMP, ALL_TRUE, CALM);
+	MOVE(p, MATH0, 7, IFIFOAB2, 0, 1, IMMED);
+	if (swap == false)
+		MATHB(p, MATH0, AND, PDCP_C_PLANE_SN_MASK, MATH1, 8,
+			IFB | IMMED2);
+	else
+		MATHB(p, MATH0, AND, PDCP_C_PLANE_SN_MASK, MATH1, 8,
+			IFB | IMMED2);
+
+	MATHB(p, MATH1, SHLD, MATH1, MATH1, 8, 0);
+	MOVE(p, DESCBUF, 4, MATH2, 0, 8, WAITCOMP | IMMED);
+	MATHB(p, MATH1, OR, MATH2, MATH2, 8, 0);
+	MOVE(p, MATH2, 0, CONTEXT1, 0, 8, IMMED);
+	MOVE(p, MATH2, 0, CONTEXT2, 0, 8, WAITCOMP | IMMED);
+
+	if (dir == OP_TYPE_ENCAP_PROTOCOL)
+		MATHB(p, SEQINSZ, ADD, PDCP_MAC_I_LEN, VSEQOUTSZ, 4, IMMED2);
+	else
+		MATHB(p, SEQINSZ, SUB, PDCP_MAC_I_LEN, VSEQOUTSZ, 4, IMMED2);
+
+	MATHB(p, SEQINSZ, SUB, ZERO, VSEQINSZ, 4, 0);
+	SEQSTORE(p, MATH0, 7, 1, 0);
+
+	if (dir == OP_TYPE_ENCAP_PROTOCOL) {
+		SEQFIFOSTORE(p, MSG, 0, 0, VLF);
+		SEQFIFOLOAD(p, MSGINSNOOP, 0, VLF | LAST2);
+	} else {
+		SEQFIFOSTORE(p, MSG, 0, 0, VLF | CONT);
+		SEQFIFOLOAD(p, MSGOUTSNOOP, 0, VLF | LAST1 | FLUSH1);
+	}
+
+	ALG_OPERATION(p, OP_ALG_ALGSEL_ZUCA,
+		      OP_ALG_AAI_F9,
+		      OP_ALG_AS_INITFINAL,
+		      dir == OP_TYPE_ENCAP_PROTOCOL ?
+			     ICV_CHECK_DISABLE : ICV_CHECK_ENABLE,
+		      DIR_ENC);
+
+	ALG_OPERATION(p, OP_ALG_ALGSEL_SNOW_F8,
+		      OP_ALG_AAI_F8,
+		      OP_ALG_AS_INITFINAL,
+		      ICV_CHECK_DISABLE,
+		      dir == OP_TYPE_ENCAP_PROTOCOL ? DIR_ENC : DIR_DEC);
+	if (dir == OP_TYPE_ENCAP_PROTOCOL) {
+		MOVE(p, CONTEXT2, 0, IFIFOAB1, 0, 4, LAST1 | FLUSH1 | IMMED);
+	} else {
+		/* Save ICV */
+		MOVE(p, OFIFO, 0, MATH0, 0, 4, IMMED);
+		LOAD(p, NFIFOENTRY_STYPE_ALTSOURCE |
+		     NFIFOENTRY_DEST_CLASS2 |
+		     NFIFOENTRY_DTYPE_ICV |
+		     NFIFOENTRY_LC2 | 4, NFIFO_SZL, 0, 4, IMMED);
+		MOVE(p, MATH0, 0, ALTSOURCE, 0, 4, WAITCOMP | IMMED);
+	}
+
+	/* Reset ZUCA mode and done interrupt */
+	LOAD(p, CLRW_CLR_C2MODE, CLRW, 0, 4, IMMED);
+	LOAD(p, CIRQ_ZADI, ICTRL, 0, 4, IMMED);
+
+	PATCH_JUMP(p, pkeyjump, keyjump);
+	return 0;
+}
+
+static inline int
+pdcp_insert_cplane_aes_zuc_op(struct program *p,
+			      bool swap __maybe_unused,
+			      struct alginfo *cipherdata,
+			      struct alginfo *authdata,
+			      unsigned int dir,
+			      unsigned char era_2_sw_hfn_ovrd __maybe_unused)
+{
+	LABEL(keyjump);
+	REFERENCE(pkeyjump);
+
+	if (rta_sec_era < RTA_SEC_ERA_5) {
+		pr_err("Invalid era for selected algorithm\n");
+		return -ENOTSUP;
+	}
+
+	pkeyjump = JUMP(p, keyjump, LOCAL_JUMP, ALL_TRUE, SHRD | SELF | BOTH);
+	KEY(p, KEY1, cipherdata->key_enc_flags, cipherdata->key,
+	    cipherdata->keylen, INLINE_KEY(cipherdata));
+	KEY(p, KEY2, authdata->key_enc_flags, authdata->key, authdata->keylen,
+	    INLINE_KEY(authdata));
+
+	if (rta_sec_era >= RTA_SEC_ERA_8) {
+		PROTOCOL(p, dir, OP_PCLID_LTE_PDCP_CTRL_MIXED,
+			 ((uint16_t)cipherdata->algtype << 8) |
+			 (uint16_t)authdata->algtype);
+
+		return 0;
+	}
+
+	SET_LABEL(p, keyjump);
+	SEQLOAD(p, MATH0, 7, 1, 0);
+	JUMP(p, 1, LOCAL_JUMP, ALL_TRUE, CALM);
+	MOVE(p, MATH0, 7, IFIFOAB2, 0, 1, IMMED);
+	if (swap == false)
+		MATHB(p, MATH0, AND, PDCP_C_PLANE_SN_MASK, MATH1, 8,
+			IFB | IMMED2);
+	else
+		MATHB(p, MATH0, AND, PDCP_C_PLANE_SN_MASK, MATH1, 8,
+			IFB | IMMED2);
+
+	MATHB(p, MATH1, SHLD, MATH1, MATH1, 8, 0);
+	MOVE(p, DESCBUF, 4, MATH2, 0, 8, WAITCOMP | IMMED);
+	MATHB(p, MATH1, OR, MATH2, MATH2, 8, 0);
+	MOVE(p, MATH2, 0, CONTEXT1, 16, 8, IMMED);
+	MOVE(p, MATH2, 0, CONTEXT2, 0, 8, WAITCOMP | IMMED);
+
+	if (dir == OP_TYPE_ENCAP_PROTOCOL)
+		MATHB(p, SEQINSZ, ADD, PDCP_MAC_I_LEN, VSEQOUTSZ, 4, IMMED2);
+	else
+		MATHB(p, SEQINSZ, SUB, PDCP_MAC_I_LEN, VSEQOUTSZ, 4, IMMED2);
+
+	MATHB(p, SEQINSZ, SUB, ZERO, VSEQINSZ, 4, 0);
+	SEQSTORE(p, MATH0, 7, 1, 0);
+
+	if (dir == OP_TYPE_ENCAP_PROTOCOL) {
+		SEQFIFOSTORE(p, MSG, 0, 0, VLF);
+		SEQFIFOLOAD(p, MSGINSNOOP, 0, VLF | LAST2);
+	} else {
+		SEQFIFOSTORE(p, MSG, 0, 0, VLF | CONT);
+		SEQFIFOLOAD(p, MSGOUTSNOOP, 0, VLF | LAST1 | FLUSH1);
+	}
+
+	ALG_OPERATION(p, OP_ALG_ALGSEL_ZUCA,
+		      OP_ALG_AAI_F9,
+		      OP_ALG_AS_INITFINAL,
+		      dir == OP_TYPE_ENCAP_PROTOCOL ?
+			     ICV_CHECK_DISABLE : ICV_CHECK_ENABLE,
+		      DIR_ENC);
+
+	ALG_OPERATION(p, OP_ALG_ALGSEL_AES,
+		      OP_ALG_AAI_CTR,
+		      OP_ALG_AS_INITFINAL,
+		      ICV_CHECK_DISABLE,
+		      dir == OP_TYPE_ENCAP_PROTOCOL ? DIR_ENC : DIR_DEC);
+
+	if (dir == OP_TYPE_ENCAP_PROTOCOL) {
+		MOVE(p, CONTEXT2, 0, IFIFOAB1, 0, 4, LAST1 | FLUSH1 | IMMED);
+	} else {
+		/* Save ICV */
+		MOVE(p, OFIFO, 0, MATH0, 0, 4, IMMED);
+
+		LOAD(p, NFIFOENTRY_STYPE_ALTSOURCE |
+		     NFIFOENTRY_DEST_CLASS2 |
+		     NFIFOENTRY_DTYPE_ICV |
+		     NFIFOENTRY_LC2 | 4, NFIFO_SZL, 0, 4, IMMED);
+		MOVE(p, MATH0, 0, ALTSOURCE, 0, 4, WAITCOMP | IMMED);
+	}
+
+	/* Reset ZUCA mode and done interrupt */
+	LOAD(p, CLRW_CLR_C2MODE, CLRW, 0, 4, IMMED);
+	LOAD(p, CIRQ_ZADI, ICTRL, 0, 4, IMMED);
+
+	PATCH_JUMP(p, pkeyjump, keyjump);
+
+	return 0;
+}
+
+static inline int
+pdcp_insert_cplane_zuc_snow_op(struct program *p,
+			       bool swap __maybe_unused,
+			       struct alginfo *cipherdata,
+			       struct alginfo *authdata,
+			       unsigned int dir,
+			       unsigned char era_2_sw_hfn_ovrd __maybe_unused)
+{
+	LABEL(keyjump);
+	REFERENCE(pkeyjump);
+
+	if (rta_sec_era < RTA_SEC_ERA_5) {
+		pr_err("Invalid era for selected algorithm\n");
+		return -ENOTSUP;
+	}
+
+	pkeyjump = JUMP(p, keyjump, LOCAL_JUMP, ALL_TRUE, SHRD | SELF | BOTH);
+	KEY(p, KEY1, cipherdata->key_enc_flags, cipherdata->key,
+	    cipherdata->keylen, INLINE_KEY(cipherdata));
+	KEY(p, KEY2, authdata->key_enc_flags, authdata->key, authdata->keylen,
+	    INLINE_KEY(authdata));
+
+	if (rta_sec_era >= RTA_SEC_ERA_8) {
+		PROTOCOL(p, dir, OP_PCLID_LTE_PDCP_CTRL_MIXED,
+			 ((uint16_t)cipherdata->algtype << 8) |
+			 (uint16_t)authdata->algtype);
+
+		return 0;
+	}
+
+	SET_LABEL(p, keyjump);
+	SEQLOAD(p, MATH0, 7, 1, 0);
+	JUMP(p, 1, LOCAL_JUMP, ALL_TRUE, CALM);
+	MOVE(p, MATH0, 7, IFIFOAB2, 0, 1, IMMED);
+	if (swap == false)
+		MATHB(p, MATH0, AND, PDCP_C_PLANE_SN_MASK, MATH1, 8,
+			IFB | IMMED2);
+	else
+		MATHB(p, MATH0, AND, PDCP_C_PLANE_SN_MASK, MATH1, 8,
+			IFB | IMMED2);
+
+	MATHB(p, MATH1, SHLD, MATH1, MATH1, 8, 0);
+	MOVE(p, DESCBUF, 4, MATH2, 0, 8, WAITCOMP | IMMED);
+	MATHB(p, MATH1, OR, MATH2, MATH1, 8, 0);
+	MOVE(p, MATH1, 0, CONTEXT1, 0, 8, IMMED);
+	MOVE(p, MATH1, 0, CONTEXT2, 0, 4, IMMED);
+	if (swap == false) {
+		MATHB(p, MATH1, AND, lower_32_bits(PDCP_BEARER_MASK), MATH2,
+			4, IMMED2);
+		MATHB(p, MATH1, AND, upper_32_bits(PDCP_DIR_MASK), MATH3,
+			4, IMMED2);
+	} else {
+		MATHB(p, MATH1, AND, lower_32_bits(PDCP_BEARER_MASK_BE), MATH2,
+			4, IMMED2);
+		MATHB(p, MATH1, AND, upper_32_bits(PDCP_DIR_MASK_BE), MATH3,
+			4, IMMED2);
+	}
+	MATHB(p, MATH3, SHLD, MATH3, MATH3, 8, 0);
+	MOVE(p, MATH2, 4, OFIFO, 0, 12, IMMED);
+	MOVE(p, OFIFO, 0, CONTEXT2, 4, 12, IMMED);
+
+	if (dir == OP_TYPE_ENCAP_PROTOCOL) {
+		MATHB(p, SEQINSZ, ADD, PDCP_MAC_I_LEN, VSEQOUTSZ, 4, IMMED2);
+		MATHB(p, SEQINSZ, SUB, ZERO, VSEQINSZ, 4, 0);
+	} else {
+		MATHB(p, SEQINSZ, SUB, PDCP_MAC_I_LEN, VSEQOUTSZ, 4, IMMED2);
+		MATHB(p, VSEQOUTSZ, SUB, ZERO, VSEQINSZ, 4, 0);
+	}
+
+	SEQSTORE(p, MATH0, 7, 1, 0);
+
+	if (dir == OP_TYPE_ENCAP_PROTOCOL) {
+		SEQFIFOSTORE(p, MSG, 0, 0, VLF);
+		SEQFIFOLOAD(p, MSGINSNOOP, 0, VLF | LAST2);
+	} else {
+		SEQFIFOSTORE(p, MSG, 0, 0, VLF | CONT);
+		SEQFIFOLOAD(p, MSGOUTSNOOP, 0, VLF | LAST2);
+	}
+
+	ALG_OPERATION(p, OP_ALG_ALGSEL_SNOW_F9,
+		      OP_ALG_AAI_F9,
+		      OP_ALG_AS_INITFINAL,
+		      dir == OP_TYPE_ENCAP_PROTOCOL ?
+			     ICV_CHECK_DISABLE : ICV_CHECK_ENABLE,
+		      DIR_DEC);
+
+	ALG_OPERATION(p, OP_ALG_ALGSEL_ZUCE,
+		      OP_ALG_AAI_F8,
+		      OP_ALG_AS_INITFINAL,
+		      ICV_CHECK_DISABLE,
+		      dir == OP_TYPE_ENCAP_PROTOCOL ? DIR_ENC : DIR_DEC);
+
+	if (dir == OP_TYPE_ENCAP_PROTOCOL) {
+		MOVE(p, CONTEXT2, 0, IFIFOAB1, 0, 4, LAST1 | FLUSH1 | IMMED);
+	} else {
+		SEQFIFOLOAD(p, MSG1, 4, LAST1 | FLUSH1);
+		JUMP(p, 1, LOCAL_JUMP, ALL_TRUE, CLASS1 | NOP | NIFP);
+
+		if (rta_sec_era >= RTA_SEC_ERA_6)
+			/*
+			 * For SEC ERA 6, there's a problem with the OFIFO
+			 * pointer, and thus it needs to be reset here before
+			 * moving to M0.
+			 */
+			LOAD(p, 0, DCTRL, 0, LDLEN_RST_CHA_OFIFO_PTR, IMMED);
+
+		/* Put ICV to M0 before sending it to C2 for comparison. */
+		MOVE(p, OFIFO, 0, MATH0, 0, 4, WAITCOMP | IMMED);
+
+		LOAD(p, NFIFOENTRY_STYPE_ALTSOURCE |
+		     NFIFOENTRY_DEST_CLASS2 |
+		     NFIFOENTRY_DTYPE_ICV |
+		     NFIFOENTRY_LC2 | 4, NFIFO_SZL, 0, 4, IMMED);
+		MOVE(p, MATH0, 0, ALTSOURCE, 0, 4, IMMED);
+	}
+
+	PATCH_JUMP(p, pkeyjump, keyjump);
+	return 0;
+}
+
+static inline int
+pdcp_insert_cplane_zuc_aes_op(struct program *p,
+			      bool swap __maybe_unused,
+			      struct alginfo *cipherdata,
+			      struct alginfo *authdata,
+			      unsigned int dir,
+			      unsigned char era_2_sw_hfn_ovrd __maybe_unused)
+{
+	if (rta_sec_era < RTA_SEC_ERA_5) {
+		pr_err("Invalid era for selected algorithm\n");
+		return -ENOTSUP;
+	}
+
+	if (rta_sec_era >= RTA_SEC_ERA_8) {
+		KEY(p, KEY1, cipherdata->key_enc_flags, cipherdata->key,
+				cipherdata->keylen, INLINE_KEY(cipherdata));
+		KEY(p, KEY2, authdata->key_enc_flags, authdata->key,
+				authdata->keylen, INLINE_KEY(authdata));
+
+		PROTOCOL(p, dir, OP_PCLID_LTE_PDCP_CTRL_MIXED,
+			 ((uint16_t)cipherdata->algtype << 8) |
+			 (uint16_t)authdata->algtype);
+		return 0;
+	}
+
+	SEQLOAD(p, MATH0, 7, 1, 0);
+	JUMP(p, 1, LOCAL_JUMP, ALL_TRUE, CALM);
+	if (swap == false)
+		MATHB(p, MATH0, AND, PDCP_C_PLANE_SN_MASK, MATH1, 8,
+			IFB | IMMED2);
+	else
+		MATHB(p, MATH0, AND, PDCP_C_PLANE_SN_MASK, MATH1, 8,
+			IFB | IMMED2);
+
+	MATHB(p, MATH1, SHLD, MATH1, MATH1, 8, 0);
+	MOVE(p, DESCBUF, 4, MATH2, 0, 0x08, WAITCOMP | IMMED);
+	MATHB(p, MATH1, OR, MATH2, MATH2, 8, 0);
+	SEQSTORE(p, MATH0, 7, 1, 0);
+	if (dir == OP_TYPE_ENCAP_PROTOCOL) {
+		KEY(p, KEY1, authdata->key_enc_flags, authdata->key,
+		    authdata->keylen, INLINE_KEY(authdata));
+		MOVE(p, MATH2, 0, IFIFOAB1, 0, 0x08, IMMED);
+		MOVE(p, MATH0, 7, IFIFOAB1, 0, 1, IMMED);
+
+		MATHB(p, SEQINSZ, SUB, ZERO, VSEQINSZ, 4, 0);
+		MATHB(p, VSEQINSZ, ADD, PDCP_MAC_I_LEN, VSEQOUTSZ, 4, IMMED2);
+
+		ALG_OPERATION(p, OP_ALG_ALGSEL_AES,
+			      OP_ALG_AAI_CMAC,
+			      OP_ALG_AS_INITFINAL,
+			      ICV_CHECK_DISABLE,
+			      DIR_DEC);
+		SEQFIFOLOAD(p, MSG1, 0, VLF | LAST1 | FLUSH1);
+		MOVE(p, CONTEXT1, 0, MATH3, 0, 4, WAITCOMP | IMMED);
+		LOAD(p, CLRW_RESET_CLS1_CHA |
+		     CLRW_CLR_C1KEY |
+		     CLRW_CLR_C1CTX |
+		     CLRW_CLR_C1ICV |
+		     CLRW_CLR_C1DATAS |
+		     CLRW_CLR_C1MODE,
+		     CLRW, 0, 4, IMMED);
+
+		KEY(p, KEY1, cipherdata->key_enc_flags, cipherdata->key,
+		    cipherdata->keylen, INLINE_KEY(cipherdata));
+
+		MOVE(p, MATH2, 0, CONTEXT1, 0, 8, IMMED);
+		SEQINPTR(p, 0, PDCP_NULL_MAX_FRAME_LEN, RTO);
+
+		ALG_OPERATION(p, OP_ALG_ALGSEL_ZUCE,
+			      OP_ALG_AAI_F8,
+			      OP_ALG_AS_INITFINAL,
+			      ICV_CHECK_DISABLE,
+			      DIR_ENC);
+		SEQFIFOSTORE(p, MSG, 0, 0, VLF);
+
+		SEQFIFOLOAD(p, SKIP, 1, 0);
+
+		SEQFIFOLOAD(p, MSG1, 0, VLF);
+		MOVE(p, MATH3, 0, IFIFOAB1, 0, 4, LAST1 | FLUSH1 | IMMED);
+	} else {
+		MOVE(p, MATH2, 0, CONTEXT1, 0, 8, IMMED);
+
+		MOVE(p, CONTEXT1, 0, CONTEXT2, 0, 8, IMMED);
+
+		MATHB(p, SEQINSZ, SUB, ZERO, VSEQINSZ, 4, 0);
+
+		MATHB(p, SEQINSZ, SUB, PDCP_MAC_I_LEN, VSEQOUTSZ, 4, IMMED2);
+
+		KEY(p, KEY1, cipherdata->key_enc_flags, cipherdata->key,
+		    cipherdata->keylen, INLINE_KEY(cipherdata));
+
+		MOVE(p, CONTEXT1, 0, CONTEXT2, 0, 8, IMMED);
+
+		ALG_OPERATION(p, OP_ALG_ALGSEL_ZUCE,
+			      OP_ALG_AAI_F8,
+			      OP_ALG_AS_INITFINAL,
+			      ICV_CHECK_DISABLE,
+			      DIR_DEC);
+		SEQFIFOSTORE(p, MSG, 0, 0, VLF | CONT);
+		SEQFIFOLOAD(p, MSG1, 0, VLF | LAST1 | FLUSH1);
+
+		MOVE(p, OFIFO, 0, MATH3, 0, 4, IMMED);
+
+		LOAD(p, CLRW_RESET_CLS1_CHA |
+		     CLRW_CLR_C1KEY |
+		     CLRW_CLR_C1CTX |
+		     CLRW_CLR_C1ICV |
+		     CLRW_CLR_C1DATAS |
+		     CLRW_CLR_C1MODE,
+		     CLRW, 0, 4, IMMED);
+
+		KEY(p, KEY1, authdata->key_enc_flags, authdata->key,
+		    authdata->keylen, INLINE_KEY(authdata));
+
+		SEQINPTR(p, 0, 0, SOP);
+
+		ALG_OPERATION(p, OP_ALG_ALGSEL_AES,
+			      OP_ALG_AAI_CMAC,
+			      OP_ALG_AS_INITFINAL,
+			      ICV_CHECK_ENABLE,
+			      DIR_DEC);
+
+		MATHB(p, SEQINSZ, SUB, ZERO, VSEQINSZ, 4, 0);
+
+		MOVE(p, CONTEXT2, 0, IFIFOAB1, 0, 8, IMMED);
+
+		SEQFIFOLOAD(p, MSG1, 0, VLF | LAST1 | FLUSH1);
+
+		LOAD(p, NFIFOENTRY_STYPE_ALTSOURCE |
+		     NFIFOENTRY_DEST_CLASS1 |
+		     NFIFOENTRY_DTYPE_ICV |
+		     NFIFOENTRY_LC1 |
+		     NFIFOENTRY_FC1 | 4, NFIFO_SZL, 0, 4, IMMED);
+		MOVE(p, MATH3, 0, ALTSOURCE, 0, 4, IMMED);
+	}
+
+	return 0;
+}
+
+static inline int
+pdcp_insert_uplane_15bit_op(struct program *p,
+			    bool swap __maybe_unused,
+			    struct alginfo *cipherdata,
+			    unsigned int dir)
+{
+	int op;
+	/* Insert Cipher Key */
+	KEY(p, KEY1, cipherdata->key_enc_flags, cipherdata->key,
+	    cipherdata->keylen, INLINE_KEY(cipherdata));
+
+	if (rta_sec_era >= RTA_SEC_ERA_8) {
+		PROTOCOL(p, dir, OP_PCLID_LTE_PDCP_USER,
+			 (uint16_t)cipherdata->algtype);
+		return 0;
+	}
+
+	SEQLOAD(p, MATH0, 6, 2, 0);
+	JUMP(p, 1, LOCAL_JUMP, ALL_TRUE, CALM);
+	if (swap == false)
+		MATHB(p, MATH0, AND, PDCP_U_PLANE_15BIT_SN_MASK, MATH1, 8,
+		      IFB | IMMED2);
+	else
+		MATHB(p, MATH0, AND, PDCP_U_PLANE_15BIT_SN_MASK_BE, MATH1, 8,
+		      IFB | IMMED2);
+	SEQSTORE(p, MATH0, 6, 2, 0);
+	MATHB(p, MATH1, SHLD, MATH1, MATH1, 8, 0);
+	MOVE(p, DESCBUF, 8, MATH2, 0, 8, WAITCOMP | IMMED);
+	MATHB(p, MATH1, OR, MATH2, MATH2, 8, 0);
+
+	MATHB(p, SEQINSZ, SUB, MATH3, VSEQINSZ, 4, 0);
+	MATHB(p, SEQINSZ, SUB, MATH3, VSEQOUTSZ, 4, 0);
+
+	SEQFIFOSTORE(p, MSG, 0, 0, VLF);
+
+	op = dir == OP_TYPE_ENCAP_PROTOCOL ? DIR_ENC : DIR_DEC;
+	switch (cipherdata->algtype) {
+	case PDCP_CIPHER_TYPE_SNOW:
+		MOVE(p, MATH2, 0, CONTEXT1, 0, 8, WAITCOMP | IMMED);
+		ALG_OPERATION(p, OP_ALG_ALGSEL_SNOW_F8,
+			      OP_ALG_AAI_F8,
+			      OP_ALG_AS_INITFINAL,
+			      ICV_CHECK_DISABLE,
+			      op);
+		break;
+
+	case PDCP_CIPHER_TYPE_AES:
+		MOVE(p, MATH2, 0, CONTEXT1, 0x10, 0x10, WAITCOMP | IMMED);
+		ALG_OPERATION(p, OP_ALG_ALGSEL_AES,
+			      OP_ALG_AAI_CTR,
+			      OP_ALG_AS_INITFINAL,
+			      ICV_CHECK_DISABLE,
+			      op);
+		break;
+
+	case PDCP_CIPHER_TYPE_ZUC:
+		if (rta_sec_era < RTA_SEC_ERA_5) {
+			pr_err("Invalid era for selected algorithm\n");
+			return -ENOTSUP;
+		}
+		MOVE(p, MATH2, 0, CONTEXT1, 0, 0x08, IMMED);
+		MOVE(p, MATH2, 0, CONTEXT1, 0x08, 0x08, WAITCOMP | IMMED);
+
+		ALG_OPERATION(p, OP_ALG_ALGSEL_ZUCE,
+			      OP_ALG_AAI_F8,
+			      OP_ALG_AS_INITFINAL,
+			      ICV_CHECK_DISABLE,
+			      op);
+		break;
+
+	default:
+		pr_err("%s: Invalid encrypt algorithm selected: %d\n",
+		       "pdcp_insert_uplane_15bit_op", cipherdata->algtype);
+		return -EINVAL;
+	}
+
+	SEQFIFOLOAD(p, MSG1, 0, VLF | LAST1 | FLUSH1);
+
+	return 0;
+}
+
+/*
+ * Function for inserting the snippet of code responsible for creating
+ * the HFN override code via either DPOVRD or via the input frame.
+ */
+static inline int
+insert_hfn_ov_op(struct program *p,
+		 uint32_t shift,
+		 enum pdb_type_e pdb_type,
+		 unsigned char era_2_sw_hfn_ovrd)
+{
+	uint32_t imm = PDCP_DPOVRD_HFN_OV_EN;
+	uint16_t hfn_pdb_offset;
+
+	if (rta_sec_era == RTA_SEC_ERA_2 && !era_2_sw_hfn_ovrd)
+		return 0;
+
+	switch (pdb_type) {
+	case PDCP_PDB_TYPE_NO_PDB:
+		/*
+		 * If there is no PDB, then HFN override mechanism does not
+		 * make any sense, thus in this case the function will
+		 * return the pointer to the current position in the
+		 * descriptor buffer
+		 */
+		return 0;
+
+	case PDCP_PDB_TYPE_REDUCED_PDB:
+		hfn_pdb_offset = 4;
+		break;
+
+	case PDCP_PDB_TYPE_FULL_PDB:
+		hfn_pdb_offset = 8;
+		break;
+
+	default:
+		return -EINVAL;
+	}
+
+	if (rta_sec_era > RTA_SEC_ERA_2) {
+		MATHB(p, DPOVRD, AND, imm, NONE, 8, IFB | IMMED2);
+	} else {
+		SEQLOAD(p, MATH0, 4, 4, 0);
+		JUMP(p, 1, LOCAL_JUMP, ALL_TRUE, CALM);
+		MATHB(p, MATH0, AND, imm, NONE, 8, IFB | IMMED2);
+		SEQSTORE(p, MATH0, 4, 4, 0);
+	}
+
+	if (rta_sec_era >= RTA_SEC_ERA_8)
+		JUMP(p, 6, LOCAL_JUMP, ALL_TRUE, MATH_Z);
+	else
+		JUMP(p, 5, LOCAL_JUMP, ALL_TRUE, MATH_Z);
+
+	if (rta_sec_era > RTA_SEC_ERA_2)
+		MATHB(p, DPOVRD, LSHIFT, shift, MATH0, 4, IMMED2);
+	else
+		MATHB(p, MATH0, LSHIFT, shift, MATH0, 4, IMMED2);
+
+	MATHB(p, MATH0, SHLD, MATH0, MATH0, 8, 0);
+	MOVE(p, MATH0, 0, DESCBUF, hfn_pdb_offset, 4, IMMED);
+
+	if (rta_sec_era >= RTA_SEC_ERA_8)
+		/*
+		 * For ERA8, DPOVRD could be handled by the PROTOCOL command
+		 * itself. For now, this is not done. Thus, clear DPOVRD here
+		 * to alleviate any side-effects.
+		 */
+		MATHB(p, DPOVRD, AND, ZERO, DPOVRD, 4, STL);
+
+	return 0;
+}
+
+/*
+ * PDCP Control PDB creation function
+ */
+static inline enum pdb_type_e
+cnstr_pdcp_c_plane_pdb(struct program *p,
+		       uint32_t hfn,
+		       unsigned char bearer,
+		       unsigned char direction,
+		       uint32_t hfn_threshold,
+		       struct alginfo *cipherdata,
+		       struct alginfo *authdata)
+{
+	struct pdcp_pdb pdb;
+	enum pdb_type_e
+		pdb_mask[PDCP_CIPHER_TYPE_INVALID][PDCP_AUTH_TYPE_INVALID] = {
+			{	/* NULL */
+				PDCP_PDB_TYPE_NO_PDB,		/* NULL */
+				PDCP_PDB_TYPE_FULL_PDB,		/* SNOW f9 */
+				PDCP_PDB_TYPE_FULL_PDB,		/* AES CMAC */
+				PDCP_PDB_TYPE_FULL_PDB		/* ZUC-I */
+			},
+			{	/* SNOW f8 */
+				PDCP_PDB_TYPE_FULL_PDB,		/* NULL */
+				PDCP_PDB_TYPE_FULL_PDB,		/* SNOW f9 */
+				PDCP_PDB_TYPE_REDUCED_PDB,	/* AES CMAC */
+				PDCP_PDB_TYPE_REDUCED_PDB	/* ZUC-I */
+			},
+			{	/* AES CTR */
+				PDCP_PDB_TYPE_FULL_PDB,		/* NULL */
+				PDCP_PDB_TYPE_REDUCED_PDB,	/* SNOW f9 */
+				PDCP_PDB_TYPE_FULL_PDB,		/* AES CMAC */
+				PDCP_PDB_TYPE_REDUCED_PDB	/* ZUC-I */
+			},
+			{	/* ZUC-E */
+				PDCP_PDB_TYPE_FULL_PDB,		/* NULL */
+				PDCP_PDB_TYPE_REDUCED_PDB,	/* SNOW f9 */
+				PDCP_PDB_TYPE_REDUCED_PDB,	/* AES CMAC */
+				PDCP_PDB_TYPE_FULL_PDB		/* ZUC-I */
+			},
+	};
+
+	if (rta_sec_era >= RTA_SEC_ERA_8) {
+		memset(&pdb, 0x00, sizeof(struct pdcp_pdb));
+
+		/* This is a HW issue. Bit 2 should be set to zero,
+		 * but it does not work this way. Override here.
+		 */
+		pdb.opt_res.rsvd = 0x00000002;
+
+		/* Copy relevant information from user to PDB */
+		pdb.hfn_res = hfn << PDCP_C_PLANE_PDB_HFN_SHIFT;
+		pdb.bearer_dir_res = (uint32_t)
+				((bearer << PDCP_C_PLANE_PDB_BEARER_SHIFT) |
+				 (direction << PDCP_C_PLANE_PDB_DIR_SHIFT));
+		pdb.hfn_thr_res =
+				hfn_threshold << PDCP_C_PLANE_PDB_HFN_THR_SHIFT;
+
+		/* copy PDB in descriptor*/
+		__rta_out32(p, pdb.opt_res.opt);
+		__rta_out32(p, pdb.hfn_res);
+		__rta_out32(p, pdb.bearer_dir_res);
+		__rta_out32(p, pdb.hfn_thr_res);
+
+		return PDCP_PDB_TYPE_FULL_PDB;
+	}
+
+	switch (pdb_mask[cipherdata->algtype][authdata->algtype]) {
+	case PDCP_PDB_TYPE_NO_PDB:
+		break;
+
+	case PDCP_PDB_TYPE_REDUCED_PDB:
+		__rta_out32(p, (hfn << PDCP_C_PLANE_PDB_HFN_SHIFT));
+		__rta_out32(p,
+			    (uint32_t)((bearer <<
+					PDCP_C_PLANE_PDB_BEARER_SHIFT) |
+					(direction <<
+					 PDCP_C_PLANE_PDB_DIR_SHIFT)));
+		break;
+
+	case PDCP_PDB_TYPE_FULL_PDB:
+		memset(&pdb, 0x00, sizeof(struct pdcp_pdb));
+
+		/* This is a HW issue. Bit 2 should be set to zero,
+		 * but it does not work this way. Override here.
+		 */
+		pdb.opt_res.rsvd = 0x00000002;
+
+		/* Copy relevant information from user to PDB */
+		pdb.hfn_res = hfn << PDCP_C_PLANE_PDB_HFN_SHIFT;
+		pdb.bearer_dir_res = (uint32_t)
+			((bearer << PDCP_C_PLANE_PDB_BEARER_SHIFT) |
+			 (direction << PDCP_C_PLANE_PDB_DIR_SHIFT));
+		pdb.hfn_thr_res =
+			hfn_threshold << PDCP_C_PLANE_PDB_HFN_THR_SHIFT;
+
+		/* copy PDB in descriptor*/
+		__rta_out32(p, pdb.opt_res.opt);
+		__rta_out32(p, pdb.hfn_res);
+		__rta_out32(p, pdb.bearer_dir_res);
+		__rta_out32(p, pdb.hfn_thr_res);
+
+		break;
+
+	default:
+		return PDCP_PDB_TYPE_INVALID;
+	}
+
+	return pdb_mask[cipherdata->algtype][authdata->algtype];
+}
+
+/*
+ * PDCP UPlane PDB creation function
+ */
+static inline int
+cnstr_pdcp_u_plane_pdb(struct program *p,
+		       enum pdcp_sn_size sn_size,
+		       uint32_t hfn, unsigned short bearer,
+		       unsigned short direction,
+		       uint32_t hfn_threshold)
+{
+	struct pdcp_pdb pdb;
+	/* Read options from user */
+	/* Depending on sequence number length, the HFN and HFN threshold
+	 * have different lengths.
+	 */
+	memset(&pdb, 0x00, sizeof(struct pdcp_pdb));
+
+	switch (sn_size) {
+	case PDCP_SN_SIZE_7:
+		pdb.opt_res.opt |= PDCP_U_PLANE_PDB_OPT_SHORT_SN;
+		pdb.hfn_res = hfn << PDCP_U_PLANE_PDB_SHORT_SN_HFN_SHIFT;
+		pdb.hfn_thr_res =
+			hfn_threshold<<PDCP_U_PLANE_PDB_SHORT_SN_HFN_THR_SHIFT;
+		break;
+
+	case PDCP_SN_SIZE_12:
+		pdb.opt_res.opt &= (uint32_t)(~PDCP_U_PLANE_PDB_OPT_SHORT_SN);
+		pdb.hfn_res = hfn << PDCP_U_PLANE_PDB_LONG_SN_HFN_SHIFT;
+		pdb.hfn_thr_res =
+			hfn_threshold<<PDCP_U_PLANE_PDB_LONG_SN_HFN_THR_SHIFT;
+		break;
+
+	case PDCP_SN_SIZE_15:
+		pdb.opt_res.opt = (uint32_t)(PDCP_U_PLANE_PDB_OPT_15B_SN);
+		pdb.hfn_res = hfn << PDCP_U_PLANE_PDB_15BIT_SN_HFN_SHIFT;
+		pdb.hfn_thr_res =
+			hfn_threshold<<PDCP_U_PLANE_PDB_15BIT_SN_HFN_THR_SHIFT;
+		break;
+
+	default:
+		pr_err("Invalid Sequence Number Size setting in PDB\n");
+		return -EINVAL;
+	}
+
+	pdb.bearer_dir_res = (uint32_t)
+				((bearer << PDCP_U_PLANE_PDB_BEARER_SHIFT) |
+				 (direction << PDCP_U_PLANE_PDB_DIR_SHIFT));
+
+	/* copy PDB in descriptor*/
+	__rta_out32(p, pdb.opt_res.opt);
+	__rta_out32(p, pdb.hfn_res);
+	__rta_out32(p, pdb.bearer_dir_res);
+	__rta_out32(p, pdb.hfn_thr_res);
+
+	return 0;
+}
+/**
+ * cnstr_shdsc_pdcp_c_plane_encap - Function for creating a PDCP Control Plane
+ *                                  encapsulation descriptor.
+ * @descbuf: pointer to buffer for descriptor construction
+ * @ps: if 36/40bit addressing is desired, this parameter must be true
+ * @swap: must be true when core endianness doesn't match SEC endianness
+ * @hfn: starting Hyper Frame Number to be used together with the SN from the
+ *       PDCP frames.
+ * @bearer: radio bearer ID
+ * @direction: the direction of the PDCP frame (UL/DL)
+ * @hfn_threshold: HFN value that once reached triggers a warning from SEC that
+ *                 keys should be renegotiated at the earliest convenience.
+ * @cipherdata: pointer to block cipher transform definitions
+ *              Valid algorithm values are those from cipher_type_pdcp enum.
+ * @authdata: pointer to authentication transform definitions
+ *            Valid algorithm values are those from auth_type_pdcp enum.
+ * @era_2_sw_hfn_ovrd: if software HFN override mechanism is desired for
+ *                     this descriptor. Note: Can only be used for
+ *                     SEC ERA 2.
+ * Return: size of descriptor written in words or negative number on error.
+ *         Once the function returns, the value of this parameter can be used
+ *         for reclaiming the space that wasn't used for the descriptor.
+ *
+ * Note: descbuf must be large enough to contain a full 256 byte long
+ * descriptor; after the function returns, by subtracting the actual number of
+ * bytes used, the user can reuse the remaining buffer space for other purposes.
+ */
+static inline int
+cnstr_shdsc_pdcp_c_plane_encap(uint32_t *descbuf,
+			       bool ps,
+			       bool swap,
+			       uint32_t hfn,
+			       unsigned char bearer,
+			       unsigned char direction,
+			       uint32_t hfn_threshold,
+			       struct alginfo *cipherdata,
+			       struct alginfo *authdata,
+			       unsigned char era_2_sw_hfn_ovrd)
+{
+	static int
+		(*pdcp_cp_fp[PDCP_CIPHER_TYPE_INVALID][PDCP_AUTH_TYPE_INVALID])
+			(struct program*, bool swap, struct alginfo *,
+			 struct alginfo *, unsigned int,
+			unsigned char __maybe_unused) = {
+		{	/* NULL */
+			pdcp_insert_cplane_null_op,	/* NULL */
+			pdcp_insert_cplane_int_only_op,	/* SNOW f9 */
+			pdcp_insert_cplane_int_only_op,	/* AES CMAC */
+			pdcp_insert_cplane_int_only_op	/* ZUC-I */
+		},
+		{	/* SNOW f8 */
+			pdcp_insert_cplane_enc_only_op,	/* NULL */
+			pdcp_insert_cplane_acc_op,	/* SNOW f9 */
+			pdcp_insert_cplane_snow_aes_op,	/* AES CMAC */
+			pdcp_insert_cplane_snow_zuc_op	/* ZUC-I */
+		},
+		{	/* AES CTR */
+			pdcp_insert_cplane_enc_only_op,	/* NULL */
+			pdcp_insert_cplane_aes_snow_op,	/* SNOW f9 */
+			pdcp_insert_cplane_acc_op,	/* AES CMAC */
+			pdcp_insert_cplane_aes_zuc_op	/* ZUC-I */
+		},
+		{	/* ZUC-E */
+			pdcp_insert_cplane_enc_only_op,	/* NULL */
+			pdcp_insert_cplane_zuc_snow_op,	/* SNOW f9 */
+			pdcp_insert_cplane_zuc_aes_op,	/* AES CMAC */
+			pdcp_insert_cplane_acc_op	/* ZUC-I */
+		},
+	};
+	static enum rta_share_type
+		desc_share[PDCP_CIPHER_TYPE_INVALID][PDCP_AUTH_TYPE_INVALID] = {
+		{	/* NULL */
+			SHR_WAIT,	/* NULL */
+			SHR_ALWAYS,	/* SNOW f9 */
+			SHR_ALWAYS,	/* AES CMAC */
+			SHR_ALWAYS	/* ZUC-I */
+		},
+		{	/* SNOW f8 */
+			SHR_ALWAYS,	/* NULL */
+			SHR_ALWAYS,	/* SNOW f9 */
+			SHR_WAIT,	/* AES CMAC */
+			SHR_WAIT	/* ZUC-I */
+		},
+		{	/* AES CTR */
+			SHR_ALWAYS,	/* NULL */
+			SHR_ALWAYS,	/* SNOW f9 */
+			SHR_ALWAYS,	/* AES CMAC */
+			SHR_WAIT	/* ZUC-I */
+		},
+		{	/* ZUC-E */
+			SHR_ALWAYS,	/* NULL */
+			SHR_WAIT,	/* SNOW f9 */
+			SHR_WAIT,	/* AES CMAC */
+			SHR_ALWAYS	/* ZUC-I */
+		},
+	};
+	enum pdb_type_e pdb_type;
+	struct program prg;
+	struct program *p = &prg;
+	int err;
+	LABEL(pdb_end);
+
+	if (rta_sec_era != RTA_SEC_ERA_2 && era_2_sw_hfn_ovrd) {
+		pr_err("Cannot select SW HFN override for other era than 2");
+		return -EINVAL;
+	}
+
+	PROGRAM_CNTXT_INIT(p, descbuf, 0);
+	if (swap)
+		PROGRAM_SET_BSWAP(p);
+	if (ps)
+		PROGRAM_SET_36BIT_ADDR(p);
+
+	SHR_HDR(p, desc_share[cipherdata->algtype][authdata->algtype], 0, 0);
+
+	pdb_type = cnstr_pdcp_c_plane_pdb(p,
+			hfn,
+			bearer,
+			direction,
+			hfn_threshold,
+			cipherdata,
+			authdata);
+
+	SET_LABEL(p, pdb_end);
+
+	err = insert_hfn_ov_op(p, PDCP_SN_SIZE_5, pdb_type,
+			       era_2_sw_hfn_ovrd);
+	if (err)
+		return err;
+
+	err = pdcp_cp_fp[cipherdata->algtype][authdata->algtype](p,
+		swap,
+		cipherdata,
+		authdata,
+		OP_TYPE_ENCAP_PROTOCOL,
+		era_2_sw_hfn_ovrd);
+	if (err)
+		return err;
+
+	PATCH_HDR(p, 0, pdb_end);
+
+	return PROGRAM_FINALIZE(p);
+}
+
+/**
+ * cnstr_shdsc_pdcp_c_plane_decap - Function for creating a PDCP Control Plane
+ *                                  decapsulation descriptor.
+ * @descbuf: pointer to buffer for descriptor construction
+ * @ps: if 36/40bit addressing is desired, this parameter must be true
+ * @swap: must be true when core endianness doesn't match SEC endianness
+ * @hfn: starting Hyper Frame Number to be used together with the SN from the
+ *       PDCP frames.
+ * @bearer: radio bearer ID
+ * @direction: the direction of the PDCP frame (UL/DL)
+ * @hfn_threshold: HFN value that once reached triggers a warning from SEC that
+ *                 keys should be renegotiated at the earliest convenience.
+ * @cipherdata: pointer to block cipher transform definitions
+ *              Valid algorithm values are those from cipher_type_pdcp enum.
+ * @authdata: pointer to authentication transform definitions
+ *            Valid algorithm values are those from auth_type_pdcp enum.
+ * @era_2_sw_hfn_ovrd: if software HFN override mechanism is desired for
+ *                     this descriptor. Note: Can only be used for
+ *                     SEC ERA 2.
+ *
+ * Return: size of descriptor written in words or negative number on error.
+ *         Once the function returns, the value of this parameter can be used
+ *         for reclaiming the space that wasn't used for the descriptor.
+ *
+ * Note: descbuf must be large enough to contain a full 256 byte long
+ * descriptor; after the function returns, by subtracting the actual number of
+ * bytes used, the user can reuse the remaining buffer space for other purposes.
+ */
+static inline int
+cnstr_shdsc_pdcp_c_plane_decap(uint32_t *descbuf,
+			       bool ps,
+			       bool swap,
+			       uint32_t hfn,
+			       unsigned char bearer,
+			       unsigned char direction,
+			       uint32_t hfn_threshold,
+			       struct alginfo *cipherdata,
+			       struct alginfo *authdata,
+			       unsigned char era_2_sw_hfn_ovrd)
+{
+	static int
+		(*pdcp_cp_fp[PDCP_CIPHER_TYPE_INVALID][PDCP_AUTH_TYPE_INVALID])
+			(struct program*, bool swap, struct alginfo *,
+			 struct alginfo *, unsigned int, unsigned char) = {
+		{	/* NULL */
+			pdcp_insert_cplane_null_op,	/* NULL */
+			pdcp_insert_cplane_int_only_op,	/* SNOW f9 */
+			pdcp_insert_cplane_int_only_op,	/* AES CMAC */
+			pdcp_insert_cplane_int_only_op	/* ZUC-I */
+		},
+		{	/* SNOW f8 */
+			pdcp_insert_cplane_enc_only_op,	/* NULL */
+			pdcp_insert_cplane_acc_op,	/* SNOW f9 */
+			pdcp_insert_cplane_snow_aes_op,	/* AES CMAC */
+			pdcp_insert_cplane_snow_zuc_op	/* ZUC-I */
+		},
+		{	/* AES CTR */
+			pdcp_insert_cplane_enc_only_op,	/* NULL */
+			pdcp_insert_cplane_aes_snow_op,	/* SNOW f9 */
+			pdcp_insert_cplane_acc_op,	/* AES CMAC */
+			pdcp_insert_cplane_aes_zuc_op	/* ZUC-I */
+		},
+		{	/* ZUC-E */
+			pdcp_insert_cplane_enc_only_op,	/* NULL */
+			pdcp_insert_cplane_zuc_snow_op,	/* SNOW f9 */
+			pdcp_insert_cplane_zuc_aes_op,	/* AES CMAC */
+			pdcp_insert_cplane_acc_op	/* ZUC-I */
+		},
+	};
+	static enum rta_share_type
+		desc_share[PDCP_CIPHER_TYPE_INVALID][PDCP_AUTH_TYPE_INVALID] = {
+		{	/* NULL */
+			SHR_WAIT,	/* NULL */
+			SHR_ALWAYS,	/* SNOW f9 */
+			SHR_ALWAYS,	/* AES CMAC */
+			SHR_ALWAYS	/* ZUC-I */
+		},
+		{	/* SNOW f8 */
+			SHR_ALWAYS,	/* NULL */
+			SHR_ALWAYS,	/* SNOW f9 */
+			SHR_WAIT,	/* AES CMAC */
+			SHR_WAIT	/* ZUC-I */
+		},
+		{	/* AES CTR */
+			SHR_ALWAYS,	/* NULL */
+			SHR_ALWAYS,	/* SNOW f9 */
+			SHR_ALWAYS,	/* AES CMAC */
+			SHR_WAIT	/* ZUC-I */
+		},
+		{	/* ZUC-E */
+			SHR_ALWAYS,	/* NULL */
+			SHR_WAIT,	/* SNOW f9 */
+			SHR_WAIT,	/* AES CMAC */
+			SHR_ALWAYS	/* ZUC-I */
+		},
+	};
+	enum pdb_type_e pdb_type;
+	struct program prg;
+	struct program *p = &prg;
+	int err;
+	LABEL(pdb_end);
+
+	if (rta_sec_era != RTA_SEC_ERA_2 && era_2_sw_hfn_ovrd) {
+		pr_err("Cannot select SW HFN override for other era than 2");
+		return -EINVAL;
+	}
+
+	PROGRAM_CNTXT_INIT(p, descbuf, 0);
+	if (swap)
+		PROGRAM_SET_BSWAP(p);
+	if (ps)
+		PROGRAM_SET_36BIT_ADDR(p);
+
+	SHR_HDR(p, desc_share[cipherdata->algtype][authdata->algtype], 0, 0);
+
+	pdb_type = cnstr_pdcp_c_plane_pdb(p,
+			hfn,
+			bearer,
+			direction,
+			hfn_threshold,
+			cipherdata,
+			authdata);
+
+	SET_LABEL(p, pdb_end);
+
+	err = insert_hfn_ov_op(p, PDCP_SN_SIZE_5, pdb_type,
+			       era_2_sw_hfn_ovrd);
+	if (err)
+		return err;
+
+	err = pdcp_cp_fp[cipherdata->algtype][authdata->algtype](p,
+		swap,
+		cipherdata,
+		authdata,
+		OP_TYPE_DECAP_PROTOCOL,
+		era_2_sw_hfn_ovrd);
+	if (err)
+		return err;
+
+	PATCH_HDR(p, 0, pdb_end);
+
+	return PROGRAM_FINALIZE(p);
+}
+
+/**
+ * cnstr_shdsc_pdcp_u_plane_encap - Function for creating a PDCP User Plane
+ *                                  encapsulation descriptor.
+ * @descbuf: pointer to buffer for descriptor construction
+ * @ps: if 36/40bit addressing is desired, this parameter must be true
+ * @swap: must be true when core endianness doesn't match SEC endianness
+ * @sn_size: selects Sequence Number Size: 7/12/15 bits
+ * @hfn: starting Hyper Frame Number to be used together with the SN from the
+ *       PDCP frames.
+ * @bearer: radio bearer ID
+ * @direction: the direction of the PDCP frame (UL/DL)
+ * @hfn_threshold: HFN value that once reached triggers a warning from SEC that
+ *                 keys should be renegotiated at the earliest convenience.
+ * @cipherdata: pointer to block cipher transform definitions
+ *              Valid algorithm values are those from cipher_type_pdcp enum.
+ * @era_2_sw_hfn_ovrd: if software HFN override mechanism is desired for
+ *                     this descriptor. Note: Can only be used for
+ *                     SEC ERA 2.
+ *
+ * Return: size of descriptor written in words or negative number on error.
+ *         Once the function returns, the value of this parameter can be used
+ *         for reclaiming the space that wasn't used for the descriptor.
+ *
+ * Note: descbuf must be large enough to contain a full 256 byte long
+ * descriptor; after the function returns, by subtracting the actual number of
+ * bytes used, the user can reuse the remaining buffer space for other purposes.
+ */
+static inline int
+cnstr_shdsc_pdcp_u_plane_encap(uint32_t *descbuf,
+			       bool ps,
+			       bool swap,
+			       enum pdcp_sn_size sn_size,
+			       uint32_t hfn,
+			       unsigned short bearer,
+			       unsigned short direction,
+			       uint32_t hfn_threshold,
+			       struct alginfo *cipherdata,
+			       unsigned char era_2_sw_hfn_ovrd)
+{
+	struct program prg;
+	struct program *p = &prg;
+	int err;
+	LABEL(pdb_end);
+
+	if (rta_sec_era != RTA_SEC_ERA_2 && era_2_sw_hfn_ovrd) {
+		pr_err("Cannot select SW HFN ovrd for other era than 2");
+		return -EINVAL;
+	}
+
+	PROGRAM_CNTXT_INIT(p, descbuf, 0);
+	if (swap)
+		PROGRAM_SET_BSWAP(p);
+	if (ps)
+		PROGRAM_SET_36BIT_ADDR(p);
+
+	SHR_HDR(p, SHR_ALWAYS, 0, 0);
+	if (cnstr_pdcp_u_plane_pdb(p, sn_size, hfn, bearer, direction,
+				   hfn_threshold)) {
+		pr_err("Error creating PDCP UPlane PDB\n");
+		return -EINVAL;
+	}
+	SET_LABEL(p, pdb_end);
+
+	err = insert_hfn_ov_op(p, sn_size, PDCP_PDB_TYPE_FULL_PDB,
+			       era_2_sw_hfn_ovrd);
+	if (err)
+		return err;
+
+	switch (sn_size) {
+	case PDCP_SN_SIZE_7:
+	case PDCP_SN_SIZE_12:
+		switch (cipherdata->algtype) {
+		case PDCP_CIPHER_TYPE_ZUC:
+			if (rta_sec_era < RTA_SEC_ERA_5) {
+				pr_err("Invalid era for selected algorithm\n");
+				return -ENOTSUP;
+			}
+		case PDCP_CIPHER_TYPE_AES:
+		case PDCP_CIPHER_TYPE_SNOW:
+			/* Insert Cipher Key */
+			KEY(p, KEY1, cipherdata->key_enc_flags,
+			    (uint64_t)cipherdata->key, cipherdata->keylen,
+			    INLINE_KEY(cipherdata));
+			PROTOCOL(p, OP_TYPE_ENCAP_PROTOCOL,
+				 OP_PCLID_LTE_PDCP_USER,
+				 (uint16_t)cipherdata->algtype);
+			break;
+		case PDCP_CIPHER_TYPE_NULL:
+			insert_copy_frame_op(p,
+					     cipherdata,
+					     OP_TYPE_ENCAP_PROTOCOL);
+			break;
+		default:
+			pr_err("%s: Invalid encrypt algorithm selected: %d\n",
+			       "cnstr_pcl_shdsc_pdcp_u_plane_decap",
+			       cipherdata->algtype);
+			return -EINVAL;
+		}
+		break;
+
+	case PDCP_SN_SIZE_15:
+		switch (cipherdata->algtype) {
+		case PDCP_CIPHER_TYPE_NULL:
+			insert_copy_frame_op(p,
+					     cipherdata,
+					     OP_TYPE_ENCAP_PROTOCOL);
+			break;
+
+		default:
+			err = pdcp_insert_uplane_15bit_op(p, swap, cipherdata,
+				OP_TYPE_ENCAP_PROTOCOL);
+			if (err)
+				return err;
+			break;
+		}
+		break;
+
+	case PDCP_SN_SIZE_5:
+	default:
+		pr_err("Invalid SN size selected\n");
+		return -ENOTSUP;
+	}
+
+	PATCH_HDR(p, 0, pdb_end);
+	return PROGRAM_FINALIZE(p);
+}
+
+/**
+ * cnstr_shdsc_pdcp_u_plane_decap - Function for creating a PDCP User Plane
+ *                                  decapsulation descriptor.
+ * @descbuf: pointer to buffer for descriptor construction
+ * @ps: if 36/40bit addressing is desired, this parameter must be true
+ * @swap: must be true when core endianness doesn't match SEC endianness
+ * @sn_size: selects Sequence Number Size: 7/12/15 bits
+ * @hfn: starting Hyper Frame Number to be used together with the SN from the
+ *       PDCP frames.
+ * @bearer: radio bearer ID
+ * @direction: the direction of the PDCP frame (UL/DL)
+ * @hfn_threshold: HFN value that once reached triggers a warning from SEC that
+ *                 keys should be renegotiated at the earliest convenience.
+ * @cipherdata: pointer to block cipher transform definitions
+ *              Valid algorithm values are those from cipher_type_pdcp enum.
+ * @era_2_sw_hfn_ovrd: if software HFN override mechanism is desired for
+ *                     this descriptor. Note: Can only be used for
+ *                     SEC ERA 2.
+ *
+ * Return: size of descriptor written in words or negative number on error.
+ *         Once the function returns, the value of this parameter can be used
+ *         for reclaiming the space that wasn't used for the descriptor.
+ *
+ * Note: descbuf must be large enough to contain a full 256 byte long
+ * descriptor; after the function returns, by subtracting the actual number of
+ * bytes used, the user can reuse the remaining buffer space for other purposes.
+ */
+static inline int
+cnstr_shdsc_pdcp_u_plane_decap(uint32_t *descbuf,
+			       bool ps,
+			       bool swap,
+			       enum pdcp_sn_size sn_size,
+			       uint32_t hfn,
+			       unsigned short bearer,
+			       unsigned short direction,
+			       uint32_t hfn_threshold,
+			       struct alginfo *cipherdata,
+			       unsigned char era_2_sw_hfn_ovrd)
+{
+	struct program prg;
+	struct program *p = &prg;
+	int err;
+	LABEL(pdb_end);
+
+	if (rta_sec_era != RTA_SEC_ERA_2 && era_2_sw_hfn_ovrd) {
+		pr_err("Cannot select SW HFN override for other era than 2");
+		return -EINVAL;
+	}
+
+	PROGRAM_CNTXT_INIT(p, descbuf, 0);
+	if (swap)
+		PROGRAM_SET_BSWAP(p);
+	if (ps)
+		PROGRAM_SET_36BIT_ADDR(p);
+
+	SHR_HDR(p, SHR_ALWAYS, 0, 0);
+	if (cnstr_pdcp_u_plane_pdb(p, sn_size, hfn, bearer, direction,
+				   hfn_threshold)) {
+		pr_err("Error creating PDCP UPlane PDB\n");
+		return -EINVAL;
+	}
+	SET_LABEL(p, pdb_end);
+
+	err = insert_hfn_ov_op(p, sn_size, PDCP_PDB_TYPE_FULL_PDB,
+			       era_2_sw_hfn_ovrd);
+	if (err)
+		return err;
+
+	switch (sn_size) {
+	case PDCP_SN_SIZE_7:
+	case PDCP_SN_SIZE_12:
+		switch (cipherdata->algtype) {
+		case PDCP_CIPHER_TYPE_ZUC:
+			if (rta_sec_era < RTA_SEC_ERA_5) {
+				pr_err("Invalid era for selected algorithm\n");
+				return -ENOTSUP;
+			}
+		case PDCP_CIPHER_TYPE_AES:
+		case PDCP_CIPHER_TYPE_SNOW:
+			/* Insert Cipher Key */
+			KEY(p, KEY1, cipherdata->key_enc_flags,
+			    cipherdata->key, cipherdata->keylen,
+			    INLINE_KEY(cipherdata));
+			PROTOCOL(p, OP_TYPE_DECAP_PROTOCOL,
+				 OP_PCLID_LTE_PDCP_USER,
+				 (uint16_t)cipherdata->algtype);
+			break;
+		case PDCP_CIPHER_TYPE_NULL:
+			insert_copy_frame_op(p,
+					     cipherdata,
+					     OP_TYPE_DECAP_PROTOCOL);
+			break;
+		default:
+			pr_err("%s: Invalid encrypt algorithm selected: %d\n",
+			       "cnstr_pcl_shdsc_pdcp_u_plane_decap",
+			       cipherdata->algtype);
+			return -EINVAL;
+		}
+		break;
+
+	case PDCP_SN_SIZE_15:
+		switch (cipherdata->algtype) {
+		case PDCP_CIPHER_TYPE_NULL:
+			insert_copy_frame_op(p,
+					     cipherdata,
+					     OP_TYPE_DECAP_PROTOCOL);
+			break;
+
+		default:
+			err = pdcp_insert_uplane_15bit_op(p, swap, cipherdata,
+				OP_TYPE_DECAP_PROTOCOL);
+			if (err)
+				return err;
+			break;
+		}
+		break;
+
+	case PDCP_SN_SIZE_5:
+	default:
+		pr_err("Invalid SN size selected\n");
+		return -ENOTSUP;
+	}
+
+	PATCH_HDR(p, 0, pdb_end);
+	return PROGRAM_FINALIZE(p);
+}
+
+/**
+ * cnstr_shdsc_pdcp_short_mac - Function for creating a PDCP Short MAC
+ *                              descriptor.
+ * @descbuf: pointer to buffer for descriptor construction
+ * @ps: if 36/40bit addressing is desired, this parameter must be true
+ * @swap: must be true when core endianness doesn't match SEC endianness
+ * @authdata: pointer to authentication transform definitions
+ *            Valid algorithm values are those from auth_type_pdcp enum.
+ *
+ * Return: size of descriptor written in words or negative number on error.
+ *         Once the function returns, the value of this parameter can be used
+ *         for reclaiming the space that wasn't used for the descriptor.
+ *
+ * Note: descbuf must be large enough to contain a full 256 byte long
+ * descriptor; after the function returns, by subtracting the actual number of
+ * bytes used, the user can reuse the remaining buffer space for other purposes.
+ */
+static inline int
+cnstr_shdsc_pdcp_short_mac(uint32_t *descbuf,
+			   bool ps,
+			   bool swap,
+			   struct alginfo *authdata)
+{
+	struct program prg;
+	struct program *p = &prg;
+	uint32_t iv[3] = {0, 0, 0};
+	LABEL(local_offset);
+	REFERENCE(move_cmd_read_descbuf);
+	REFERENCE(move_cmd_write_descbuf);
+
+	PROGRAM_CNTXT_INIT(p, descbuf, 0);
+	if (swap)
+		PROGRAM_SET_BSWAP(p);
+	if (ps)
+		PROGRAM_SET_36BIT_ADDR(p);
+
+	SHR_HDR(p, SHR_ALWAYS, 1, 0);
+
+	if (rta_sec_era > RTA_SEC_ERA_2) {
+		MATHB(p, SEQINSZ, SUB, ZERO, VSEQINSZ, 4, 0);
+		MATHB(p, SEQINSZ, SUB, ZERO, MATH1, 4, 0);
+	} else {
+		MATHB(p, SEQINSZ, ADD, ONE, MATH1, 4, 0);
+		MATHB(p, MATH1, SUB, ONE, MATH1, 4, 0);
+		MATHB(p, ZERO, ADD, MATH1, VSEQINSZ, 4, 0);
+		MOVE(p, MATH1, 0, MATH0, 0, 8, IMMED);
+
+		/*
+		 * Since MOVELEN is available only starting with
+		 * SEC ERA 3, use poor man's MOVELEN: create a MOVE
+		 * command dynamically by writing the length from M1 by
+		 * OR-ing the command in the M1 register and MOVE the
+		 * result into the descriptor buffer. Care must be taken
+		 * wrt. the location of the command because of SEC
+		 * pipelining. The actual MOVEs are written at the end
+		 * of the descriptor due to calculations needed on the
+		 * offset in the descriptor for the MOVE command.
+		 */
+		move_cmd_read_descbuf = MOVE(p, DESCBUF, 0, MATH0, 0, 6,
+					     IMMED);
+		move_cmd_write_descbuf = MOVE(p, MATH0, 0, DESCBUF, 0, 8,
+					      WAITCOMP | IMMED);
+	}
+	MATHB(p, ZERO, ADD, MATH1, VSEQOUTSZ, 4, 0);
+
+	switch (authdata->algtype) {
+	case PDCP_AUTH_TYPE_NULL:
+		SEQFIFOSTORE(p, MSG, 0, 0, VLF);
+		if (rta_sec_era > RTA_SEC_ERA_2) {
+			MOVE(p, AB1, 0, OFIFO, 0, MATH1, 0);
+		} else {
+			SET_LABEL(p, local_offset);
+
+			/* Shut off automatic Info FIFO entries */
+			LOAD(p, 0, DCTRL, LDOFF_DISABLE_AUTO_NFIFO, 0, IMMED);
+
+			/* Placeholder for MOVE command with length from M1
+			 * register
+			 */
+			MOVE(p, IFIFOAB1, 0, OFIFO, 0, 0, IMMED);
+
+			/* Enable automatic Info FIFO entries */
+			LOAD(p, 0, DCTRL, LDOFF_ENABLE_AUTO_NFIFO, 0, IMMED);
+		}
+
+		LOAD(p, (uintptr_t)iv, MATH0, 0, 8, IMMED | COPY);
+		SEQFIFOLOAD(p, MSG1, 0, VLF | LAST1 | LAST2 | FLUSH1);
+		SEQSTORE(p, MATH0, 0, 4, 0);
+
+		break;
+
+	case PDCP_AUTH_TYPE_SNOW:
+		iv[0] = 0xFFFFFFFF;
+		iv[1] = swap ? swab32(0x04000000) : 0x04000000;
+		iv[2] = swap ? swab32(0xF8000000) : 0xF8000000;
+
+		KEY(p, KEY2, authdata->key_enc_flags, authdata->key,
+		    authdata->keylen, INLINE_KEY(authdata));
+		LOAD(p, (uintptr_t)&iv, CONTEXT2, 0, 12, IMMED | COPY);
+		ALG_OPERATION(p, OP_ALG_ALGSEL_SNOW_F9,
+			      OP_ALG_AAI_F9,
+			      OP_ALG_AS_INITFINAL,
+			      ICV_CHECK_DISABLE,
+			      DIR_ENC);
+		SEQFIFOSTORE(p, MSG, 0, 0, VLF);
+
+		if (rta_sec_era > RTA_SEC_ERA_2) {
+			MOVE(p, AB1, 0, OFIFO, 0, MATH1, 0);
+		} else {
+			SET_LABEL(p, local_offset);
+
+
+			/* Shut off automatic Info FIFO entries */
+			LOAD(p, 0, DCTRL, LDOFF_DISABLE_AUTO_NFIFO, 0, IMMED);
+
+			/* Placeholder for MOVE command with length from M1
+			 * register
+			 */
+			MOVE(p, IFIFOAB1, 0, OFIFO, 0, 0, IMMED);
+
+			/* Enable automatic Info FIFO entries */
+			LOAD(p, 0, DCTRL, LDOFF_ENABLE_AUTO_NFIFO, 0, IMMED);
+		}
+		SEQFIFOLOAD(p, MSGINSNOOP, 0, VLF | LAST1 | LAST2 | FLUSH1);
+		SEQSTORE(p, CONTEXT2, 0, 4, 0);
+
+		break;
+
+	case PDCP_AUTH_TYPE_AES:
+		iv[0] = 0xFFFFFFFF;
+		iv[1] = swap ? swab32(0xFC000000) : 0xFC000000;
+		iv[2] = 0x00000000; /* unused */
+
+		KEY(p, KEY1, authdata->key_enc_flags, authdata->key,
+		    authdata->keylen, INLINE_KEY(authdata));
+		LOAD(p, (uintptr_t)&iv, MATH0, 0, 8, IMMED | COPY);
+		MOVE(p, MATH0, 0, IFIFOAB1, 0, 8, IMMED);
+		ALG_OPERATION(p, OP_ALG_ALGSEL_AES,
+			      OP_ALG_AAI_CMAC,
+			      OP_ALG_AS_INITFINAL,
+			      ICV_CHECK_DISABLE,
+			      DIR_ENC);
+		SEQFIFOSTORE(p, MSG, 0, 0, VLF);
+
+		if (rta_sec_era > RTA_SEC_ERA_2) {
+			MOVE(p, AB2, 0, OFIFO, 0, MATH1, 0);
+		} else {
+			SET_LABEL(p, local_offset);
+
+			/* Shut off automatic Info FIFO entries */
+			LOAD(p, 0, DCTRL, LDOFF_DISABLE_AUTO_NFIFO, 0, IMMED);
+
+			/* Placeholder for MOVE command with length from M1
+			 * register
+			 */
+			MOVE(p, IFIFOAB2, 0, OFIFO, 0, 0, IMMED);
+
+			/* Enable automatic Info FIFO entries */
+			LOAD(p, 0, DCTRL, LDOFF_ENABLE_AUTO_NFIFO, 0, IMMED);
+		}
+		SEQFIFOLOAD(p, MSGINSNOOP, 0, VLF | LAST1 | LAST2 | FLUSH1);
+		SEQSTORE(p, CONTEXT1, 0, 4, 0);
+
+		break;
+
+	case PDCP_AUTH_TYPE_ZUC:
+		if (rta_sec_era < RTA_SEC_ERA_5) {
+			pr_err("Invalid era for selected algorithm\n");
+			return -ENOTSUP;
+		}
+		iv[0] = 0xFFFFFFFF;
+		iv[1] = swap ? swab32(0xFC000000) : 0xFC000000;
+		iv[2] = 0x00000000; /* unused */
+
+		KEY(p, KEY2, authdata->key_enc_flags, authdata->key,
+		    authdata->keylen, INLINE_KEY(authdata));
+		LOAD(p, (uintptr_t)&iv, CONTEXT2, 0, 12, IMMED | COPY);
+		ALG_OPERATION(p, OP_ALG_ALGSEL_ZUCA,
+			      OP_ALG_AAI_F9,
+			      OP_ALG_AS_INITFINAL,
+			      ICV_CHECK_DISABLE,
+			      DIR_ENC);
+		SEQFIFOSTORE(p, MSG, 0, 0, VLF);
+		MOVE(p, AB1, 0, OFIFO, 0, MATH1, 0);
+		SEQFIFOLOAD(p, MSGINSNOOP, 0, VLF | LAST1 | LAST2 | FLUSH1);
+		SEQSTORE(p, CONTEXT2, 0, 4, 0);
+
+		break;
+
+	default:
+		pr_err("%s: Invalid integrity algorithm selected: %d\n",
+		       "cnstr_shdsc_pdcp_short_mac", authdata->algtype);
+		return -EINVAL;
+	}
+
+
+	if (rta_sec_era < RTA_SEC_ERA_3) {
+		PATCH_MOVE(p, move_cmd_read_descbuf, local_offset);
+		PATCH_MOVE(p, move_cmd_write_descbuf, local_offset);
+	}
+
+	return PROGRAM_FINALIZE(p);
+}
+
+#endif /* __DESC_PDCP_H__ */
-- 
2.7.4

^ permalink raw reply	[flat|nested] 41+ messages in thread

* [dpdk-dev] [PATCH v6 3/3] crypto/dpaa2_sec: support pdcp offload
  2018-10-22  7:12         ` [dpdk-dev] [PATCH v6 " Hemant Agrawal
  2018-10-22  7:12           ` [dpdk-dev] [PATCH v6 1/3] security: support pdcp protocol Hemant Agrawal
  2018-10-22  7:12           ` [dpdk-dev] [PATCH v6 2/3] crypto/dpaa2_sec: add sample pdcp descriptor apis Hemant Agrawal
@ 2018-10-22  7:12           ` Hemant Agrawal
  2 siblings, 0 replies; 41+ messages in thread
From: Hemant Agrawal @ 2018-10-22  7:12 UTC (permalink / raw)
  To: dev
  Cc: thomas, pablo.de.lara.guarch, radu.nicolau, jerin.jacob,
	narayanaprasad.athreya, Shally.Verma, Anoob.Joseph,
	Vidya.Velumuri, akhil.goyal

From: Akhil Goyal <akhil.goyal@nxp.com>

PDCP session configuration for lookaside protocol offload
and data path is added.

Signed-off-by: Hemant Agrawal <hemant.agrawal@nxp.com>
Signed-off-by: Akhil Goyal <akhil.goyal@nxp.com>
---
 drivers/crypto/dpaa2_sec/dpaa2_sec_dpseci.c | 258 ++++++++++++++++++++++++++++
 drivers/crypto/dpaa2_sec/dpaa2_sec_priv.h   | 208 +++++++++++++++++++++-
 2 files changed, 458 insertions(+), 8 deletions(-)

diff --git a/drivers/crypto/dpaa2_sec/dpaa2_sec_dpseci.c b/drivers/crypto/dpaa2_sec/dpaa2_sec_dpseci.c
index 0336d5f..e5c3e7b 100644
--- a/drivers/crypto/dpaa2_sec/dpaa2_sec_dpseci.c
+++ b/drivers/crypto/dpaa2_sec/dpaa2_sec_dpseci.c
@@ -35,6 +35,7 @@ typedef uint64_t	dma_addr_t;
 
 /* RTA header files */
 #include <hw/desc/ipsec.h>
+#include <hw/desc/pdcp.h>
 #include <hw/desc/algo.h>
 
 /* Minimum job descriptor consists of a oneword job descriptor HEADER and
@@ -74,6 +75,9 @@ build_proto_compound_fd(dpaa2_sec_session *sess,
 	struct rte_mbuf *dst_mbuf = sym_op->m_dst;
 	int retval;
 
+	if (!dst_mbuf)
+		dst_mbuf = src_mbuf;
+
 	/* Save the shared descriptor */
 	flc = &priv->flc_desc[0].flc;
 
@@ -118,6 +122,15 @@ build_proto_compound_fd(dpaa2_sec_session *sess,
 	DPAA2_SET_FD_LEN(fd, ip_fle->length);
 	DPAA2_SET_FLE_FIN(ip_fle);
 
+#ifdef ENABLE_HFN_OVERRIDE
+	if (sess->ctxt_type == DPAA2_SEC_PDCP && sess->pdcp.hfn_ovd) {
+		/*enable HFN override override */
+		DPAA2_SET_FLE_INTERNAL_JD(ip_fle, sess->pdcp.hfn_ovd);
+		DPAA2_SET_FLE_INTERNAL_JD(op_fle, sess->pdcp.hfn_ovd);
+		DPAA2_SET_FD_INTERNAL_JD(fd, sess->pdcp.hfn_ovd);
+	}
+#endif
+
 	return 0;
 
 }
@@ -1188,6 +1201,9 @@ build_sec_fd(struct rte_crypto_op *op,
 		case DPAA2_SEC_IPSEC:
 			ret = build_proto_fd(sess, op, fd, bpid);
 			break;
+		case DPAA2_SEC_PDCP:
+			ret = build_proto_compound_fd(sess, op, fd, bpid);
+			break;
 		case DPAA2_SEC_HASH_CIPHER:
 		default:
 			DPAA2_SEC_ERR("error: Unsupported session");
@@ -2552,6 +2568,244 @@ dpaa2_sec_set_ipsec_session(struct rte_cryptodev *dev,
 }
 
 static int
+dpaa2_sec_set_pdcp_session(struct rte_cryptodev *dev,
+			   struct rte_security_session_conf *conf,
+			   void *sess)
+{
+	struct rte_security_pdcp_xform *pdcp_xform = &conf->pdcp;
+	struct rte_crypto_sym_xform *xform = conf->crypto_xform;
+	struct rte_crypto_auth_xform *auth_xform = NULL;
+	struct rte_crypto_cipher_xform *cipher_xform;
+	dpaa2_sec_session *session = (dpaa2_sec_session *)sess;
+	struct ctxt_priv *priv;
+	struct dpaa2_sec_dev_private *dev_priv = dev->data->dev_private;
+	struct alginfo authdata, cipherdata;
+	int bufsize = -1;
+	struct sec_flow_context *flc;
+#if RTE_BYTE_ORDER == RTE_BIG_ENDIAN
+	int swap = true;
+#else
+	int swap = false;
+#endif
+
+	PMD_INIT_FUNC_TRACE();
+
+	memset(session, 0, sizeof(dpaa2_sec_session));
+
+	priv = (struct ctxt_priv *)rte_zmalloc(NULL,
+				sizeof(struct ctxt_priv) +
+				sizeof(struct sec_flc_desc),
+				RTE_CACHE_LINE_SIZE);
+
+	if (priv == NULL) {
+		DPAA2_SEC_ERR("No memory for priv CTXT");
+		return -ENOMEM;
+	}
+
+	priv->fle_pool = dev_priv->fle_pool;
+	flc = &priv->flc_desc[0].flc;
+
+	/* find xfrm types */
+	if (xform->type == RTE_CRYPTO_SYM_XFORM_CIPHER && xform->next == NULL) {
+		cipher_xform = &xform->cipher;
+	} else if (xform->type == RTE_CRYPTO_SYM_XFORM_CIPHER &&
+		   xform->next->type == RTE_CRYPTO_SYM_XFORM_AUTH) {
+		session->ext_params.aead_ctxt.auth_cipher_text = true;
+		cipher_xform = &xform->cipher;
+		auth_xform = &xform->next->auth;
+	} else if (xform->type == RTE_CRYPTO_SYM_XFORM_AUTH &&
+		   xform->next->type == RTE_CRYPTO_SYM_XFORM_CIPHER) {
+		session->ext_params.aead_ctxt.auth_cipher_text = false;
+		cipher_xform = &xform->next->cipher;
+		auth_xform = &xform->auth;
+	} else {
+		DPAA2_SEC_ERR("Invalid crypto type");
+		return -EINVAL;
+	}
+
+	session->ctxt_type = DPAA2_SEC_PDCP;
+	if (cipher_xform) {
+		session->cipher_key.data = rte_zmalloc(NULL,
+					       cipher_xform->key.length,
+					       RTE_CACHE_LINE_SIZE);
+		if (session->cipher_key.data == NULL &&
+				cipher_xform->key.length > 0) {
+			DPAA2_SEC_ERR("No Memory for cipher key");
+			rte_free(priv);
+			return -ENOMEM;
+		}
+		session->cipher_key.length = cipher_xform->key.length;
+		memcpy(session->cipher_key.data, cipher_xform->key.data,
+			cipher_xform->key.length);
+		session->dir =
+			(cipher_xform->op == RTE_CRYPTO_CIPHER_OP_ENCRYPT) ?
+					DIR_ENC : DIR_DEC;
+		session->cipher_alg = cipher_xform->algo;
+	} else {
+		session->cipher_key.data = NULL;
+		session->cipher_key.length = 0;
+		session->cipher_alg = RTE_CRYPTO_CIPHER_NULL;
+		session->dir = DIR_ENC;
+	}
+
+	session->pdcp.domain = pdcp_xform->domain;
+	session->pdcp.bearer = pdcp_xform->bearer;
+	session->pdcp.pkt_dir = pdcp_xform->pkt_dir;
+	session->pdcp.sn_size = pdcp_xform->sn_size;
+#ifdef ENABLE_HFN_OVERRIDE
+	session->pdcp.hfn_ovd = pdcp_xform->hfn_ovd;
+#endif
+	session->pdcp.hfn = pdcp_xform->hfn;
+	session->pdcp.hfn_threshold = pdcp_xform->hfn_threshold;
+
+	cipherdata.key = (size_t)session->cipher_key.data;
+	cipherdata.keylen = session->cipher_key.length;
+	cipherdata.key_enc_flags = 0;
+	cipherdata.key_type = RTA_DATA_IMM;
+
+	switch (session->cipher_alg) {
+	case RTE_CRYPTO_CIPHER_SNOW3G_UEA2:
+		cipherdata.algtype = PDCP_CIPHER_TYPE_SNOW;
+		break;
+	case RTE_CRYPTO_CIPHER_ZUC_EEA3:
+		cipherdata.algtype = PDCP_CIPHER_TYPE_ZUC;
+		break;
+	case RTE_CRYPTO_CIPHER_AES_CTR:
+		cipherdata.algtype = PDCP_CIPHER_TYPE_AES;
+		break;
+	case RTE_CRYPTO_CIPHER_NULL:
+		cipherdata.algtype = PDCP_CIPHER_TYPE_NULL;
+		break;
+	default:
+		DPAA2_SEC_ERR("Crypto: Undefined Cipher specified %u",
+			      session->cipher_alg);
+		goto out;
+	}
+
+	/* Auth is only applicable for control mode operation. */
+	if (pdcp_xform->domain == RTE_SECURITY_PDCP_MODE_CONTROL) {
+		if (pdcp_xform->sn_size != RTE_SECURITY_PDCP_SN_SIZE_5) {
+			DPAA2_SEC_ERR(
+				"PDCP Seq Num size should be 5 bits for cmode");
+			goto out;
+		}
+		if (auth_xform) {
+			session->auth_key.data = rte_zmalloc(NULL,
+							auth_xform->key.length,
+							RTE_CACHE_LINE_SIZE);
+			if (session->auth_key.data == NULL &&
+					auth_xform->key.length > 0) {
+				DPAA2_SEC_ERR("No Memory for auth key");
+				rte_free(session->cipher_key.data);
+				rte_free(priv);
+				return -ENOMEM;
+			}
+			session->auth_key.length = auth_xform->key.length;
+			memcpy(session->auth_key.data, auth_xform->key.data,
+					auth_xform->key.length);
+			session->auth_alg = auth_xform->algo;
+		} else {
+			session->auth_key.data = NULL;
+			session->auth_key.length = 0;
+			session->auth_alg = RTE_CRYPTO_AUTH_NULL;
+		}
+		authdata.key = (size_t)session->auth_key.data;
+		authdata.keylen = session->auth_key.length;
+		authdata.key_enc_flags = 0;
+		authdata.key_type = RTA_DATA_IMM;
+
+		switch (session->auth_alg) {
+		case RTE_CRYPTO_AUTH_SNOW3G_UIA2:
+			authdata.algtype = PDCP_AUTH_TYPE_SNOW;
+			break;
+		case RTE_CRYPTO_AUTH_ZUC_EIA3:
+			authdata.algtype = PDCP_AUTH_TYPE_ZUC;
+			break;
+		case RTE_CRYPTO_AUTH_AES_CMAC:
+			authdata.algtype = PDCP_AUTH_TYPE_AES;
+			break;
+		case RTE_CRYPTO_AUTH_NULL:
+			authdata.algtype = PDCP_AUTH_TYPE_NULL;
+			break;
+		default:
+			DPAA2_SEC_ERR("Crypto: Unsupported auth alg %u",
+				      session->auth_alg);
+			goto out;
+		}
+
+		if (session->dir == DIR_ENC)
+			bufsize = cnstr_shdsc_pdcp_c_plane_encap(
+					priv->flc_desc[0].desc, 1, swap,
+					pdcp_xform->hfn,
+					pdcp_xform->bearer,
+					pdcp_xform->pkt_dir,
+					pdcp_xform->hfn_threshold,
+					&cipherdata, &authdata,
+					0);
+		else if (session->dir == DIR_DEC)
+			bufsize = cnstr_shdsc_pdcp_c_plane_decap(
+					priv->flc_desc[0].desc, 1, swap,
+					pdcp_xform->hfn,
+					pdcp_xform->bearer,
+					pdcp_xform->pkt_dir,
+					pdcp_xform->hfn_threshold,
+					&cipherdata, &authdata,
+					0);
+	} else {
+		if (session->dir == DIR_ENC)
+			bufsize = cnstr_shdsc_pdcp_u_plane_encap(
+					priv->flc_desc[0].desc, 1, swap,
+					(enum pdcp_sn_size)pdcp_xform->sn_size,
+					pdcp_xform->hfn,
+					pdcp_xform->bearer,
+					pdcp_xform->pkt_dir,
+					pdcp_xform->hfn_threshold,
+					&cipherdata, 0);
+		else if (session->dir == DIR_DEC)
+			bufsize = cnstr_shdsc_pdcp_u_plane_decap(
+					priv->flc_desc[0].desc, 1, swap,
+					(enum pdcp_sn_size)pdcp_xform->sn_size,
+					pdcp_xform->hfn,
+					pdcp_xform->bearer,
+					pdcp_xform->pkt_dir,
+					pdcp_xform->hfn_threshold,
+					&cipherdata, 0);
+	}
+
+	if (bufsize < 0) {
+		DPAA2_SEC_ERR("Crypto: Invalid buffer length");
+		goto out;
+	}
+
+	/* Enable the stashing control bit */
+	DPAA2_SET_FLC_RSC(flc);
+	flc->word2_rflc_31_0 = lower_32_bits(
+			(size_t)&(((struct dpaa2_sec_qp *)
+			dev->data->queue_pairs[0])->rx_vq) | 0x14);
+	flc->word3_rflc_63_32 = upper_32_bits(
+			(size_t)&(((struct dpaa2_sec_qp *)
+			dev->data->queue_pairs[0])->rx_vq));
+
+	flc->word1_sdl = (uint8_t)bufsize;
+
+	/* Set EWS bit i.e. enable write-safe */
+	DPAA2_SET_FLC_EWS(flc);
+	/* Set BS = 1 i.e reuse input buffers as output buffers */
+	DPAA2_SET_FLC_REUSE_BS(flc);
+	/* Set FF = 10; reuse input buffers if they provide sufficient space */
+	DPAA2_SET_FLC_REUSE_FF(flc);
+
+	session->ctxt = priv;
+
+	return 0;
+out:
+	rte_free(session->auth_key.data);
+	rte_free(session->cipher_key.data);
+	rte_free(priv);
+	return -1;
+}
+
+static int
 dpaa2_sec_security_session_create(void *dev,
 				  struct rte_security_session_conf *conf,
 				  struct rte_security_session *sess,
@@ -2573,6 +2827,10 @@ dpaa2_sec_security_session_create(void *dev,
 		break;
 	case RTE_SECURITY_PROTOCOL_MACSEC:
 		return -ENOTSUP;
+	case RTE_SECURITY_PROTOCOL_PDCP:
+		ret = dpaa2_sec_set_pdcp_session(cdev, conf,
+				sess_private_data);
+		break;
 	default:
 		return -EINVAL;
 	}
diff --git a/drivers/crypto/dpaa2_sec/dpaa2_sec_priv.h b/drivers/crypto/dpaa2_sec/dpaa2_sec_priv.h
index bce9633..5175110 100644
--- a/drivers/crypto/dpaa2_sec/dpaa2_sec_priv.h
+++ b/drivers/crypto/dpaa2_sec/dpaa2_sec_priv.h
@@ -137,6 +137,19 @@ struct dpaa2_sec_aead_ctxt {
 	uint8_t auth_cipher_text;       /**< Authenticate/cipher ordering */
 };
 
+/*
+ * The structure is to be filled by user for PDCP Protocol
+ */
+struct dpaa2_pdcp_ctxt {
+	enum rte_security_pdcp_domain domain; /*!< Data/Control mode*/
+	int8_t bearer;	/*!< PDCP bearer ID */
+	int8_t pkt_dir;/*!< PDCP Frame Direction 0:UL 1:DL*/
+	int8_t hfn_ovd;/*!< Overwrite HFN per packet*/
+	uint32_t hfn;	/*!< Hyper Frame Number */
+	uint32_t hfn_threshold;	/*!< HFN Threashold for key renegotiation */
+	uint8_t sn_size;	/*!< Sequence number size, 7/12/15 */
+};
+
 typedef struct dpaa2_sec_session_entry {
 	void *ctxt;
 	uint8_t ctxt_type;
@@ -160,15 +173,20 @@ typedef struct dpaa2_sec_session_entry {
 			} auth_key;
 		};
 	};
-	struct {
-		uint16_t length; /**< IV length in bytes */
-		uint16_t offset; /**< IV offset in bytes */
-	} iv;
-	uint16_t digest_length;
-	uint8_t status;
 	union {
-		struct dpaa2_sec_aead_ctxt aead_ctxt;
-	} ext_params;
+		struct {
+			struct {
+				uint16_t length; /**< IV length in bytes */
+				uint16_t offset; /**< IV offset in bytes */
+			} iv;
+			uint16_t digest_length;
+			uint8_t status;
+			union {
+				struct dpaa2_sec_aead_ctxt aead_ctxt;
+			} ext_params;
+		};
+		struct dpaa2_pdcp_ctxt pdcp;
+	};
 } dpaa2_sec_session;
 
 static const struct rte_cryptodev_capabilities dpaa2_sec_capabilities[] = {
@@ -392,6 +410,162 @@ static const struct rte_cryptodev_capabilities dpaa2_sec_capabilities[] = {
 	RTE_CRYPTODEV_END_OF_CAPABILITIES_LIST()
 };
 
+static const struct rte_cryptodev_capabilities dpaa2_pdcp_capabilities[] = {
+	{	/* SNOW 3G (UIA2) */
+		.op = RTE_CRYPTO_OP_TYPE_SYMMETRIC,
+		{.sym = {
+			.xform_type = RTE_CRYPTO_SYM_XFORM_AUTH,
+			{.auth = {
+				.algo = RTE_CRYPTO_AUTH_SNOW3G_UIA2,
+				.block_size = 16,
+				.key_size = {
+					.min = 16,
+					.max = 16,
+					.increment = 0
+				},
+				.digest_size = {
+					.min = 4,
+					.max = 4,
+					.increment = 0
+				},
+				.iv_size = {
+					.min = 16,
+					.max = 16,
+					.increment = 0
+				}
+			}, }
+		}, }
+	},
+	{	/* SNOW 3G (UEA2) */
+		.op = RTE_CRYPTO_OP_TYPE_SYMMETRIC,
+		{.sym = {
+			.xform_type = RTE_CRYPTO_SYM_XFORM_CIPHER,
+			{.cipher = {
+				.algo = RTE_CRYPTO_CIPHER_SNOW3G_UEA2,
+				.block_size = 16,
+				.key_size = {
+					.min = 16,
+					.max = 16,
+					.increment = 0
+				},
+				.iv_size = {
+					.min = 16,
+					.max = 16,
+					.increment = 0
+				}
+			}, }
+		}, }
+	},
+	{	/* AES CTR */
+		.op = RTE_CRYPTO_OP_TYPE_SYMMETRIC,
+		{.sym = {
+			.xform_type = RTE_CRYPTO_SYM_XFORM_CIPHER,
+			{.cipher = {
+				.algo = RTE_CRYPTO_CIPHER_AES_CTR,
+				.block_size = 16,
+				.key_size = {
+					.min = 16,
+					.max = 32,
+					.increment = 8
+				},
+				.iv_size = {
+					.min = 16,
+					.max = 16,
+					.increment = 0
+				}
+			}, }
+		}, }
+	},
+	{	/* NULL (AUTH) */
+		.op = RTE_CRYPTO_OP_TYPE_SYMMETRIC,
+		{.sym = {
+			.xform_type = RTE_CRYPTO_SYM_XFORM_AUTH,
+			{.auth = {
+				.algo = RTE_CRYPTO_AUTH_NULL,
+				.block_size = 1,
+				.key_size = {
+					.min = 0,
+					.max = 0,
+					.increment = 0
+				},
+				.digest_size = {
+					.min = 0,
+					.max = 0,
+					.increment = 0
+				},
+				.iv_size = { 0 }
+			}, },
+		}, },
+	},
+	{	/* NULL (CIPHER) */
+		.op = RTE_CRYPTO_OP_TYPE_SYMMETRIC,
+		{.sym = {
+			.xform_type = RTE_CRYPTO_SYM_XFORM_CIPHER,
+			{.cipher = {
+				.algo = RTE_CRYPTO_CIPHER_NULL,
+				.block_size = 1,
+				.key_size = {
+					.min = 0,
+					.max = 0,
+					.increment = 0
+				},
+				.iv_size = {
+					.min = 0,
+					.max = 0,
+					.increment = 0
+				}
+			}, },
+		}, }
+	},
+	{	/* ZUC (EEA3) */
+		.op = RTE_CRYPTO_OP_TYPE_SYMMETRIC,
+		{.sym = {
+			.xform_type = RTE_CRYPTO_SYM_XFORM_CIPHER,
+			{.cipher = {
+				.algo = RTE_CRYPTO_CIPHER_ZUC_EEA3,
+				.block_size = 16,
+				.key_size = {
+					.min = 16,
+					.max = 16,
+					.increment = 0
+				},
+				.iv_size = {
+					.min = 16,
+					.max = 16,
+					.increment = 0
+				}
+			}, }
+		}, }
+	},
+	{	/* ZUC (EIA3) */
+		.op = RTE_CRYPTO_OP_TYPE_SYMMETRIC,
+		{.sym = {
+			.xform_type = RTE_CRYPTO_SYM_XFORM_AUTH,
+			{.auth = {
+				.algo = RTE_CRYPTO_AUTH_ZUC_EIA3,
+				.block_size = 16,
+				.key_size = {
+					.min = 16,
+					.max = 16,
+					.increment = 0
+				},
+				.digest_size = {
+					.min = 4,
+					.max = 4,
+					.increment = 0
+				},
+				.iv_size = {
+					.min = 16,
+					.max = 16,
+					.increment = 0
+				}
+			}, }
+		}, }
+	},
+
+	RTE_CRYPTODEV_END_OF_CAPABILITIES_LIST()
+};
+
 static const struct rte_security_capability dpaa2_sec_security_cap[] = {
 	{ /* IPsec Lookaside Protocol offload ESP Transport Egress */
 		.action = RTE_SECURITY_ACTION_TYPE_LOOKASIDE_PROTOCOL,
@@ -415,6 +589,24 @@ static const struct rte_security_capability dpaa2_sec_security_cap[] = {
 		},
 		.crypto_capabilities = dpaa2_sec_capabilities
 	},
+	{ /* PDCP Lookaside Protocol offload Data */
+		.action = RTE_SECURITY_ACTION_TYPE_LOOKASIDE_PROTOCOL,
+		.protocol = RTE_SECURITY_PROTOCOL_PDCP,
+		.pdcp = {
+			.domain = RTE_SECURITY_PDCP_MODE_DATA,
+			.capa_flags = 0
+		},
+		.crypto_capabilities = dpaa2_pdcp_capabilities
+	},
+	{ /* PDCP Lookaside Protocol offload Control */
+		.action = RTE_SECURITY_ACTION_TYPE_LOOKASIDE_PROTOCOL,
+		.protocol = RTE_SECURITY_PROTOCOL_PDCP,
+		.pdcp = {
+			.domain = RTE_SECURITY_PDCP_MODE_CONTROL,
+			.capa_flags = 0
+		},
+		.crypto_capabilities = dpaa2_pdcp_capabilities
+	},
 	{
 		.action = RTE_SECURITY_ACTION_TYPE_NONE
 	}
-- 
2.7.4

^ permalink raw reply	[flat|nested] 41+ messages in thread

end of thread, other threads:[~2018-10-22  7:14 UTC | newest]

Thread overview: 41+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2018-08-28 13:01 [dpdk-dev] [PATCH 0/3] security: support for pdcp akhil.goyal
2018-08-28 13:01 ` [dpdk-dev] [PATCH 1/3] security: support pdcp protocol akhil.goyal
2018-09-06  4:15   ` Joseph, Anoob
2018-10-05 12:05     ` Akhil Goyal
2018-10-07  9:02       ` Joseph, Anoob
2018-10-08  9:49         ` Akhil Goyal
2018-10-09 11:38           ` Joseph, Anoob
2018-10-15 13:03             ` Akhil Goyal
2018-10-16  6:27               ` Joseph
2018-08-28 13:01 ` [dpdk-dev] [PATCH 2/3] crypto/dpaa2_sec: add sample pdcp descriptor apis akhil.goyal
2018-08-28 13:01 ` [dpdk-dev] [PATCH 3/3] crypto/dpaa2_sec: support pdcp offload akhil.goyal
2018-08-30  6:46 ` [dpdk-dev] [PATCH 0/3] security: support for pdcp Akhil Goyal
2018-10-05 13:33 ` [dpdk-dev] [PATCH v2 " akhil.goyal
2018-10-05 13:33   ` [dpdk-dev] [PATCH v2 1/3] security: support pdcp protocol akhil.goyal
2018-10-05 13:33   ` [dpdk-dev] [PATCH v2 2/3] crypto/dpaa2_sec: add sample pdcp descriptor apis akhil.goyal
2018-10-05 13:33   ` [dpdk-dev] [PATCH v2 3/3] crypto/dpaa2_sec: support pdcp offload akhil.goyal
2018-10-05 13:53   ` [dpdk-dev] [PATCH v3 0/3] security: support for pdcp akhil.goyal
2018-10-05 13:53     ` [dpdk-dev] [PATCH v3 1/3] security: support pdcp protocol akhil.goyal
2018-10-05 13:53     ` [dpdk-dev] [PATCH v3 2/3] crypto/dpaa2_sec: add sample pdcp descriptor apis akhil.goyal
2018-10-05 13:53     ` [dpdk-dev] [PATCH v3 3/3] crypto/dpaa2_sec: support pdcp offload akhil.goyal
2018-10-15 12:53     ` [dpdk-dev] [PATCH v4 0/3] security: support for pdcp Akhil Goyal
2018-10-15 12:53       ` [dpdk-dev] [PATCH v4 1/3] security: support pdcp protocol Akhil Goyal
2018-10-16  6:40         ` Joseph
2018-10-16  6:55           ` Akhil Goyal
2018-10-15 12:53       ` [dpdk-dev] [PATCH v4 2/3] crypto/dpaa2_sec: add sample pdcp descriptor apis Akhil Goyal
2018-10-15 12:53       ` [dpdk-dev] [PATCH v4 3/3] crypto/dpaa2_sec: support pdcp offload Akhil Goyal
2018-10-16 10:38       ` [dpdk-dev] [PATCH v5 0/3] security: support for pdcp Akhil Goyal
2018-10-16 10:39         ` [dpdk-dev] [PATCH v5 1/3] security: support pdcp protocol Akhil Goyal
2018-10-16 10:49           ` Joseph, Anoob
2018-10-16 10:57             ` Akhil Goyal
2018-10-16 11:15               ` Joseph, Anoob
2018-10-16 12:25                 ` Akhil Goyal
2018-10-16 10:39         ` [dpdk-dev] [PATCH v5 2/3] crypto/dpaa2_sec: add sample pdcp descriptor apis Akhil Goyal
2018-10-16 10:39         ` [dpdk-dev] [PATCH v5 3/3] crypto/dpaa2_sec: support pdcp offload Akhil Goyal
2018-10-16 14:35         ` [dpdk-dev] [PATCH v5 0/3] security: support for pdcp Akhil Goyal
2018-10-18 14:40           ` Thomas Monjalon
2018-10-22  7:10             ` Hemant Agrawal
2018-10-22  7:12         ` [dpdk-dev] [PATCH v6 " Hemant Agrawal
2018-10-22  7:12           ` [dpdk-dev] [PATCH v6 1/3] security: support pdcp protocol Hemant Agrawal
2018-10-22  7:12           ` [dpdk-dev] [PATCH v6 2/3] crypto/dpaa2_sec: add sample pdcp descriptor apis Hemant Agrawal
2018-10-22  7:12           ` [dpdk-dev] [PATCH v6 3/3] crypto/dpaa2_sec: support pdcp offload Hemant Agrawal

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).