From mboxrd@z Thu Jan  1 00:00:00 1970
Return-Path: <akhil.goyal@nxp.com>
Received: from EUR04-HE1-obe.outbound.protection.outlook.com
 (mail-eopbgr70042.outbound.protection.outlook.com [40.107.7.42])
 by dpdk.org (Postfix) with ESMTP id 9FF714C95
 for <dev@dpdk.org>; Tue, 16 Oct 2018 12:39:09 +0200 (CEST)
DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=nxp.com; s=selector1; 
 h=From:Date:Subject:Message-ID:Content-Type:MIME-Version:X-MS-Exchange-SenderADCheck;
 bh=i50FwPDwJ5/b5LmCTgM7AbCXoMQbgrCwSXAazrL1UwE=;
 b=ITsyMimXA+885oC0azimxAyyhwgnmY5KyHjRGqRbdM4uD1LPpT+xTiDBlnuWfkl5KjJ1QNIwVfco7yjLSDVqNUu0aV9KS+KKklWG6lOf21R9f5tIULFbLtCBd7tW3ge//dw/wO7zXDOuAY3YtLGtr0QLaprVSP9Fq/6iArN/iZ0=
Received: from VI1PR04MB4893.eurprd04.prod.outlook.com (20.177.49.154) by
 VI1PR04MB3231.eurprd04.prod.outlook.com (10.170.227.28) with Microsoft SMTP
 Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id
 15.20.1228.31; Tue, 16 Oct 2018 10:39:06 +0000
Received: from VI1PR04MB4893.eurprd04.prod.outlook.com
 ([fe80::cc19:b6c6:27db:3fec]) by VI1PR04MB4893.eurprd04.prod.outlook.com
 ([fe80::cc19:b6c6:27db:3fec%3]) with mapi id 15.20.1228.027; Tue, 16 Oct 2018
 10:39:06 +0000
From: Akhil Goyal <akhil.goyal@nxp.com>
To: "dev@dpdk.org" <dev@dpdk.org>
CC: "pablo.de.lara.guarch@intel.com" <pablo.de.lara.guarch@intel.com>,
 "radu.nicolau@intel.com" <radu.nicolau@intel.com>,
 "jerin.jacob@caviumnetworks.com" <jerin.jacob@caviumnetworks.com>,
 "narayanaprasad.athreya@caviumnetworks.com"
 <narayanaprasad.athreya@caviumnetworks.com>,
 "Shally.Verma@caviumnetworks.com" <Shally.Verma@caviumnetworks.com>,
 "Anoob.Joseph@caviumnetworks.com" <Anoob.Joseph@caviumnetworks.com>,
 "Vidya.Velumuri@caviumnetworks.com" <Vidya.Velumuri@caviumnetworks.com>,
 Hemant Agrawal <hemant.agrawal@nxp.com>, Akhil Goyal <akhil.goyal@nxp.com>
Thread-Topic: [PATCH v5 2/3] crypto/dpaa2_sec: add sample pdcp descriptor apis
Thread-Index: AQHUZTx2yj14mPLKQEu6w1yKagyQ5w==
Date: Tue, 16 Oct 2018 10:39:06 +0000
Message-ID: <20181016103352.2678-3-akhil.goyal@nxp.com>
References: <20181015124858.5562-1-akhil.goyal@nxp.com>
 <20181016103352.2678-1-akhil.goyal@nxp.com>
In-Reply-To: <20181016103352.2678-1-akhil.goyal@nxp.com>
Accept-Language: en-IN, en-US
Content-Language: en-US
X-MS-Has-Attach: 
X-MS-TNEF-Correlator: 
x-clientproxiedby: TYAPR01CA0026.jpnprd01.prod.outlook.com
 (2603:1096:404:28::14) To VI1PR04MB4893.eurprd04.prod.outlook.com
 (2603:10a6:803:56::26)
authentication-results: spf=none (sender IP is )
 smtp.mailfrom=akhil.goyal@nxp.com; 
x-ms-exchange-messagesentrepresentingtype: 1
x-originating-ip: [14.143.30.134]
x-ms-publictraffictype: Email
x-microsoft-exchange-diagnostics: 1; VI1PR04MB3231;
 6:115FNyNBHeCaQn/3sT4lMmzeyyijdaIb2VS3x31/phY85f/2RfgAqCOJEy3JWNx+bI+EkfyTuyNMM+/RJtf8x80RlEs6gnIGuvD675WoQM5bd1S/QlrrICoQRDvBpQvoHYBnCdCMC/IESjEZG11b0RpiRfWw0UryHNYZOMHUSLkLM4N5F+qII3emnTlNbC2WPeqitzLorlfTnKu6KoMafd25hmUMZKQ8ue/gIKI2IRi2IKxJQErMa/WTy/nxfVVkutcIOWA7qZl0dlvkxa3nWrXUiq7gDxdbkg2QMUMvs4Vu0tElBFI0AxCr++FEzXRejSe9o6TkusDtf00oazsCKxcZ/Aok0Y5Gk+LMSCiFr5c1HZgTWVgAgjX6QfxVLwuaZzJCo6Osp0wMjjepwRmuZdlzxTKbDyi6kuX23pOJUODPjsFP4jI++6svFfLTsNm0ZG6efLWeegu6rZSGw6wqqg==;
 5:QVCqWlhlIXF5LNB/Bk79kKTha4puksYKTDXbpRIO+AvgQfxf0yHfYfmBYqQ+M40tBSbqeAFJpJOgpK8cAWuzW5LKMnBivmljsnbDSSB2a9pTUUxwry0eaQWRaIePpQ0g1yLl3I63mIHw+PJ7eN/+uQBb8+ADFUCc+7Dt4BarwEY=;
 7:8F8IXHJtL/zMhx1+3wRlTuUdf9mAJI9AhEcY7Q4Hm6myijM7lT6eghaER4ZILI71mboAabwCipBijRnMnaysjXzBPibQsxhxrHFYr3XrqHEo/6NquK8HV5PuY5kPvmx5/GvH/1psI5YeXH/7vcb0JMLOOjCwfHTDT+XB9pKgO79zZYZFjtetJmHv+iScoVU0lxEjCzKjp9CErMKqBOyvp8IKynaCS4UCSEsV7m6fqDEVIDYC8frgn2yrt+bGSuCK
x-ms-office365-filtering-correlation-id: b0ae15a6-80c0-4ca6-f665-08d63353985e
x-ms-office365-filtering-ht: Tenant
x-microsoft-antispam: BCL:0; PCL:0;
 RULEID:(7020095)(4652040)(8989299)(5600074)(711020)(4618075)(4534185)(7168020)(4627221)(201703031133081)(201702281549075)(8990200)(2017052603328)(7153060)(7193020);
 SRVR:VI1PR04MB3231; 
x-ms-traffictypediagnostic: VI1PR04MB3231:
x-microsoft-antispam-prvs: <VI1PR04MB32314FD3316EFFC18FCCEE32E6FE0@VI1PR04MB3231.eurprd04.prod.outlook.com>
x-exchange-antispam-report-test: UriScan:(269456686620040)(185117386973197);
x-ms-exchange-senderadcheck: 1
x-exchange-antispam-report-cfa-test: BCL:0; PCL:0;
 RULEID:(8211001083)(6040522)(2401047)(8121501046)(5005006)(3231355)(944501410)(52105095)(3002001)(10201501046)(93006095)(93001095)(6055026)(149066)(150057)(6041310)(20161123560045)(20161123558120)(20161123562045)(20161123564045)(201703131423095)(201702281528075)(20161123555045)(201703061421075)(201703061406153)(201708071742011)(7699051);
 SRVR:VI1PR04MB3231; BCL:0; PCL:0; RULEID:; SRVR:VI1PR04MB3231; 
x-forefront-prvs: 0827D7ACB9
x-forefront-antispam-report: SFV:NSPM;
 SFS:(10009020)(136003)(39860400002)(396003)(346002)(366004)(376002)(189003)(199004)(1076002)(53936002)(6512007)(14444005)(256004)(575784001)(6916009)(3846002)(86362001)(44832011)(97736004)(5640700003)(476003)(68736007)(6436002)(4744004)(16200700003)(55236004)(66066001)(6116002)(76176011)(2900100001)(36756003)(6506007)(6486002)(53946003)(386003)(71200400001)(71190400001)(105586002)(2351001)(5250100002)(106356001)(99286004)(102836004)(8936002)(1730700003)(8676002)(2906002)(305945005)(478600001)(25786009)(81166006)(446003)(4326008)(81156014)(7736002)(316002)(54906003)(14454004)(2501003)(2616005)(486006)(186003)(11346002)(52116002)(26005)(5660300001)(569006);
 DIR:OUT; SFP:1101; SCL:1; SRVR:VI1PR04MB3231;
 H:VI1PR04MB4893.eurprd04.prod.outlook.com; FPR:; SPF:None; LANG:en;
 PTR:InfoNoRecords; MX:1; A:1; 
received-spf: None (protection.outlook.com: nxp.com does not designate
 permitted sender hosts)
x-microsoft-antispam-message-info: 986AxU1/HA1FtC2XjlVm9BQ5qybcuOnGvRVoc7F+HjAgm0KpOyq0FpUIHN3peR0pfOQ6uB63BpB7ddUdjq3Sid+SC4EZuFCfgV07ekKAibV5G2qotzAMdH3mi5w1krZLpEpbteL26X/l9guCZsAIfCxZOokisfe2NQ1AFSn0KDjzGJ5q7k9wBslkCmar+u9EZ+yZHHJWc3d6980I9s5JKpYak2qAC3huKPe3J2X3XQ9ka1izkAwVz3HeS7rZtHNZXhhU5z6gjvn4fcygdI0Ua8OOsZ8q1POLxXToVJb+9jkxW85SbB/qVv5zMt7M+PxjfoMLrLTwq0B4gdyWqKSHNoFpYW3dUWqQjFng2cFDEYo=
spamdiagnosticoutput: 1:99
spamdiagnosticmetadata: NSPM
Content-Type: text/plain; charset="iso-8859-1"
Content-Transfer-Encoding: quoted-printable
MIME-Version: 1.0
X-OriginatorOrg: nxp.com
X-MS-Exchange-CrossTenant-Network-Message-Id: b0ae15a6-80c0-4ca6-f665-08d63353985e
X-MS-Exchange-CrossTenant-originalarrivaltime: 16 Oct 2018 10:39:06.6647 (UTC)
X-MS-Exchange-CrossTenant-fromentityheader: Hosted
X-MS-Exchange-CrossTenant-id: 686ea1d3-bc2b-4c6f-a92c-d99c5c301635
X-MS-Exchange-Transport-CrossTenantHeadersStamped: VI1PR04MB3231
Subject: [dpdk-dev] [PATCH v5 2/3] crypto/dpaa2_sec: add sample pdcp
	descriptor apis
X-BeenThere: dev@dpdk.org
X-Mailman-Version: 2.1.15
Precedence: list
List-Id: DPDK patches and discussions <dev.dpdk.org>
List-Unsubscribe: <https://mails.dpdk.org/options/dev>,
 <mailto:dev-request@dpdk.org?subject=unsubscribe>
List-Archive: <http://mails.dpdk.org/archives/dev/>
List-Post: <mailto:dev@dpdk.org>
List-Help: <mailto:dev-request@dpdk.org?subject=help>
List-Subscribe: <https://mails.dpdk.org/listinfo/dev>,
 <mailto:dev-request@dpdk.org?subject=subscribe>
X-List-Received-Date: Tue, 16 Oct 2018 10:39:10 -0000

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 suppor=
ted 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 fi=
eld 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 PDC=
P
+ *                        Control Plane header. For PDCP Control Plane, th=
e SN
+ *                        is constant (5 bits) as opposed to PDCP Data Pla=
ne
+ *                        (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 t=
he
+ *                              PDCP User Plane header. For PDCP Control P=
lane,
+ *                              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 nee=
ded
+ * for SNOW f9.
+ *
+ * The lower 32 bits of the mask are used for masking the direction for AE=
S
+ * 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 nee=
ded
+ * for SNOW f9.
+ *
+ * The upper 32 bits of the mask are used for masking the direction for AE=
S
+ * 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 c=
heck
+ *                                         failed in case of NULL integrit=
y
+ *                                         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 f=
or 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-->|
+ * //=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D||=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D|=
|=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D\\
+ * || PDCP_DPOVRD_HFN_OV_EN | HFN value || PDCP Header|| PDCP Payload ||
+ * \\=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D||=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D|=
|=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D//
+ *
+ * If HFN override mechanism is not desired, then the MSB of the first 4 b=
ytes
+ * must be set to 0b.
+ */
+#define PDCP_P4080REV2_HFN_OV_BUFLEN	4
+
+/**
+ * enum cipher_type_pdcp - Type selectors for cipher types in PDCP protoco=
l 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 protoc=
ol 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 =3D 0,
+	PDCP_DIR_DOWNLINK =3D 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 =3D 5,
+	PDCP_SN_SIZE_7 =3D 7,
+	PDCP_SN_SIZE_12 =3D 12,
+	PDCP_SN_SIZE_15 =3D 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 descr=
iptor
+ * which performs NULL encryption and integrity (i.e. copies the input fra=
me
+ * 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 =3D=3D 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 =3D=3D 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 =3D MOVE(p, DESCBUF, 0, MATH0, 0, 6,
+					     IMMED);
+		move_cmd_write_descbuf =3D 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 =3D=3D 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 =3D=3D 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 =3D MOVE(p, DESCBUF, 0, MATH0, 0, 6,
+					     IMMED);
+		move_cmd_write_descbuf =3D 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 =3D=3D RTA_SEC_ERA_2 &&
+				   era_2_sw_hfn_ovrd =3D=3D 0)) {
+			SEQINPTR(p, 0, 1, RTO);
+		} else {
+			SEQINPTR(p, 0, 5, RTO);
+			SEQFIFOLOAD(p, SKIP, 4, 0);
+		}
+
+		if (swap =3D=3D 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 =3D=3D 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 =3D MOVE(p, DESCBUF, 0, MATH1, 0, 6,
+						     IMMED);
+			move_cmd_write_descbuf =3D 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 =3D=3D 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 =3D=3D 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 =3D=3D RTA_SEC_ERA_2 &&
+		     era_2_sw_hfn_ovrd =3D=3D 0)) {
+			SEQINPTR(p, 0, 1, RTO);
+		} else {
+			SEQINPTR(p, 0, 5, RTO);
+			SEQFIFOLOAD(p, SKIP, 4, 0);
+		}
+
+		if (swap =3D=3D 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 =3D=3D 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 =3D MOVE(p, DESCBUF, 0, MATH1, 0, 6,
+						     IMMED);
+			move_cmd_write_descbuf =3D 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 =3D=3D 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 =3D=3D 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 =3D=3D 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 =3D=3D 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 =3D=3D 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 =3D=3D 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 >=3D 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 =3D=3D 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 =3D=3D 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 =3D=3D 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 =3D=3D 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 =3D=3D 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 =3D=3D 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 =3D=3D 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 =3D=3D 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 >=3D 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 =3D=3D 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 =3D=3D OP_TYPE_ENCAP_PROTOCOL) {
+		if (rta_sec_era > RTA_SEC_ERA_2 ||
+		    (rta_sec_era =3D=3D RTA_SEC_ERA_2 &&
+				   era_2_sw_hfn_ovrd =3D=3D 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 =3D 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 =3D MOVE(p, DESCBUF, 0, MATH1, 0, 6, IMMED);
+		seqin_ptr_write =3D 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 <=3D 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 <=3D 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 =3D=3D 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 =3D=3D RTA_SEC_ERA_2 &&
+				   era_2_sw_hfn_ovrd =3D=3D 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 >=3D 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 =3D 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 comman=
d
+ * Thus, it is inserted as a raw word, as per PS setting.
+ */
+		if (p->ps)
+			seq_out_read =3D MOVE(p, DESCBUF, 0, MATH1, 0, 20,
+					    WAITCOMP | IMMED);
+		else
+			seq_out_read =3D 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 comman=
d
+ * 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 >=3D 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 <=3D RTA_SEC_ERA_3)
+			move_mac_i_to_desc_buf =3D MOVE(p, OFIFO, 0, DESCBUF, 0,
+						      4, WAITCOMP | IMMED);
+		else
+			MOVE(p, OFIFO, 0, MATH3, 0, 4, IMMED);
+
+		if (rta_sec_era <=3D 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 <=3D 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 =3D=3D 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 >=3D 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 <=3D 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 <=3D 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 >=3D 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 =3D=3D 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 =3D=3D 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 =3D=3D 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 =3D=3D 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 =3D=3D 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 =3D=3D 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 =3D=3D OP_TYPE_ENCAP_PROTOCOL ? DIR_ENC : DIR_DEC);
+
+	if (dir =3D=3D 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 >=3D 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 <=3D 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 =3D 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 >=3D 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 =3D=3D 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 =3D=3D 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 =3D=3D 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 =3D=3D 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 =3D=3D OP_TYPE_ENCAP_PROTOCOL ? DIR_ENC : DIR_DEC);
+	if (dir =3D=3D 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 =3D 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 >=3D 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 =3D=3D 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 =3D=3D 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 =3D=3D 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 =3D=3D 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 =3D=3D OP_TYPE_ENCAP_PROTOCOL ? DIR_ENC : DIR_DEC);
+
+	if (dir =3D=3D 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 =3D 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 >=3D 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 =3D=3D 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 =3D=3D 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 =3D=3D 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 =3D=3D 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 =3D=3D 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 =3D=3D OP_TYPE_ENCAP_PROTOCOL ? DIR_ENC : DIR_DEC);
+
+	if (dir =3D=3D 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 >=3D 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 >=3D 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 =3D=3D 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 =3D=3D 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 >=3D 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 =3D=3D 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 =3D dir =3D=3D 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 =3D PDCP_DPOVRD_HFN_OV_EN;
+	uint16_t hfn_pdb_offset;
+
+	if (rta_sec_era =3D=3D 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 =3D 4;
+		break;
+
+	case PDCP_PDB_TYPE_FULL_PDB:
+		hfn_pdb_offset =3D 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 >=3D 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 >=3D 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] =3D {
+			{	/* 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 >=3D 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 =3D 0x00000002;
+
+		/* Copy relevant information from user to PDB */
+		pdb.hfn_res =3D hfn << PDCP_C_PLANE_PDB_HFN_SHIFT;
+		pdb.bearer_dir_res =3D (uint32_t)
+				((bearer << PDCP_C_PLANE_PDB_BEARER_SHIFT) |
+				 (direction << PDCP_C_PLANE_PDB_DIR_SHIFT));
+		pdb.hfn_thr_res =3D
+				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 =3D 0x00000002;
+
+		/* Copy relevant information from user to PDB */
+		pdb.hfn_res =3D hfn << PDCP_C_PLANE_PDB_HFN_SHIFT;
+		pdb.bearer_dir_res =3D (uint32_t)
+			((bearer << PDCP_C_PLANE_PDB_BEARER_SHIFT) |
+			 (direction << PDCP_C_PLANE_PDB_DIR_SHIFT));
+		pdb.hfn_thr_res =3D
+			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 |=3D PDCP_U_PLANE_PDB_OPT_SHORT_SN;
+		pdb.hfn_res =3D hfn << PDCP_U_PLANE_PDB_SHORT_SN_HFN_SHIFT;
+		pdb.hfn_thr_res =3D
+			hfn_threshold<<PDCP_U_PLANE_PDB_SHORT_SN_HFN_THR_SHIFT;
+		break;
+
+	case PDCP_SN_SIZE_12:
+		pdb.opt_res.opt &=3D (uint32_t)(~PDCP_U_PLANE_PDB_OPT_SHORT_SN);
+		pdb.hfn_res =3D hfn << PDCP_U_PLANE_PDB_LONG_SN_HFN_SHIFT;
+		pdb.hfn_thr_res =3D
+			hfn_threshold<<PDCP_U_PLANE_PDB_LONG_SN_HFN_THR_SHIFT;
+		break;
+
+	case PDCP_SN_SIZE_15:
+		pdb.opt_res.opt =3D (uint32_t)(PDCP_U_PLANE_PDB_OPT_15B_SN);
+		pdb.hfn_res =3D hfn << PDCP_U_PLANE_PDB_15BIT_SN_HFN_SHIFT;
+		pdb.hfn_thr_res =3D
+			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 =3D (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 P=
lane
+ *                                  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 enu=
m.
+ * @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 u=
sed
+ *         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 numbe=
r of
+ * bytes used, the user can reuse the remaining buffer space for other pur=
poses.
+ */
+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) =3D {
+		{	/* 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] =3D {
+		{	/* 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 =3D &prg;
+	int err;
+	LABEL(pdb_end);
+
+	if (rta_sec_era !=3D 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 =3D cnstr_pdcp_c_plane_pdb(p,
+			hfn,
+			bearer,
+			direction,
+			hfn_threshold,
+			cipherdata,
+			authdata);
+
+	SET_LABEL(p, pdb_end);
+
+	err =3D insert_hfn_ov_op(p, PDCP_SN_SIZE_5, pdb_type,
+			       era_2_sw_hfn_ovrd);
+	if (err)
+		return err;
+
+	err =3D 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 P=
lane
+ *                                  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 enu=
m.
+ * @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 u=
sed
+ *         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 numbe=
r of
+ * bytes used, the user can reuse the remaining buffer space for other pur=
poses.
+ */
+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) =3D {
+		{	/* 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] =3D {
+		{	/* 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 =3D &prg;
+	int err;
+	LABEL(pdb_end);
+
+	if (rta_sec_era !=3D 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 =3D cnstr_pdcp_c_plane_pdb(p,
+			hfn,
+			bearer,
+			direction,
+			hfn_threshold,
+			cipherdata,
+			authdata);
+
+	SET_LABEL(p, pdb_end);
+
+	err =3D insert_hfn_ov_op(p, PDCP_SN_SIZE_5, pdb_type,
+			       era_2_sw_hfn_ovrd);
+	if (err)
+		return err;
+
+	err =3D 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 Plan=
e
+ *                                  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 enu=
m.
+ * @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 u=
sed
+ *         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 numbe=
r of
+ * bytes used, the user can reuse the remaining buffer space for other pur=
poses.
+ */
+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 =3D &prg;
+	int err;
+	LABEL(pdb_end);
+
+	if (rta_sec_era !=3D 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 =3D 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 =3D 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 Plan=
e
+ *                                  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 enu=
m.
+ * @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 u=
sed
+ *         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 numbe=
r of
+ * bytes used, the user can reuse the remaining buffer space for other pur=
poses.
+ */
+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 =3D &prg;
+	int err;
+	LABEL(pdb_end);
+
+	if (rta_sec_era !=3D 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 =3D 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 =3D 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 u=
sed
+ *         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 numbe=
r of
+ * bytes used, the user can reuse the remaining buffer space for other pur=
poses.
+ */
+static inline int
+cnstr_shdsc_pdcp_short_mac(uint32_t *descbuf,
+			   bool ps,
+			   bool swap,
+			   struct alginfo *authdata)
+{
+	struct program prg;
+	struct program *p =3D &prg;
+	uint32_t iv[3] =3D {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 =3D MOVE(p, DESCBUF, 0, MATH0, 0, 6,
+					     IMMED);
+		move_cmd_write_descbuf =3D 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] =3D 0xFFFFFFFF;
+		iv[1] =3D swap ? swab32(0x04000000) : 0x04000000;
+		iv[2] =3D 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] =3D 0xFFFFFFFF;
+		iv[1] =3D swap ? swab32(0xFC000000) : 0xFC000000;
+		iv[2] =3D 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] =3D 0xFFFFFFFF;
+		iv[1] =3D swap ? swab32(0xFC000000) : 0xFC000000;
+		iv[2] =3D 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__ */
--=20
2.17.1