From patchwork Mon Oct 22 07:12:08 2018 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Hemant Agrawal X-Patchwork-Id: 149371 Delivered-To: patch@linaro.org Received: by 2002:a2e:8595:0:0:0:0:0 with SMTP id b21-v6csp2295778lji; Mon, 22 Oct 2018 00:14:44 -0700 (PDT) X-Google-Smtp-Source: ACcGV60n5esQZ+2GYkdUdjif2unXxoCMWim5ncZDAZ4bHeBrpZWYZy0vIk7MsLGU2A6GS24aPXsr X-Received: by 2002:a05:6000:1008:: with SMTP id a8mr44529575wrx.271.1540192484680; Mon, 22 Oct 2018 00:14:44 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1540192484; cv=none; d=google.com; s=arc-20160816; b=hoROSOyqOZ0dTBKGPC5fNqiButReKZPOl/d5IupD+nvjGSK+uwZE/QAftbPwJXFeHC 2xqCC8VpXysA+b37EppeQ/p0Bb0Z3aF2WiQAUrr87UdRz5yOVOKh0SY9sk7A0n/hdtww 2nmBzwaQ4cwMkZullxttwx8tMnXKs8Y1sKk0Q6X8/z4OX4iqiNO0Bb5Qgnhoz6kknIV9 ZgAL5yxYlkBs4uPWi/oQvMzy9xC8VHlsj0KUUsvxcPV5Vllm2wA7HgEygYWhf4jU7yqN kp9+ltp16xtEAlxKLEPbsgLw8UUUQWvMpts5ysD5qlSkuxT64MJbuushwoBgvXMTfAg6 jrHA== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=sender:errors-to:list-subscribe:list-help:list-post:list-archive :list-unsubscribe:list-id:precedence:subject:references:in-reply-to :message-id:date:cc:to:from; bh=bfqlUrAcmcePbT22irUabrUkF6fxp9k3Qti4/a7/KbU=; b=L5O7nWHA3cmyZYl4Or/0IKmDtipjazA81ZWorkRJG9XwMbBmT2gYCaTv5QXZWeSC11 LHleN70tPCdvUFALAxA4RF1YTI03nyy64CkhxLsZzG3f+8ep/4VWnchWAcQ6z0FrJsZB i2b9As/z2hsDb6LqxeqtQTPZZ1P7TDKD1xau2ZsYc8ec+f0HpKSVgjTcPI2Mn35M9wdk CdsACEwDZlfVmG6khNeabVdfZxEE/lLeCbyTsnid0HN2YYaHrJhz5WoVYnkRfCW32tOX 44lC6j32ypTmfJqS/xvidhfkBKQSZWx9CQCOaoR/MnV+fJ+PnNXsE7xuTeIG5x+1Zg6h YOCA== ARC-Authentication-Results: i=1; mx.google.com; spf=pass (google.com: domain of dev-bounces@dpdk.org designates 92.243.14.124 as permitted sender) smtp.mailfrom=dev-bounces@dpdk.org; dmarc=fail (p=NONE sp=NONE dis=NONE) header.from=nxp.com Return-Path: Received: from dpdk.org (dpdk.org. [92.243.14.124]) by mx.google.com with ESMTP id d14-v6si766841wro.232.2018.10.22.00.14.44; Mon, 22 Oct 2018 00:14:44 -0700 (PDT) Received-SPF: pass (google.com: domain of dev-bounces@dpdk.org designates 92.243.14.124 as permitted sender) client-ip=92.243.14.124; Authentication-Results: mx.google.com; spf=pass (google.com: domain of dev-bounces@dpdk.org designates 92.243.14.124 as permitted sender) smtp.mailfrom=dev-bounces@dpdk.org; dmarc=fail (p=NONE sp=NONE dis=NONE) header.from=nxp.com Received: from [92.243.14.124] (localhost [127.0.0.1]) by dpdk.org (Postfix) with ESMTP id 4612D4F90; Mon, 22 Oct 2018 09:14:44 +0200 (CEST) Received: from inva021.nxp.com (inva021.nxp.com [92.121.34.21]) by dpdk.org (Postfix) with ESMTP id E30EB4D3A for ; Mon, 22 Oct 2018 09:14:36 +0200 (CEST) Received: from inva021.nxp.com (localhost [127.0.0.1]) by inva021.eu-rdc02.nxp.com (Postfix) with ESMTP id 8CB9A2001B8; Mon, 22 Oct 2018 09:14:36 +0200 (CEST) Received: from invc005.ap-rdc01.nxp.com (invc005.ap-rdc01.nxp.com [165.114.16.14]) by inva021.eu-rdc02.nxp.com (Postfix) with ESMTP id A0C942001BE; Mon, 22 Oct 2018 09:14:31 +0200 (CEST) Received: from bf-netperf1.ap.freescale.net (bf-netperf1.ap.freescale.net [10.232.134.28]) by invc005.ap-rdc01.nxp.com (Postfix) with ESMTP id 6D0A0402AB; Mon, 22 Oct 2018 15:14:25 +0800 (SGT) From: Hemant Agrawal To: dev@dpdk.org Cc: thomas@monjalon.net, pablo.de.lara.guarch@intel.com, radu.nicolau@intel.com, jerin.jacob@caviumnetworks.com, narayanaprasad.athreya@caviumnetworks.com, Shally.Verma@caviumnetworks.com, Anoob.Joseph@caviumnetworks.com, Vidya.Velumuri@caviumnetworks.com, akhil.goyal@nxp.com Date: Mon, 22 Oct 2018 12:42:08 +0530 Message-Id: <1540192330-4105-2-git-send-email-hemant.agrawal@nxp.com> X-Mailer: git-send-email 2.7.4 In-Reply-To: <1540192330-4105-1-git-send-email-hemant.agrawal@nxp.com> References: <20181016103352.2678-1-akhil.goyal@nxp.com> <1540192330-4105-1-git-send-email-hemant.agrawal@nxp.com> X-Virus-Scanned: ClamAV using ClamSMTP Subject: [dpdk-dev] [PATCH v6 1/3] security: support pdcp protocol X-BeenThere: dev@dpdk.org X-Mailman-Version: 2.1.15 Precedence: list List-Id: DPDK patches and discussions List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: dev-bounces@dpdk.org Sender: "dev" From: Akhil Goyal Packet Data Convergence Protocol (PDCP) is added in rte_security for 3GPP TS 36.323 for LTE. The patchset provide the structure definitions for configuring the PDCP sessions and relevant documentation is added. Signed-off-by: Hemant Agrawal Signed-off-by: Akhil Goyal Acked-by: Anoob Joseph --- doc/guides/prog_guide/rte_security.rst | 107 ++++++++++++++++++++++++++++++--- lib/librte_security/rte_security.c | 4 ++ lib/librte_security/rte_security.h | 90 +++++++++++++++++++++++++++ 3 files changed, 194 insertions(+), 7 deletions(-) -- 2.7.4 diff --git a/doc/guides/prog_guide/rte_security.rst b/doc/guides/prog_guide/rte_security.rst index 0812abe..6c7d8ee 100644 --- a/doc/guides/prog_guide/rte_security.rst +++ b/doc/guides/prog_guide/rte_security.rst @@ -10,8 +10,8 @@ The security library provides a framework for management and provisioning of security protocol operations offloaded to hardware based devices. The library defines generic APIs to create and free security sessions which can support full protocol offload as well as inline crypto operation with -NIC or crypto devices. The framework currently only supports the IPSec protocol -and associated operations, other protocols will be added in future. +NIC or crypto devices. The framework currently only supports the IPsec and PDCP +protocol and associated operations, other protocols will be added in future. Design Principles ----------------- @@ -253,6 +253,49 @@ for any protocol header addition. +--------|--------+ V +PDCP Flow Diagram +~~~~~~~~~~~~~~~~~ + +Based on 3GPP TS 36.323 Evolved Universal Terrestrial Radio Access (E-UTRA); +Packet Data Convergence Protocol (PDCP) specification + +.. code-block:: c + + Transmitting PDCP Entity Receiving PDCP Entity + | ^ + | +-----------|-----------+ + V | In order delivery and | + +---------|----------+ | Duplicate detection | + | Sequence Numbering | | (Data Plane only) | + +---------|----------+ +-----------|-----------+ + | | + +---------|----------+ +-----------|----------+ + | Header Compression*| | Header Decompression*| + | (Data-Plane only) | | (Data Plane only) | + +---------|----------+ +-----------|----------+ + | | + +---------|-----------+ +-----------|----------+ + | Integrity Protection| |Integrity Verification| + | (Control Plane only)| | (Control Plane only) | + +---------|-----------+ +-----------|----------+ + +---------|-----------+ +----------|----------+ + | Ciphering | | Deciphering | + +---------|-----------+ +----------|----------+ + +---------|-----------+ +----------|----------+ + | Add PDCP header | | Remove PDCP Header | + +---------|-----------+ +----------|----------+ + | | + +----------------->>----------------+ + + +.. note:: + + * Header Compression and decompression are not supported currently. + +Just like IPsec, in case of PDCP also header addition/deletion, cipher/ +de-cipher, integrity protection/verification is done based on the action +type chosen. + Device Features and Capabilities --------------------------------- @@ -271,7 +314,7 @@ structure in the *DPDK API Reference*. Each driver (crypto or ethernet) defines its own private array of capabilities for the operations it supports. Below is an example of the capabilities for a -PMD which supports the IPSec protocol. +PMD which supports the IPsec and PDCP protocol. .. code-block:: c @@ -298,6 +341,24 @@ PMD which supports the IPSec protocol. }, .crypto_capabilities = pmd_capabilities }, + { /* PDCP Lookaside Protocol offload Data Plane */ + .action = RTE_SECURITY_ACTION_TYPE_LOOKASIDE_PROTOCOL, + .protocol = RTE_SECURITY_PROTOCOL_PDCP, + .pdcp = { + .domain = RTE_SECURITY_PDCP_MODE_DATA, + .capa_flags = 0 + }, + .crypto_capabilities = pmd_capabilities + }, + { /* PDCP Lookaside Protocol offload Control */ + .action = RTE_SECURITY_ACTION_TYPE_LOOKASIDE_PROTOCOL, + .protocol = RTE_SECURITY_PROTOCOL_PDCP, + .pdcp = { + .domain = RTE_SECURITY_PDCP_MODE_CONTROL, + .capa_flags = 0 + }, + .crypto_capabilities = pmd_capabilities + }, { .action = RTE_SECURITY_ACTION_TYPE_NONE } @@ -429,6 +490,7 @@ Security Session configuration structure is defined as ``rte_security_session_co union { struct rte_security_ipsec_xform ipsec; struct rte_security_macsec_xform macsec; + struct rte_security_pdcp_xform pdcp; }; /**< Configuration parameters for security session */ struct rte_crypto_sym_xform *crypto_xform; @@ -463,15 +525,17 @@ The ``rte_security_session_protocol`` is defined as .. code-block:: c enum rte_security_session_protocol { - RTE_SECURITY_PROTOCOL_IPSEC, + RTE_SECURITY_PROTOCOL_IPSEC = 1, /**< IPsec Protocol */ RTE_SECURITY_PROTOCOL_MACSEC, /**< MACSec Protocol */ + RTE_SECURITY_PROTOCOL_PDCP, + /**< PDCP Protocol */ }; -Currently the library defines configuration parameters for IPSec only. For other -protocols like MACSec, structures and enums are defined as place holders which -will be updated in the future. +Currently the library defines configuration parameters for IPsec and PDCP only. +For other protocols like MACSec, structures and enums are defined as place holders +which will be updated in the future. IPsec related configuration parameters are defined in ``rte_security_ipsec_xform`` @@ -494,6 +558,35 @@ IPsec related configuration parameters are defined in ``rte_security_ipsec_xform /**< Tunnel parameters, NULL for transport mode */ }; +PDCP related configuration parameters are defined in ``rte_security_pdcp_xform`` + +.. code-block:: c + + struct rte_security_pdcp_xform { + int8_t bearer; /**< PDCP bearer ID */ + /**< Enable in order delivery, this field shall be set only if + * driver/HW is capable. See RTE_SECURITY_PDCP_ORDERING_CAP. + */ + uint8_t en_ordering; + /**< Notify driver/HW to detect and remove duplicate packets. + * This field should be set only when driver/hw is capable. + * See RTE_SECURITY_PDCP_DUP_DETECT_CAP. + */ + uint8_t remove_duplicates; + /**< PDCP mode of operation: Control or data */ + enum rte_security_pdcp_domain domain; + /**< PDCP Frame Direction 0:UL 1:DL */ + enum rte_security_pdcp_direction pkt_dir; + /**< Sequence number size, 5/7/12/15/18 */ + enum rte_security_pdcp_sn_size sn_size; + /**< Starting Hyper Frame Number to be used together with the SN + * from the PDCP frames + */ + uint32_t hfn; + /**< HFN Threshold for key renegotiation */ + uint32_t hfn_threshold; + }; + Security API ~~~~~~~~~~~~ diff --git a/lib/librte_security/rte_security.c b/lib/librte_security/rte_security.c index 1954960..c6355de 100644 --- a/lib/librte_security/rte_security.c +++ b/lib/librte_security/rte_security.c @@ -131,6 +131,10 @@ rte_security_capability_get(struct rte_security_ctx *instance, capability->ipsec.direction == idx->ipsec.direction) return capability; + } else if (idx->protocol == RTE_SECURITY_PROTOCOL_PDCP) { + if (capability->pdcp.domain == + idx->pdcp.domain) + return capability; } } } diff --git a/lib/librte_security/rte_security.h b/lib/librte_security/rte_security.h index b0d1b97..a60e9d7 100644 --- a/lib/librte_security/rte_security.h +++ b/lib/librte_security/rte_security.h @@ -207,6 +207,64 @@ struct rte_security_macsec_xform { }; /** + * PDCP Mode of session + */ +enum rte_security_pdcp_domain { + RTE_SECURITY_PDCP_MODE_CONTROL, /**< PDCP control plane */ + RTE_SECURITY_PDCP_MODE_DATA, /**< PDCP data plane */ +}; + +/** PDCP Frame direction */ +enum rte_security_pdcp_direction { + RTE_SECURITY_PDCP_UPLINK, /**< Uplink */ + RTE_SECURITY_PDCP_DOWNLINK, /**< Downlink */ +}; + +/** PDCP Sequence Number Size selectors */ +enum rte_security_pdcp_sn_size { + RTE_SECURITY_PDCP_SN_SIZE_5 = 5, + /**< PDCP_SN_SIZE_5: 5bit sequence number */ + RTE_SECURITY_PDCP_SN_SIZE_7 = 7, + /**< PDCP_SN_SIZE_7: 7bit sequence number */ + RTE_SECURITY_PDCP_SN_SIZE_12 = 12, + /**< PDCP_SN_SIZE_12: 12bit sequence number */ + RTE_SECURITY_PDCP_SN_SIZE_15 = 15, + /**< PDCP_SN_SIZE_15: 15bit sequence number */ + RTE_SECURITY_PDCP_SN_SIZE_18 = 18 + /**< PDCP_SN_SIZE_18: 18bit sequence number */ +}; + +/** + * PDCP security association configuration data. + * + * This structure contains data required to create a PDCP security session. + */ +struct rte_security_pdcp_xform { + int8_t bearer; /**< PDCP bearer ID */ + uint8_t en_ordering; + /**< Enable in order delivery, this field shall be set only if + * driver/HW is capable. See RTE_SECURITY_PDCP_ORDERING_CAP. + */ + uint8_t remove_duplicates; + /**< Notify driver/HW to detect and remove duplicate packets. + * This field should be set only when driver/hw is capable. + * See RTE_SECURITY_PDCP_DUP_DETECT_CAP. + */ + enum rte_security_pdcp_domain domain; + /**< PDCP mode of operation: Control or data */ + enum rte_security_pdcp_direction pkt_dir; + /**< PDCP Frame Direction 0:UL 1:DL */ + enum rte_security_pdcp_sn_size sn_size; + /**< Sequence number size, 5/7/12/15/18 */ + uint32_t hfn; + /**< Starting Hyper Frame Number to be used together with the SN + * from the PDCP frames + */ + uint32_t hfn_threshold; + /**< HFN Threshold for key renegotiation */ +}; + +/** * Security session action type. */ enum rte_security_session_action_type { @@ -232,6 +290,8 @@ enum rte_security_session_protocol { /**< IPsec Protocol */ RTE_SECURITY_PROTOCOL_MACSEC, /**< MACSec Protocol */ + RTE_SECURITY_PROTOCOL_PDCP, + /**< PDCP Protocol */ }; /** @@ -246,6 +306,7 @@ struct rte_security_session_conf { union { struct rte_security_ipsec_xform ipsec; struct rte_security_macsec_xform macsec; + struct rte_security_pdcp_xform pdcp; }; /**< Configuration parameters for security session */ struct rte_crypto_sym_xform *crypto_xform; @@ -413,6 +474,10 @@ struct rte_security_ipsec_stats { }; +struct rte_security_pdcp_stats { + uint64_t reserved; +}; + struct rte_security_stats { enum rte_security_session_protocol protocol; /**< Security protocol to be configured */ @@ -421,6 +486,7 @@ struct rte_security_stats { union { struct rte_security_macsec_stats macsec; struct rte_security_ipsec_stats ipsec; + struct rte_security_pdcp_stats pdcp; }; }; @@ -465,6 +531,13 @@ struct rte_security_capability { int dummy; } macsec; /**< MACsec capability */ + struct { + enum rte_security_pdcp_domain domain; + /** < PDCP mode of operation: Control or data */ + uint32_t capa_flags; + /** < Capabilitity flags, see RTE_SECURITY_PDCP_* */ + } pdcp; + /**< PDCP capability */ }; const struct rte_cryptodev_capabilities *crypto_capabilities; @@ -474,6 +547,19 @@ struct rte_security_capability { /**< Device offload flags */ }; +/**< Underlying Hardware/driver which support PDCP may or may not support + * packet ordering. Set RTE_SECURITY_PDCP_ORDERING_CAP if it support. + * If it is not set, driver/HW assumes packets received are in order + * and it will be application's responsibility to maintain ordering. + */ +#define RTE_SECURITY_PDCP_ORDERING_CAP 0x00000001 + +/**< Underlying Hardware/driver which support PDCP may or may not detect + * duplicate packet. Set RTE_SECURITY_PDCP_DUP_DETECT_CAP if it support. + * If it is not set, driver/HW assumes there is no duplicate packet received. + */ +#define RTE_SECURITY_PDCP_DUP_DETECT_CAP 0x00000002 + #define RTE_SECURITY_TX_OLOAD_NEED_MDATA 0x00000001 /**< HW needs metadata update, see rte_security_set_pkt_metadata(). */ @@ -506,6 +592,10 @@ struct rte_security_capability_idx { enum rte_security_ipsec_sa_mode mode; enum rte_security_ipsec_sa_direction direction; } ipsec; + struct { + enum rte_security_pdcp_domain domain; + uint32_t capa_flags; + } pdcp; }; }; From patchwork Mon Oct 22 07:12:09 2018 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Hemant Agrawal X-Patchwork-Id: 149373 Delivered-To: patch@linaro.org Received: by 2002:a2e:8595:0:0:0:0:0 with SMTP id b21-v6csp2295992lji; Mon, 22 Oct 2018 00:15:02 -0700 (PDT) X-Google-Smtp-Source: ACcGV63ACTF3JhTAc6tMUB1tqs8z6g3kmhtrRf+Fy6qY6eisye3HIcMIXnCsQmtyQDn+rR6lBPnS X-Received: by 2002:a1c:84cd:: with SMTP id g196-v6mr14572961wmd.38.1540192502823; Mon, 22 Oct 2018 00:15:02 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1540192502; cv=none; d=google.com; s=arc-20160816; b=mYhA/QxX0gLwAs7Bf/j9T2s3xQwzU30cnoE+8ZcOGtnBRmXz8rtlnLaKKYIHhW20ai 28ED4mY20ECiR9f81A7AorW+bybGcbOuby0b+xyYZCQtWn6OcIMN4anjiCE1aqMu6RnU +C4rNdXb/nXub44LM1qMWG+QMEGTYVfudIIZOn0Tl2NPv7+cTbFMHwlTgjgb6LtN3H3h URqc3zSegxPVG1unXRt00nTvvrOP3+vxN9/gjPZPPFgobnHVyo1vHrZKv4gGq5cpNuMG keXwULCBynJG18auuKZK++wiI9w4CU+fn/YeqwjVDsOjGiXefZyuwhhcKjURyYngJX84 1a8A== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=sender:errors-to:list-subscribe:list-help:list-post:list-archive :list-unsubscribe:list-id:precedence:subject:references:in-reply-to :message-id:date:cc:to:from; bh=p64MPkEm7EgMU1jJsaLAlMo1tV2Rs5fmXtJT5jkg97Q=; b=MalaZG9peXPECZsEl4HJxAbQrOlWy+NHrDa3SaBSwYD8eMsfh+ndMAKybf06M3tsNS BdFl+mBePUP5T0OO6rUnR62OV+DtQa00gyRXfrJEmkXB+5CxXihe8LPtDP5mXFRezxi0 XxlT8PT8X8sriW3NVrjpMbbXpBjQ57HA1SMnPXrKAM/kG53q7KdSNg/Vwmsxd6So0Hij avsQBAZlbVA39Etg/85HHzdPBLAttQuRUP9sbiD+WjZPD9Jtgx5orkTpboqzkZMGiiJ2 8t8POqJDzHvFB+CrCKqfdmtGXb1HQACnXPzQ6U/tzd34XGbl8P8mWKO5z0PDKnSgBFTb OsdA== ARC-Authentication-Results: i=1; mx.google.com; spf=pass (google.com: domain of dev-bounces@dpdk.org designates 92.243.14.124 as permitted sender) smtp.mailfrom=dev-bounces@dpdk.org; dmarc=fail (p=NONE sp=NONE dis=NONE) header.from=nxp.com Return-Path: Received: from dpdk.org (dpdk.org. [92.243.14.124]) by mx.google.com with ESMTP id w184-v6si8687378wmg.96.2018.10.22.00.15.02; Mon, 22 Oct 2018 00:15:02 -0700 (PDT) Received-SPF: pass (google.com: domain of dev-bounces@dpdk.org designates 92.243.14.124 as permitted sender) client-ip=92.243.14.124; Authentication-Results: mx.google.com; spf=pass (google.com: domain of dev-bounces@dpdk.org designates 92.243.14.124 as permitted sender) smtp.mailfrom=dev-bounces@dpdk.org; dmarc=fail (p=NONE sp=NONE dis=NONE) header.from=nxp.com Received: from [92.243.14.124] (localhost [127.0.0.1]) by dpdk.org (Postfix) with ESMTP id A33905681; Mon, 22 Oct 2018 09:14:48 +0200 (CEST) Received: from inva020.nxp.com (inva020.nxp.com [92.121.34.13]) by dpdk.org (Postfix) with ESMTP id 3375C4CA7 for ; Mon, 22 Oct 2018 09:14:41 +0200 (CEST) Received: from inva020.nxp.com (localhost [127.0.0.1]) by inva020.eu-rdc02.nxp.com (Postfix) with ESMTP id 9BB5E1A01C8; Mon, 22 Oct 2018 09:14:40 +0200 (CEST) Received: from invc005.ap-rdc01.nxp.com (invc005.ap-rdc01.nxp.com [165.114.16.14]) by inva020.eu-rdc02.nxp.com (Postfix) with ESMTP id 0B4861A01BE; Mon, 22 Oct 2018 09:14:34 +0200 (CEST) Received: from bf-netperf1.ap.freescale.net (bf-netperf1.ap.freescale.net [10.232.134.28]) by invc005.ap-rdc01.nxp.com (Postfix) with ESMTP id A718040309; Mon, 22 Oct 2018 15:14:26 +0800 (SGT) From: Hemant Agrawal To: dev@dpdk.org Cc: thomas@monjalon.net, pablo.de.lara.guarch@intel.com, radu.nicolau@intel.com, jerin.jacob@caviumnetworks.com, narayanaprasad.athreya@caviumnetworks.com, Shally.Verma@caviumnetworks.com, Anoob.Joseph@caviumnetworks.com, Vidya.Velumuri@caviumnetworks.com, akhil.goyal@nxp.com, Horia Geanta Neag , Alex Porosanu Date: Mon, 22 Oct 2018 12:42:09 +0530 Message-Id: <1540192330-4105-3-git-send-email-hemant.agrawal@nxp.com> X-Mailer: git-send-email 2.7.4 In-Reply-To: <1540192330-4105-1-git-send-email-hemant.agrawal@nxp.com> References: <20181016103352.2678-1-akhil.goyal@nxp.com> <1540192330-4105-1-git-send-email-hemant.agrawal@nxp.com> X-Virus-Scanned: ClamAV using ClamSMTP Subject: [dpdk-dev] [PATCH v6 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 List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: dev-bounces@dpdk.org Sender: "dev" From: Akhil Goyal 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 Signed-off-by: Horia Geanta Neag Signed-off-by: Alex Porosanu Signed-off-by: Akhil Goyal --- 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 -- 2.7.4 diff --git a/drivers/crypto/dpaa2_sec/hw/desc.h b/drivers/crypto/dpaa2_sec/hw/desc.h index ca94ea3..5d99dd8 100644 --- a/drivers/crypto/dpaa2_sec/hw/desc.h +++ b/drivers/crypto/dpaa2_sec/hw/desc.h @@ -868,7 +868,7 @@ #define OP_PCL_LTE_MIXED_AUTH_SHIFT 0 #define OP_PCL_LTE_MIXED_AUTH_MASK (3 << OP_PCL_LTE_MIXED_AUTH_SHIFT) #define OP_PCL_LTE_MIXED_ENC_SHIFT 8 -#define OP_PCL_LTE_MIXED_ENC_MASK (3 < OP_PCL_LTE_MIXED_ENC_SHIFT) +#define OP_PCL_LTE_MIXED_ENC_MASK (3 << OP_PCL_LTE_MIXED_ENC_SHIFT) #define OP_PCL_LTE_MIXED_AUTH_NULL (OP_PCL_LTE_NULL << \ OP_PCL_LTE_MIXED_AUTH_SHIFT) #define OP_PCL_LTE_MIXED_AUTH_SNOW (OP_PCL_LTE_SNOW << \ diff --git a/drivers/crypto/dpaa2_sec/hw/desc/pdcp.h b/drivers/crypto/dpaa2_sec/hw/desc/pdcp.h new file mode 100644 index 0000000..719ef60 --- /dev/null +++ b/drivers/crypto/dpaa2_sec/hw/desc/pdcp.h @@ -0,0 +1,2796 @@ +/* + * Copyright 2008-2013 Freescale Semiconductor, Inc. + * + * SPDX-License-Identifier: BSD-3-Clause or GPL-2.0+ + */ + +#ifndef __DESC_PDCP_H__ +#define __DESC_PDCP_H__ + +#include "hw/rta.h" +#include "common.h" + +/** + * DOC: PDCP Shared Descriptor Constructors + * + * Shared descriptors for PDCP protocol. + */ + +/** + * PDCP_NULL_MAX_FRAME_LEN - The maximum frame frame length that is supported by + * PDCP NULL protocol. + */ +#define PDCP_NULL_MAX_FRAME_LEN 0x00002FFF + +/** + * PDCP_MAC_I_LEN - The length of the MAC-I for PDCP protocol operation + */ +#define PDCP_MAC_I_LEN 0x00000004 + +/** + * PDCP_MAX_FRAME_LEN_STATUS - The status returned in FD status/command field in + * case the input frame is larger than + * PDCP_NULL_MAX_FRAME_LEN. + */ +#define PDCP_MAX_FRAME_LEN_STATUS 0xF1 + +/** + * PDCP_C_PLANE_SN_MASK - This mask is used in the PDCP descriptors for + * extracting the sequence number (SN) from the PDCP + * Control Plane header. For PDCP Control Plane, the SN + * is constant (5 bits) as opposed to PDCP Data Plane + * (7/12/15 bits). + */ +#define PDCP_C_PLANE_SN_MASK 0x1F000000 +#define PDCP_C_PLANE_SN_MASK_BE 0x0000001F + +/** + * PDCP_U_PLANE_15BIT_SN_MASK - This mask is used in the PDCP descriptors for + * extracting the sequence number (SN) from the + * PDCP User Plane header. For PDCP Control Plane, + * the SN is constant (5 bits) as opposed to PDCP + * Data Plane (7/12/15 bits). + */ +#define PDCP_U_PLANE_15BIT_SN_MASK 0xFF7F0000 +#define PDCP_U_PLANE_15BIT_SN_MASK_BE 0x00007FFF + +/** + * PDCP_BEARER_MASK - This mask is used masking out the bearer for PDCP + * processing with SNOW f9 in LTE. + * + * The value on which this mask is applied is formatted as below: + * Count-C (32 bit) | Bearer (5 bit) | Direction (1 bit) | 0 (26 bits) + * + * Applying this mask is done for creating the upper 64 bits of the IV needed + * for SNOW f9. + * + * The lower 32 bits of the mask are used for masking the direction for AES + * CMAC IV. + */ +#define PDCP_BEARER_MASK 0x00000004FFFFFFFFull +#define PDCP_BEARER_MASK_BE 0xFFFFFFFF04000000ull + +/** + * PDCP_DIR_MASK - This mask is used masking out the direction for PDCP + * processing with SNOW f9 in LTE. + * + * The value on which this mask is applied is formatted as below: + * Bearer (5 bit) | Direction (1 bit) | 0 (26 bits) + * + * Applying this mask is done for creating the lower 32 bits of the IV needed + * for SNOW f9. + * + * The upper 32 bits of the mask are used for masking the direction for AES + * CMAC IV. + */ +#define PDCP_DIR_MASK 0x00000000000000F8ull +#define PDCP_DIR_MASK_BE 0xF800000000000000ull + +/** + * PDCP_NULL_INT_MAC_I_VAL - The value of the PDCP PDU MAC-I in case NULL + * integrity is used. + */ + +#define PDCP_NULL_INT_MAC_I_VAL 0x00000000 + +/** + * PDCP_NULL_INT_ICV_CHECK_FAILED_STATUS - The status used to report ICV check + * failed in case of NULL integrity + * Control Plane processing. + */ +#define PDCP_NULL_INT_ICV_CHECK_FAILED_STATUS 0x0A +/** + * PDCP_DPOVRD_HFN_OV_EN - Value to be used in the FD status/cmd field to + * indicate the HFN override mechanism is active for the + * frame. + */ +#define PDCP_DPOVRD_HFN_OV_EN 0x80000000 + +/** + * PDCP_P4080REV2_HFN_OV_BUFLEN - The length in bytes of the supplementary space + * that must be provided by the user at the + * beginning of the input frame buffer for + * P4080 REV 2. + * + * The format of the frame buffer is the following: + * + * |<---PDCP_P4080REV2_HFN_OV_BUFLEN-->| + * //===================================||============||==============\\ + * || PDCP_DPOVRD_HFN_OV_EN | HFN value || PDCP Header|| PDCP Payload || + * \\===================================||============||==============// + * + * If HFN override mechanism is not desired, then the MSB of the first 4 bytes + * must be set to 0b. + */ +#define PDCP_P4080REV2_HFN_OV_BUFLEN 4 + +/** + * enum cipher_type_pdcp - Type selectors for cipher types in PDCP protocol OP + * instructions. + * @PDCP_CIPHER_TYPE_NULL: NULL + * @PDCP_CIPHER_TYPE_SNOW: SNOW F8 + * @PDCP_CIPHER_TYPE_AES: AES + * @PDCP_CIPHER_TYPE_ZUC: ZUCE + * @PDCP_CIPHER_TYPE_INVALID: invalid option + */ +enum cipher_type_pdcp { + PDCP_CIPHER_TYPE_NULL, + PDCP_CIPHER_TYPE_SNOW, + PDCP_CIPHER_TYPE_AES, + PDCP_CIPHER_TYPE_ZUC, + PDCP_CIPHER_TYPE_INVALID +}; + +/** + * enum auth_type_pdcp - Type selectors for integrity types in PDCP protocol OP + * instructions. + * @PDCP_AUTH_TYPE_NULL: NULL + * @PDCP_AUTH_TYPE_SNOW: SNOW F9 + * @PDCP_AUTH_TYPE_AES: AES CMAC + * @PDCP_AUTH_TYPE_ZUC: ZUCA + * @PDCP_AUTH_TYPE_INVALID: invalid option + */ +enum auth_type_pdcp { + PDCP_AUTH_TYPE_NULL, + PDCP_AUTH_TYPE_SNOW, + PDCP_AUTH_TYPE_AES, + PDCP_AUTH_TYPE_ZUC, + PDCP_AUTH_TYPE_INVALID +}; + +/** + * enum pdcp_dir - Type selectors for direction for PDCP protocol + * @PDCP_DIR_UPLINK: uplink direction + * @PDCP_DIR_DOWNLINK: downlink direction + * @PDCP_DIR_INVALID: invalid option + */ +enum pdcp_dir { + PDCP_DIR_UPLINK = 0, + PDCP_DIR_DOWNLINK = 1, + PDCP_DIR_INVALID +}; + +/** + * enum pdcp_plane - PDCP domain selectors + * @PDCP_CONTROL_PLANE: Control Plane + * @PDCP_DATA_PLANE: Data Plane + * @PDCP_SHORT_MAC: Short MAC + */ +enum pdcp_plane { + PDCP_CONTROL_PLANE, + PDCP_DATA_PLANE, + PDCP_SHORT_MAC +}; + +/** + * enum pdcp_sn_size - Sequence Number Size selectors for PDCP protocol + * @PDCP_SN_SIZE_5: 5bit sequence number + * @PDCP_SN_SIZE_7: 7bit sequence number + * @PDCP_SN_SIZE_12: 12bit sequence number + * @PDCP_SN_SIZE_15: 15bit sequence number + * @PDCP_SN_SIZE_18: 18bit sequence number + */ +enum pdcp_sn_size { + PDCP_SN_SIZE_5 = 5, + PDCP_SN_SIZE_7 = 7, + PDCP_SN_SIZE_12 = 12, + PDCP_SN_SIZE_15 = 15 +}; + +/* + * PDCP Control Plane Protocol Data Blocks + */ +#define PDCP_C_PLANE_PDB_HFN_SHIFT 5 +#define PDCP_C_PLANE_PDB_BEARER_SHIFT 27 +#define PDCP_C_PLANE_PDB_DIR_SHIFT 26 +#define PDCP_C_PLANE_PDB_HFN_THR_SHIFT 5 + +#define PDCP_U_PLANE_PDB_OPT_SHORT_SN 0x2 +#define PDCP_U_PLANE_PDB_OPT_15B_SN 0x4 +#define PDCP_U_PLANE_PDB_SHORT_SN_HFN_SHIFT 7 +#define PDCP_U_PLANE_PDB_LONG_SN_HFN_SHIFT 12 +#define PDCP_U_PLANE_PDB_15BIT_SN_HFN_SHIFT 15 +#define PDCP_U_PLANE_PDB_BEARER_SHIFT 27 +#define PDCP_U_PLANE_PDB_DIR_SHIFT 26 +#define PDCP_U_PLANE_PDB_SHORT_SN_HFN_THR_SHIFT 7 +#define PDCP_U_PLANE_PDB_LONG_SN_HFN_THR_SHIFT 12 +#define PDCP_U_PLANE_PDB_15BIT_SN_HFN_THR_SHIFT 15 + +struct pdcp_pdb { + union { + uint32_t opt; + uint32_t rsvd; + } opt_res; + uint32_t hfn_res; /* HyperFrame number,(27, 25 or 21 bits), + * left aligned & right-padded with zeros. + */ + uint32_t bearer_dir_res;/* Bearer(5 bits), packet direction (1 bit), + * left aligned & right-padded with zeros. + */ + uint32_t hfn_thr_res; /* HyperFrame number threshold (27, 25 or 21 + * bits), left aligned & right-padded with + * zeros. + */ +}; + +/* + * PDCP internal PDB types + */ +enum pdb_type_e { + PDCP_PDB_TYPE_NO_PDB, + PDCP_PDB_TYPE_FULL_PDB, + PDCP_PDB_TYPE_REDUCED_PDB, + PDCP_PDB_TYPE_INVALID +}; + +/* + * Function for appending the portion of a PDCP Control Plane shared descriptor + * which performs NULL encryption and integrity (i.e. copies the input frame + * to the output frame, appending 32 bits of zeros at the end (MAC-I for + * NULL integrity). + */ +static inline int +pdcp_insert_cplane_null_op(struct program *p, + bool swap __maybe_unused, + struct alginfo *cipherdata __maybe_unused, + struct alginfo *authdata __maybe_unused, + unsigned int dir, + unsigned char era_2_sw_hfn_ovrd __maybe_unused) +{ + LABEL(local_offset); + REFERENCE(move_cmd_read_descbuf); + REFERENCE(move_cmd_write_descbuf); + + if (rta_sec_era > RTA_SEC_ERA_2) { + MATHB(p, SEQINSZ, ADD, ZERO, VSEQINSZ, 4, 0); + if (dir == OP_TYPE_ENCAP_PROTOCOL) + MATHB(p, SEQINSZ, ADD, PDCP_MAC_I_LEN, VSEQOUTSZ, 4, + IMMED2); + else + MATHB(p, SEQINSZ, SUB, PDCP_MAC_I_LEN, VSEQOUTSZ, 4, + IMMED2); + } else { + MATHB(p, SEQINSZ, ADD, ONE, VSEQINSZ, 4, 0); + MATHB(p, VSEQINSZ, SUB, ONE, VSEQINSZ, 4, 0); + + if (dir == OP_TYPE_ENCAP_PROTOCOL) { + MATHB(p, SEQINSZ, ADD, PDCP_MAC_I_LEN, VSEQOUTSZ, 4, + IMMED2); + MATHB(p, VSEQINSZ, SUB, ONE, MATH0, 4, 0); + } else { + MATHB(p, VSEQINSZ, SUB, PDCP_MAC_I_LEN, VSEQINSZ, 4, + IMMED2); + MATHB(p, SEQINSZ, SUB, PDCP_MAC_I_LEN, VSEQOUTSZ, 4, + IMMED2); + MATHB(p, VSEQOUTSZ, SUB, ONE, MATH0, 4, 0); + } + + MATHB(p, MATH0, ADD, ONE, MATH0, 4, 0); + + /* + * Since MOVELEN is available only starting with + * SEC ERA 3, use poor man's MOVELEN: create a MOVE + * command dynamically by writing the length from M1 by + * OR-ing the command in the M1 register and MOVE the + * result into the descriptor buffer. Care must be taken + * wrt. the location of the command because of SEC + * pipelining. The actual MOVEs are written at the end + * of the descriptor due to calculations needed on the + * offset in the descriptor for the MOVE command. + */ + move_cmd_read_descbuf = MOVE(p, DESCBUF, 0, MATH0, 0, 6, + IMMED); + move_cmd_write_descbuf = MOVE(p, MATH0, 0, DESCBUF, 0, 8, + WAITCOMP | IMMED); + } + MATHB(p, VSEQINSZ, SUB, PDCP_NULL_MAX_FRAME_LEN, NONE, 4, + IMMED2); + JUMP(p, PDCP_MAX_FRAME_LEN_STATUS, HALT_STATUS, ALL_FALSE, MATH_N); + + if (rta_sec_era > RTA_SEC_ERA_2) { + if (dir == OP_TYPE_ENCAP_PROTOCOL) + MATHB(p, VSEQINSZ, ADD, ZERO, MATH0, 4, 0); + else + MATHB(p, VSEQOUTSZ, ADD, ZERO, MATH0, 4, 0); + } + SEQFIFOSTORE(p, MSG, 0, 0, VLF); + SEQFIFOLOAD(p, MSG1, 0, VLF | LAST1 | FLUSH1); + + if (rta_sec_era > RTA_SEC_ERA_2) { + MOVE(p, AB1, 0, OFIFO, 0, MATH0, 0); + } else { + SET_LABEL(p, local_offset); + + /* Shut off automatic Info FIFO entries */ + LOAD(p, 0, DCTRL, LDOFF_DISABLE_AUTO_NFIFO, 0, IMMED); + /* Placeholder for MOVE command with length from M1 register */ + MOVE(p, IFIFOAB1, 0, OFIFO, 0, 0, IMMED); + /* Enable automatic Info FIFO entries */ + LOAD(p, 0, DCTRL, LDOFF_ENABLE_AUTO_NFIFO, 0, IMMED); + } + + if (dir == OP_TYPE_ENCAP_PROTOCOL) { + MATHB(p, MATH1, XOR, MATH1, MATH0, 8, 0); + MOVE(p, MATH0, 0, OFIFO, 0, 4, IMMED); + } + + if (rta_sec_era < RTA_SEC_ERA_3) { + PATCH_MOVE(p, move_cmd_read_descbuf, local_offset); + PATCH_MOVE(p, move_cmd_write_descbuf, local_offset); + } + + return 0; +} + +static inline int +insert_copy_frame_op(struct program *p, + struct alginfo *cipherdata __maybe_unused, + unsigned int dir __maybe_unused) +{ + LABEL(local_offset); + REFERENCE(move_cmd_read_descbuf); + REFERENCE(move_cmd_write_descbuf); + + if (rta_sec_era > RTA_SEC_ERA_2) { + MATHB(p, SEQINSZ, ADD, ZERO, VSEQINSZ, 4, 0); + MATHB(p, SEQINSZ, ADD, ZERO, VSEQOUTSZ, 4, 0); + } else { + MATHB(p, SEQINSZ, ADD, ONE, VSEQINSZ, 4, 0); + MATHB(p, VSEQINSZ, SUB, ONE, VSEQINSZ, 4, 0); + MATHB(p, SEQINSZ, ADD, ONE, VSEQOUTSZ, 4, 0); + MATHB(p, VSEQOUTSZ, SUB, ONE, VSEQOUTSZ, 4, 0); + MATHB(p, VSEQINSZ, SUB, ONE, MATH0, 4, 0); + MATHB(p, MATH0, ADD, ONE, MATH0, 4, 0); + + /* + * Since MOVELEN is available only starting with + * SEC ERA 3, use poor man's MOVELEN: create a MOVE + * command dynamically by writing the length from M1 by + * OR-ing the command in the M1 register and MOVE the + * result into the descriptor buffer. Care must be taken + * wrt. the location of the command because of SEC + * pipelining. The actual MOVEs are written at the end + * of the descriptor due to calculations needed on the + * offset in the descriptor for the MOVE command. + */ + move_cmd_read_descbuf = MOVE(p, DESCBUF, 0, MATH0, 0, 6, + IMMED); + move_cmd_write_descbuf = MOVE(p, MATH0, 0, DESCBUF, 0, 8, + WAITCOMP | IMMED); + } + MATHB(p, SEQINSZ, SUB, PDCP_NULL_MAX_FRAME_LEN, NONE, 4, + IFB | IMMED2); + JUMP(p, PDCP_MAX_FRAME_LEN_STATUS, HALT_STATUS, ALL_FALSE, MATH_N); + + if (rta_sec_era > RTA_SEC_ERA_2) + MATHB(p, VSEQINSZ, ADD, ZERO, MATH0, 4, 0); + + SEQFIFOLOAD(p, MSG1, 0, VLF | LAST1 | FLUSH1); + if (rta_sec_era > RTA_SEC_ERA_2) { + MOVE(p, AB1, 0, OFIFO, 0, MATH0, 0); + } else { + SET_LABEL(p, local_offset); + + /* Shut off automatic Info FIFO entries */ + LOAD(p, 0, DCTRL, LDOFF_DISABLE_AUTO_NFIFO, 0, IMMED); + + /* Placeholder for MOVE command with length from M0 register */ + MOVE(p, IFIFOAB1, 0, OFIFO, 0, 0, IMMED); + + /* Enable automatic Info FIFO entries */ + LOAD(p, 0, DCTRL, LDOFF_ENABLE_AUTO_NFIFO, 0, IMMED); + } + + SEQFIFOSTORE(p, MSG, 0, 0, VLF); + + if (rta_sec_era < RTA_SEC_ERA_3) { + PATCH_MOVE(p, move_cmd_read_descbuf, local_offset); + PATCH_MOVE(p, move_cmd_write_descbuf, local_offset); + } + return 0; +} + +static inline int +pdcp_insert_cplane_int_only_op(struct program *p, + bool swap __maybe_unused, + struct alginfo *cipherdata __maybe_unused, + struct alginfo *authdata, unsigned int dir, + unsigned char era_2_sw_hfn_ovrd) +{ + LABEL(local_offset); + REFERENCE(move_cmd_read_descbuf); + REFERENCE(move_cmd_write_descbuf); + + switch (authdata->algtype) { + case PDCP_AUTH_TYPE_SNOW: + /* Insert Auth Key */ + KEY(p, KEY2, authdata->key_enc_flags, authdata->key, + authdata->keylen, INLINE_KEY(authdata)); + SEQLOAD(p, MATH0, 7, 1, 0); + JUMP(p, 1, LOCAL_JUMP, ALL_TRUE, CALM); + + if (rta_sec_era > RTA_SEC_ERA_2 || + (rta_sec_era == RTA_SEC_ERA_2 && + era_2_sw_hfn_ovrd == 0)) { + SEQINPTR(p, 0, 1, RTO); + } else { + SEQINPTR(p, 0, 5, RTO); + SEQFIFOLOAD(p, SKIP, 4, 0); + } + + if (swap == false) { + MATHB(p, MATH0, AND, PDCP_C_PLANE_SN_MASK, MATH1, 8, + IFB | IMMED2); + MATHB(p, MATH1, SHLD, MATH1, MATH1, 8, 0); + + MOVEB(p, DESCBUF, 8, MATH2, 0, 8, WAITCOMP | IMMED); + + MATHB(p, MATH2, AND, PDCP_BEARER_MASK, MATH2, 8, + IMMED2); + MOVEB(p, DESCBUF, 0x0C, MATH3, 0, 4, WAITCOMP | IMMED); + MATHB(p, MATH3, AND, PDCP_DIR_MASK, MATH3, 8, IMMED2); + MATHB(p, MATH1, OR, MATH2, MATH2, 8, 0); + MOVEB(p, MATH2, 0, CONTEXT2, 0, 0x0C, WAITCOMP | IMMED); + } else { + MATHB(p, MATH0, AND, PDCP_C_PLANE_SN_MASK_BE, MATH1, 8, + IFB | IMMED2); + MATHB(p, MATH1, SHLD, MATH1, MATH1, 8, 0); + + MOVE(p, DESCBUF, 8, MATH2, 0, 8, WAITCOMP | IMMED); + MATHB(p, MATH2, AND, PDCP_BEARER_MASK_BE, MATH2, 8, + IMMED2); + + MOVE(p, DESCBUF, 0x0C, MATH3, 0, 4, WAITCOMP | IMMED); + MATHB(p, MATH3, AND, PDCP_DIR_MASK_BE, MATH3, 8, + IMMED2); + MATHB(p, MATH1, OR, MATH2, MATH2, 8, 0); + MOVE(p, MATH2, 0, CONTEXT2, 0, 0x0C, WAITCOMP | IMMED); + } + + if (dir == OP_TYPE_DECAP_PROTOCOL) { + MATHB(p, SEQINSZ, SUB, PDCP_MAC_I_LEN, MATH1, 4, + IMMED2); + } else { + if (rta_sec_era > RTA_SEC_ERA_2) { + MATHB(p, SEQINSZ, SUB, ZERO, MATH1, 4, + 0); + } else { + MATHB(p, SEQINSZ, ADD, ONE, MATH1, 4, + 0); + MATHB(p, MATH1, SUB, ONE, MATH1, 4, + 0); + } + } + + if (rta_sec_era > RTA_SEC_ERA_2) { + MATHB(p, MATH1, SUB, ZERO, VSEQINSZ, 4, 0); + MATHB(p, MATH1, SUB, ZERO, VSEQOUTSZ, 4, 0); + } else { + MATHB(p, ZERO, ADD, MATH1, VSEQINSZ, 4, 0); + MATHB(p, ZERO, ADD, MATH1, VSEQOUTSZ, 4, 0); + + /* + * Since MOVELEN is available only starting with + * SEC ERA 3, use poor man's MOVELEN: create a MOVE + * command dynamically by writing the length from M1 by + * OR-ing the command in the M1 register and MOVE the + * result into the descriptor buffer. Care must be taken + * wrt. the location of the command because of SEC + * pipelining. The actual MOVEs are written at the end + * of the descriptor due to calculations needed on the + * offset in the descriptor for the MOVE command. + */ + move_cmd_read_descbuf = MOVE(p, DESCBUF, 0, MATH1, 0, 6, + IMMED); + move_cmd_write_descbuf = MOVE(p, MATH1, 0, DESCBUF, 0, + 8, WAITCOMP | IMMED); + } + + SEQFIFOSTORE(p, MSG, 0, 0, VLF); + ALG_OPERATION(p, OP_ALG_ALGSEL_SNOW_F9, OP_ALG_AAI_F9, + OP_ALG_AS_INITFINAL, + dir == OP_TYPE_ENCAP_PROTOCOL ? + ICV_CHECK_DISABLE : ICV_CHECK_ENABLE, + DIR_ENC); + + if (rta_sec_era > RTA_SEC_ERA_2) { + SEQFIFOLOAD(p, MSGINSNOOP, 0, + VLF | LAST1 | LAST2 | FLUSH1); + MOVE(p, AB1, 0, OFIFO, 0, MATH1, 0); + } else { + SEQFIFOLOAD(p, MSGINSNOOP, 0, + VLF | LAST1 | LAST2 | FLUSH1); + SET_LABEL(p, local_offset); + + /* Shut off automatic Info FIFO entries */ + LOAD(p, 0, DCTRL, LDOFF_DISABLE_AUTO_NFIFO, 0, IMMED); + /* + * Placeholder for MOVE command with length from M1 + * register + */ + MOVE(p, IFIFOAB1, 0, OFIFO, 0, 0, IMMED); + /* Enable automatic Info FIFO entries */ + LOAD(p, 0, DCTRL, LDOFF_ENABLE_AUTO_NFIFO, 0, IMMED); + } + + if (dir == OP_TYPE_DECAP_PROTOCOL) + SEQFIFOLOAD(p, ICV2, 4, LAST2); + else + SEQSTORE(p, CONTEXT2, 0, 4, 0); + + break; + + case PDCP_AUTH_TYPE_AES: + /* Insert Auth Key */ + KEY(p, KEY1, authdata->key_enc_flags, authdata->key, + authdata->keylen, INLINE_KEY(authdata)); + SEQLOAD(p, MATH0, 7, 1, 0); + JUMP(p, 1, LOCAL_JUMP, ALL_TRUE, CALM); + if (rta_sec_era > RTA_SEC_ERA_2 || + (rta_sec_era == RTA_SEC_ERA_2 && + era_2_sw_hfn_ovrd == 0)) { + SEQINPTR(p, 0, 1, RTO); + } else { + SEQINPTR(p, 0, 5, RTO); + SEQFIFOLOAD(p, SKIP, 4, 0); + } + + if (swap == false) { + MATHB(p, MATH0, AND, PDCP_C_PLANE_SN_MASK, MATH1, 8, + IFB | IMMED2); + MATHB(p, MATH1, SHLD, MATH1, MATH1, 8, 0); + + MOVEB(p, DESCBUF, 8, MATH2, 0, 8, WAITCOMP | IMMED); + MATHB(p, MATH1, OR, MATH2, MATH2, 8, 0); + MOVEB(p, MATH2, 0, IFIFOAB1, 0, 8, IMMED); + } else { + MATHB(p, MATH0, AND, PDCP_C_PLANE_SN_MASK_BE, MATH1, 8, + IFB | IMMED2); + MATHB(p, MATH1, SHLD, MATH1, MATH1, 8, 0); + + MOVE(p, DESCBUF, 8, MATH2, 0, 8, WAITCOMP | IMMED); + MATHB(p, MATH1, OR, MATH2, MATH2, 8, 0); + MOVE(p, MATH2, 0, IFIFOAB1, 0, 8, IMMED); + } + + if (dir == OP_TYPE_DECAP_PROTOCOL) { + MATHB(p, SEQINSZ, SUB, PDCP_MAC_I_LEN, MATH1, 4, + IMMED2); + } else { + if (rta_sec_era > RTA_SEC_ERA_2) { + MATHB(p, SEQINSZ, SUB, ZERO, MATH1, 4, + 0); + } else { + MATHB(p, SEQINSZ, ADD, ONE, MATH1, 4, + 0); + MATHB(p, MATH1, SUB, ONE, MATH1, 4, + 0); + } + } + + if (rta_sec_era > RTA_SEC_ERA_2) { + MATHB(p, MATH1, SUB, ZERO, VSEQINSZ, 4, 0); + MATHB(p, MATH1, SUB, ZERO, VSEQOUTSZ, 4, 0); + } else { + MATHB(p, ZERO, ADD, MATH1, VSEQINSZ, 4, 0); + MATHB(p, ZERO, ADD, MATH1, VSEQOUTSZ, 4, 0); + + /* + * Since MOVELEN is available only starting with + * SEC ERA 3, use poor man's MOVELEN: create a MOVE + * command dynamically by writing the length from M1 by + * OR-ing the command in the M1 register and MOVE the + * result into the descriptor buffer. Care must be taken + * wrt. the location of the command because of SEC + * pipelining. The actual MOVEs are written at the end + * of the descriptor due to calculations needed on the + * offset in the descriptor for the MOVE command. + */ + move_cmd_read_descbuf = MOVE(p, DESCBUF, 0, MATH1, 0, 6, + IMMED); + move_cmd_write_descbuf = MOVE(p, MATH1, 0, DESCBUF, 0, + 8, WAITCOMP | IMMED); + } + SEQFIFOSTORE(p, MSG, 0, 0, VLF); + ALG_OPERATION(p, OP_ALG_ALGSEL_AES, + OP_ALG_AAI_CMAC, + OP_ALG_AS_INITFINAL, + dir == OP_TYPE_ENCAP_PROTOCOL ? + ICV_CHECK_DISABLE : ICV_CHECK_ENABLE, + DIR_ENC); + + if (rta_sec_era > RTA_SEC_ERA_2) { + MOVE(p, AB2, 0, OFIFO, 0, MATH1, 0); + SEQFIFOLOAD(p, MSGINSNOOP, 0, + VLF | LAST1 | LAST2 | FLUSH1); + } else { + SEQFIFOLOAD(p, MSGINSNOOP, 0, + VLF | LAST1 | LAST2 | FLUSH1); + SET_LABEL(p, local_offset); + + /* Shut off automatic Info FIFO entries */ + LOAD(p, 0, DCTRL, LDOFF_DISABLE_AUTO_NFIFO, 0, IMMED); + + /* + * Placeholder for MOVE command with length from + * M1 register + */ + MOVE(p, IFIFOAB2, 0, OFIFO, 0, 0, IMMED); + + /* Enable automatic Info FIFO entries */ + LOAD(p, 0, DCTRL, LDOFF_ENABLE_AUTO_NFIFO, 0, IMMED); + } + + if (dir == OP_TYPE_DECAP_PROTOCOL) + SEQFIFOLOAD(p, ICV1, 4, LAST1 | FLUSH1); + else + SEQSTORE(p, CONTEXT1, 0, 4, 0); + + break; + + case PDCP_AUTH_TYPE_ZUC: + if (rta_sec_era < RTA_SEC_ERA_5) { + pr_err("Invalid era for selected algorithm\n"); + return -ENOTSUP; + } + /* Insert Auth Key */ + KEY(p, KEY2, authdata->key_enc_flags, authdata->key, + authdata->keylen, INLINE_KEY(authdata)); + SEQLOAD(p, MATH0, 7, 1, 0); + JUMP(p, 1, LOCAL_JUMP, ALL_TRUE, CALM); + SEQINPTR(p, 0, 1, RTO); + if (swap == false) { + MATHB(p, MATH0, AND, PDCP_C_PLANE_SN_MASK, MATH1, 8, + IFB | IMMED2); + MATHB(p, MATH1, SHLD, MATH1, MATH1, 8, 0); + + MOVEB(p, DESCBUF, 8, MATH2, 0, 8, WAITCOMP | IMMED); + MATHB(p, MATH1, OR, MATH2, MATH2, 8, 0); + MOVEB(p, MATH2, 0, CONTEXT2, 0, 8, IMMED); + + } else { + MATHB(p, MATH0, AND, PDCP_C_PLANE_SN_MASK_BE, MATH1, 8, + IFB | IMMED2); + MATHB(p, MATH1, SHLD, MATH1, MATH1, 8, 0); + + MOVE(p, DESCBUF, 8, MATH2, 0, 8, WAITCOMP | IMMED); + MATHB(p, MATH1, OR, MATH2, MATH2, 8, 0); + MOVE(p, MATH2, 0, CONTEXT2, 0, 8, IMMED); + } + if (dir == OP_TYPE_DECAP_PROTOCOL) + MATHB(p, SEQINSZ, SUB, PDCP_MAC_I_LEN, MATH1, 4, + IMMED2); + else + MATHB(p, SEQINSZ, SUB, ZERO, MATH1, 4, 0); + + MATHB(p, MATH1, SUB, ZERO, VSEQINSZ, 4, 0); + MATHB(p, MATH1, SUB, ZERO, VSEQOUTSZ, 4, 0); + SEQFIFOSTORE(p, MSG, 0, 0, VLF); + ALG_OPERATION(p, OP_ALG_ALGSEL_ZUCA, + OP_ALG_AAI_F9, + OP_ALG_AS_INITFINAL, + dir == OP_TYPE_ENCAP_PROTOCOL ? + ICV_CHECK_DISABLE : ICV_CHECK_ENABLE, + DIR_ENC); + SEQFIFOLOAD(p, MSGINSNOOP, 0, VLF | LAST1 | LAST2 | FLUSH1); + MOVE(p, AB1, 0, OFIFO, 0, MATH1, 0); + + if (dir == OP_TYPE_DECAP_PROTOCOL) + SEQFIFOLOAD(p, ICV2, 4, LAST2); + else + SEQSTORE(p, CONTEXT2, 0, 4, 0); + + break; + + default: + pr_err("%s: Invalid integrity algorithm selected: %d\n", + "pdcp_insert_cplane_int_only_op", authdata->algtype); + return -EINVAL; + } + + if (rta_sec_era < RTA_SEC_ERA_3) { + PATCH_MOVE(p, move_cmd_read_descbuf, local_offset); + PATCH_MOVE(p, move_cmd_write_descbuf, local_offset); + } + + return 0; +} + +static inline int +pdcp_insert_cplane_enc_only_op(struct program *p, + bool swap __maybe_unused, + struct alginfo *cipherdata, + struct alginfo *authdata __maybe_unused, + unsigned int dir, + unsigned char era_2_sw_hfn_ovrd __maybe_unused) +{ + /* Insert Cipher Key */ + KEY(p, KEY1, cipherdata->key_enc_flags, cipherdata->key, + cipherdata->keylen, INLINE_KEY(cipherdata)); + + if (rta_sec_era >= RTA_SEC_ERA_8) { + PROTOCOL(p, dir, OP_PCLID_LTE_PDCP_CTRL_MIXED, + (uint16_t)cipherdata->algtype << 8); + return 0; + } + + SEQLOAD(p, MATH0, 7, 1, 0); + JUMP(p, 1, LOCAL_JUMP, ALL_TRUE, CALM); + if (swap == false) + MATHB(p, MATH0, AND, PDCP_C_PLANE_SN_MASK, MATH1, 8, + IFB | IMMED2); + else + MATHB(p, MATH0, AND, PDCP_C_PLANE_SN_MASK_BE, MATH1, 8, + IFB | IMMED2); + SEQSTORE(p, MATH0, 7, 1, 0); + MATHB(p, MATH1, SHLD, MATH1, MATH1, 8, 0); + MOVE(p, DESCBUF, 8, MATH2, 0, 8, WAITCOMP | IMMED); + MATHB(p, MATH1, OR, MATH2, MATH2, 8, 0); + + switch (cipherdata->algtype) { + case PDCP_CIPHER_TYPE_SNOW: + MOVE(p, MATH2, 0, CONTEXT1, 0, 8, WAITCOMP | IMMED); + + if (rta_sec_era > RTA_SEC_ERA_2) { + MATHB(p, SEQINSZ, SUB, ZERO, VSEQINSZ, 4, 0); + } else { + MATHB(p, SEQINSZ, SUB, ONE, MATH1, 4, 0); + MATHB(p, MATH1, ADD, ONE, VSEQINSZ, 4, 0); + } + + if (dir == OP_TYPE_ENCAP_PROTOCOL) + MATHB(p, SEQINSZ, ADD, PDCP_MAC_I_LEN, VSEQOUTSZ, 4, + IMMED2); + else + MATHB(p, SEQINSZ, SUB, PDCP_MAC_I_LEN, VSEQOUTSZ, 4, + IMMED2); + SEQFIFOSTORE(p, MSG, 0, 0, VLF | CONT); + ALG_OPERATION(p, OP_ALG_ALGSEL_SNOW_F8, + OP_ALG_AAI_F8, + OP_ALG_AS_INITFINAL, ICV_CHECK_DISABLE, + dir == OP_TYPE_ENCAP_PROTOCOL ? + DIR_ENC : DIR_DEC); + break; + + case PDCP_CIPHER_TYPE_AES: + MOVE(p, MATH2, 0, CONTEXT1, 0x10, 0x10, WAITCOMP | IMMED); + + if (rta_sec_era > RTA_SEC_ERA_2) { + MATHB(p, SEQINSZ, SUB, ZERO, VSEQINSZ, 4, 0); + } else { + MATHB(p, SEQINSZ, SUB, ONE, MATH1, 4, 0); + MATHB(p, MATH1, ADD, ONE, VSEQINSZ, 4, 0); + } + + if (dir == OP_TYPE_ENCAP_PROTOCOL) + MATHB(p, SEQINSZ, ADD, PDCP_MAC_I_LEN, VSEQOUTSZ, 4, + IMMED2); + else + MATHB(p, SEQINSZ, SUB, PDCP_MAC_I_LEN, VSEQOUTSZ, 4, + IMMED2); + + SEQFIFOSTORE(p, MSG, 0, 0, VLF | CONT); + ALG_OPERATION(p, OP_ALG_ALGSEL_AES, + OP_ALG_AAI_CTR, + OP_ALG_AS_INITFINAL, + ICV_CHECK_DISABLE, + dir == OP_TYPE_ENCAP_PROTOCOL ? + DIR_ENC : DIR_DEC); + break; + + case PDCP_CIPHER_TYPE_ZUC: + if (rta_sec_era < RTA_SEC_ERA_5) { + pr_err("Invalid era for selected algorithm\n"); + return -ENOTSUP; + } + + MOVE(p, MATH2, 0, CONTEXT1, 0, 0x08, IMMED); + MOVE(p, MATH2, 0, CONTEXT1, 0x08, 0x08, WAITCOMP | IMMED); + MATHB(p, SEQINSZ, SUB, ZERO, VSEQINSZ, 4, 0); + if (dir == OP_TYPE_ENCAP_PROTOCOL) + MATHB(p, SEQINSZ, ADD, PDCP_MAC_I_LEN, VSEQOUTSZ, 4, + IMMED2); + else + MATHB(p, SEQINSZ, SUB, PDCP_MAC_I_LEN, VSEQOUTSZ, 4, + IMMED2); + + SEQFIFOSTORE(p, MSG, 0, 0, VLF | CONT); + ALG_OPERATION(p, OP_ALG_ALGSEL_ZUCE, + OP_ALG_AAI_F8, + OP_ALG_AS_INITFINAL, + ICV_CHECK_DISABLE, + dir == OP_TYPE_ENCAP_PROTOCOL ? + DIR_ENC : DIR_DEC); + break; + + default: + pr_err("%s: Invalid encrypt algorithm selected: %d\n", + "pdcp_insert_cplane_enc_only_op", cipherdata->algtype); + return -EINVAL; + } + + if (dir == OP_TYPE_ENCAP_PROTOCOL) { + SEQFIFOLOAD(p, MSG1, 0, VLF); + FIFOLOAD(p, MSG1, PDCP_NULL_INT_MAC_I_VAL, 4, + LAST1 | FLUSH1 | IMMED); + } else { + SEQFIFOLOAD(p, MSG1, 0, VLF | LAST1 | FLUSH1); + MOVE(p, OFIFO, 0, MATH1, 4, PDCP_MAC_I_LEN, WAITCOMP | IMMED); + MATHB(p, MATH1, XOR, PDCP_NULL_INT_MAC_I_VAL, NONE, 4, IMMED2); + JUMP(p, PDCP_NULL_INT_ICV_CHECK_FAILED_STATUS, + HALT_STATUS, ALL_FALSE, MATH_Z); + } + + return 0; +} + +static inline int +pdcp_insert_cplane_acc_op(struct program *p, + bool swap __maybe_unused, + struct alginfo *cipherdata, + struct alginfo *authdata, + unsigned int dir, + unsigned char era_2_hfn_ovrd __maybe_unused) +{ + /* Insert Auth Key */ + KEY(p, KEY2, authdata->key_enc_flags, authdata->key, authdata->keylen, + INLINE_KEY(authdata)); + + /* Insert Cipher Key */ + KEY(p, KEY1, cipherdata->key_enc_flags, cipherdata->key, + cipherdata->keylen, INLINE_KEY(cipherdata)); + PROTOCOL(p, dir, OP_PCLID_LTE_PDCP_CTRL, (uint16_t)cipherdata->algtype); + + return 0; +} + +static inline int +pdcp_insert_cplane_snow_aes_op(struct program *p, + bool swap __maybe_unused, + struct alginfo *cipherdata, + struct alginfo *authdata, + unsigned int dir, + unsigned char era_2_sw_hfn_ovrd) +{ + LABEL(back_to_sd_offset); + LABEL(end_desc); + LABEL(local_offset); + LABEL(jump_to_beginning); + LABEL(fifo_load_mac_i_offset); + REFERENCE(seqin_ptr_read); + REFERENCE(seqin_ptr_write); + REFERENCE(seq_out_read); + REFERENCE(jump_back_to_sd_cmd); + REFERENCE(move_mac_i_to_desc_buf); + + if (rta_sec_era >= RTA_SEC_ERA_8) { + KEY(p, KEY1, cipherdata->key_enc_flags, cipherdata->key, + cipherdata->keylen, INLINE_KEY(cipherdata)); + KEY(p, KEY2, authdata->key_enc_flags, authdata->key, + authdata->keylen, INLINE_KEY(authdata)); + + PROTOCOL(p, dir, OP_PCLID_LTE_PDCP_CTRL_MIXED, + ((uint16_t)cipherdata->algtype << 8) | + (uint16_t)authdata->algtype); + + return 0; + } + + SEQLOAD(p, MATH0, 7, 1, 0); + JUMP(p, 1, LOCAL_JUMP, ALL_TRUE, CALM); + if (swap == false) + MATHB(p, MATH0, AND, PDCP_C_PLANE_SN_MASK, MATH1, 8, + IFB | IMMED2); + else + MATHB(p, MATH0, AND, PDCP_C_PLANE_SN_MASK_BE, MATH1, 8, + IFB | IMMED2); + MATHB(p, MATH1, SHLD, MATH1, MATH1, 8, 0); + MOVE(p, DESCBUF, 4, MATH2, 0, 0x08, WAITCOMP | IMMED); + MATHB(p, MATH1, OR, MATH2, MATH2, 8, 0); + SEQSTORE(p, MATH0, 7, 1, 0); + if (dir == OP_TYPE_ENCAP_PROTOCOL) { + if (rta_sec_era > RTA_SEC_ERA_2 || + (rta_sec_era == RTA_SEC_ERA_2 && + era_2_sw_hfn_ovrd == 0)) { + SEQINPTR(p, 0, 1, RTO); + } else { + SEQINPTR(p, 0, 5, RTO); + SEQFIFOLOAD(p, SKIP, 4, 0); + } + KEY(p, KEY1, authdata->key_enc_flags, authdata->key, + authdata->keylen, INLINE_KEY(authdata)); + MOVE(p, MATH2, 0, IFIFOAB1, 0, 0x08, IMMED); + + if (rta_sec_era > RTA_SEC_ERA_2) { + MATHB(p, SEQINSZ, SUB, ZERO, VSEQINSZ, 4, 0); + MATHB(p, SEQINSZ, SUB, ZERO, MATH1, 4, 0); + MATHB(p, VSEQINSZ, ADD, PDCP_MAC_I_LEN - 1, VSEQOUTSZ, + 4, IMMED2); + } else { + MATHB(p, SEQINSZ, SUB, MATH3, VSEQINSZ, 4, 0); + MATHB(p, VSEQINSZ, ADD, PDCP_MAC_I_LEN - 1, VSEQOUTSZ, + 4, IMMED2); + /* + * Note: Although the calculations below might seem a + * little off, the logic is the following: + * + * - SEQ IN PTR RTO below needs the full length of the + * frame; in case of P4080_REV_2_HFN_OV_WORKAROUND, + * this means the length of the frame to be processed + * + 4 bytes (the HFN override flag and value). + * The length of the frame to be processed minus 1 + * byte is in the VSIL register (because + * VSIL = SIL + 3, due to 1 byte, the header being + * already written by the SEQ STORE above). So for + * calculating the length to use in RTO, I add one + * to the VSIL value in order to obtain the total + * frame length. This helps in case of P4080 which + * can have the value 0 as an operand in a MATH + * command only as SRC1 When the HFN override + * workaround is not enabled, the length of the + * frame is given by the SIL register; the + * calculation is similar to the one in the SEC 4.2 + * and SEC 5.3 cases. + */ + if (era_2_sw_hfn_ovrd) + MATHB(p, VSEQOUTSZ, ADD, ONE, MATH1, 4, + 0); + else + MATHB(p, SEQINSZ, ADD, MATH3, MATH1, 4, + 0); + } + /* + * Placeholder for filling the length in + * SEQIN PTR RTO below + */ + seqin_ptr_read = MOVE(p, DESCBUF, 0, MATH1, 0, 6, IMMED); + seqin_ptr_write = MOVE(p, MATH1, 0, DESCBUF, 0, 8, + WAITCOMP | IMMED); + ALG_OPERATION(p, OP_ALG_ALGSEL_AES, + OP_ALG_AAI_CMAC, + OP_ALG_AS_INITFINAL, + ICV_CHECK_DISABLE, + DIR_DEC); + SEQFIFOLOAD(p, MSG1, 0, VLF | LAST1 | FLUSH1); + MOVE(p, CONTEXT1, 0, MATH3, 0, 4, WAITCOMP | IMMED); + if (rta_sec_era <= RTA_SEC_ERA_3) + LOAD(p, CLRW_CLR_C1KEY | + CLRW_CLR_C1CTX | + CLRW_CLR_C1ICV | + CLRW_CLR_C1DATAS | + CLRW_CLR_C1MODE, + CLRW, 0, 4, IMMED); + else + LOAD(p, CLRW_RESET_CLS1_CHA | + CLRW_CLR_C1KEY | + CLRW_CLR_C1CTX | + CLRW_CLR_C1ICV | + CLRW_CLR_C1DATAS | + CLRW_CLR_C1MODE, + CLRW, 0, 4, IMMED); + + if (rta_sec_era <= RTA_SEC_ERA_3) + LOAD(p, CCTRL_RESET_CHA_ALL, CCTRL, 0, 4, IMMED); + + KEY(p, KEY1, cipherdata->key_enc_flags, cipherdata->key, + cipherdata->keylen, INLINE_KEY(cipherdata)); + SET_LABEL(p, local_offset); + MOVE(p, MATH2, 0, CONTEXT1, 0, 8, IMMED); + SEQINPTR(p, 0, 0, RTO); + + if (rta_sec_era == RTA_SEC_ERA_2 && era_2_sw_hfn_ovrd) { + SEQFIFOLOAD(p, SKIP, 5, 0); + MATHB(p, SEQINSZ, ADD, ONE, SEQINSZ, 4, 0); + } + + MATHB(p, SEQINSZ, SUB, ONE, VSEQINSZ, 4, 0); + ALG_OPERATION(p, OP_ALG_ALGSEL_SNOW_F8, + OP_ALG_AAI_F8, + OP_ALG_AS_INITFINAL, + ICV_CHECK_DISABLE, + DIR_ENC); + SEQFIFOSTORE(p, MSG, 0, 0, VLF); + + if (rta_sec_era > RTA_SEC_ERA_2 || + (rta_sec_era == RTA_SEC_ERA_2 && + era_2_sw_hfn_ovrd == 0)) + SEQFIFOLOAD(p, SKIP, 1, 0); + + SEQFIFOLOAD(p, MSG1, 0, VLF); + MOVE(p, MATH3, 0, IFIFOAB1, 0, 4, LAST1 | FLUSH1 | IMMED); + PATCH_MOVE(p, seqin_ptr_read, local_offset); + PATCH_MOVE(p, seqin_ptr_write, local_offset); + } else { + MOVE(p, MATH2, 0, CONTEXT1, 0, 8, IMMED); + + if (rta_sec_era >= RTA_SEC_ERA_5) + MOVE(p, CONTEXT1, 0, CONTEXT2, 0, 8, IMMED); + + if (rta_sec_era > RTA_SEC_ERA_2) + MATHB(p, SEQINSZ, SUB, ZERO, VSEQINSZ, 4, 0); + else + MATHB(p, SEQINSZ, SUB, MATH3, VSEQINSZ, 4, 0); + + MATHB(p, SEQINSZ, SUB, PDCP_MAC_I_LEN, VSEQOUTSZ, 4, IMMED2); +/* + * TODO: To be changed when proper support is added in RTA (can't load a + * command that is also written by RTA (or patch it for that matter). + * Change when proper RTA support is added. + */ + if (p->ps) + WORD(p, 0x168B0004); + else + WORD(p, 0x16880404); + + jump_back_to_sd_cmd = JUMP(p, 0, LOCAL_JUMP, ALL_TRUE, 0); + /* + * Placeholder for command reading the SEQ OUT command in + * JD. Done for rereading the decrypted data and performing + * the integrity check + */ +/* + * TODO: RTA currently doesn't support patching of length of a MOVE command + * Thus, it is inserted as a raw word, as per PS setting. + */ + if (p->ps) + seq_out_read = MOVE(p, DESCBUF, 0, MATH1, 0, 20, + WAITCOMP | IMMED); + else + seq_out_read = MOVE(p, DESCBUF, 0, MATH1, 0, 16, + WAITCOMP | IMMED); + + MATHB(p, MATH1, XOR, CMD_SEQ_IN_PTR ^ CMD_SEQ_OUT_PTR, MATH1, 4, + IMMED2); + /* Placeholder for overwriting the SEQ IN with SEQ OUT */ +/* + * TODO: RTA currently doesn't support patching of length of a MOVE command + * Thus, it is inserted as a raw word, as per PS setting. + */ + if (p->ps) + MOVE(p, MATH1, 0, DESCBUF, 0, 24, IMMED); + else + MOVE(p, MATH1, 0, DESCBUF, 0, 20, IMMED); + + KEY(p, KEY1, cipherdata->key_enc_flags, cipherdata->key, + cipherdata->keylen, INLINE_KEY(cipherdata)); + + if (rta_sec_era >= RTA_SEC_ERA_4) + MOVE(p, CONTEXT1, 0, CONTEXT2, 0, 8, IMMED); + else + MOVE(p, CONTEXT1, 0, MATH3, 0, 8, IMMED); + + ALG_OPERATION(p, OP_ALG_ALGSEL_SNOW_F8, + OP_ALG_AAI_F8, + OP_ALG_AS_INITFINAL, + ICV_CHECK_DISABLE, + DIR_DEC); + SEQFIFOSTORE(p, MSG, 0, 0, VLF | CONT); + SEQFIFOLOAD(p, MSG1, 0, VLF | LAST1 | FLUSH1); + + if (rta_sec_era <= RTA_SEC_ERA_3) + move_mac_i_to_desc_buf = MOVE(p, OFIFO, 0, DESCBUF, 0, + 4, WAITCOMP | IMMED); + else + MOVE(p, OFIFO, 0, MATH3, 0, 4, IMMED); + + if (rta_sec_era <= RTA_SEC_ERA_3) + LOAD(p, CCTRL_RESET_CHA_ALL, CCTRL, 0, 4, IMMED); + else + LOAD(p, CLRW_RESET_CLS1_CHA | + CLRW_CLR_C1KEY | + CLRW_CLR_C1CTX | + CLRW_CLR_C1ICV | + CLRW_CLR_C1DATAS | + CLRW_CLR_C1MODE, + CLRW, 0, 4, IMMED); + + KEY(p, KEY1, authdata->key_enc_flags, authdata->key, + authdata->keylen, INLINE_KEY(authdata)); + /* + * Placeholder for jump in SD for executing the new SEQ IN PTR + * command (which is actually the old SEQ OUT PTR command + * copied over from JD. + */ + SET_LABEL(p, jump_to_beginning); + JUMP(p, 1 - jump_to_beginning, LOCAL_JUMP, ALL_TRUE, 0); + SET_LABEL(p, back_to_sd_offset); + ALG_OPERATION(p, OP_ALG_ALGSEL_AES, + OP_ALG_AAI_CMAC, + OP_ALG_AS_INITFINAL, + ICV_CHECK_ENABLE, + DIR_DEC); + + /* Read the # of bytes written in the output buffer + 1 (HDR) */ + MATHB(p, VSEQOUTSZ, ADD, ONE, VSEQINSZ, 4, 0); + + if (rta_sec_era <= RTA_SEC_ERA_3) + MOVE(p, MATH3, 0, IFIFOAB1, 0, 8, IMMED); + else + MOVE(p, CONTEXT2, 0, IFIFOAB1, 0, 8, IMMED); + + if (rta_sec_era == RTA_SEC_ERA_2 && era_2_sw_hfn_ovrd) + SEQFIFOLOAD(p, SKIP, 4, 0); + + SEQFIFOLOAD(p, MSG1, 0, VLF | LAST1 | FLUSH1); + + if (rta_sec_era >= RTA_SEC_ERA_4) { + LOAD(p, NFIFOENTRY_STYPE_ALTSOURCE | + NFIFOENTRY_DEST_CLASS1 | + NFIFOENTRY_DTYPE_ICV | + NFIFOENTRY_LC1 | + NFIFOENTRY_FC1 | 4, NFIFO_SZL, 0, 4, IMMED); + MOVE(p, MATH3, 0, ALTSOURCE, 0, 4, IMMED); + } else { + SET_LABEL(p, fifo_load_mac_i_offset); + FIFOLOAD(p, ICV1, fifo_load_mac_i_offset, 4, + LAST1 | FLUSH1 | IMMED); + } + + SET_LABEL(p, end_desc); + + if (!p->ps) { + PATCH_MOVE(p, seq_out_read, end_desc + 1); + PATCH_JUMP(p, jump_back_to_sd_cmd, + back_to_sd_offset + jump_back_to_sd_cmd - 5); + + if (rta_sec_era <= RTA_SEC_ERA_3) + PATCH_MOVE(p, move_mac_i_to_desc_buf, + fifo_load_mac_i_offset + 1); + } else { + PATCH_MOVE(p, seq_out_read, end_desc + 2); + PATCH_JUMP(p, jump_back_to_sd_cmd, + back_to_sd_offset + jump_back_to_sd_cmd - 5); + + if (rta_sec_era <= RTA_SEC_ERA_3) + PATCH_MOVE(p, move_mac_i_to_desc_buf, + fifo_load_mac_i_offset + 1); + } + } + + return 0; +} + +static inline int +pdcp_insert_cplane_aes_snow_op(struct program *p, + bool swap __maybe_unused, + struct alginfo *cipherdata, + struct alginfo *authdata, + unsigned int dir, + unsigned char era_2_sw_hfn_ovrd __maybe_unused) +{ + KEY(p, KEY1, cipherdata->key_enc_flags, cipherdata->key, + cipherdata->keylen, INLINE_KEY(cipherdata)); + KEY(p, KEY2, authdata->key_enc_flags, authdata->key, authdata->keylen, + INLINE_KEY(authdata)); + + if (rta_sec_era >= RTA_SEC_ERA_8) { + PROTOCOL(p, dir, OP_PCLID_LTE_PDCP_CTRL_MIXED, + ((uint16_t)cipherdata->algtype << 8) | + (uint16_t)authdata->algtype); + + return 0; + } + + if (dir == OP_TYPE_ENCAP_PROTOCOL) + MATHB(p, SEQINSZ, SUB, ONE, VSEQINSZ, 4, 0); + + SEQLOAD(p, MATH0, 7, 1, 0); + JUMP(p, 1, LOCAL_JUMP, ALL_TRUE, CALM); + MOVE(p, MATH0, 7, IFIFOAB2, 0, 1, IMMED); + if (swap == false) + MATHB(p, MATH0, AND, PDCP_C_PLANE_SN_MASK, MATH1, 8, + IFB | IMMED2); + else + MATHB(p, MATH0, AND, PDCP_C_PLANE_SN_MASK_BE, MATH1, 8, + IFB | IMMED2); + + SEQSTORE(p, MATH0, 7, 1, 0); + MATHB(p, MATH1, SHLD, MATH1, MATH1, 8, 0); + MOVE(p, DESCBUF, 4, MATH2, 0, 8, WAITCOMP | IMMED); + MATHB(p, MATH1, OR, MATH2, MATH1, 8, 0); + MOVE(p, MATH1, 0, CONTEXT1, 16, 8, IMMED); + MOVE(p, MATH1, 0, CONTEXT2, 0, 4, IMMED); + if (swap == false) { + MATHB(p, MATH1, AND, lower_32_bits(PDCP_BEARER_MASK), MATH2, 4, + IMMED2); + MATHB(p, MATH1, AND, upper_32_bits(PDCP_DIR_MASK), MATH3, 4, + IMMED2); + } else { + MATHB(p, MATH1, AND, lower_32_bits(PDCP_BEARER_MASK_BE), MATH2, + 4, IMMED2); + MATHB(p, MATH1, AND, upper_32_bits(PDCP_DIR_MASK_BE), MATH3, + 4, IMMED2); + } + MATHB(p, MATH3, SHLD, MATH3, MATH3, 8, 0); + MOVE(p, MATH2, 4, OFIFO, 0, 12, IMMED); + MOVE(p, OFIFO, 0, CONTEXT2, 4, 12, IMMED); + if (dir == OP_TYPE_ENCAP_PROTOCOL) { + MATHB(p, SEQINSZ, ADD, PDCP_MAC_I_LEN, VSEQOUTSZ, 4, IMMED2); + } else { + MATHB(p, SEQINSZ, SUB, PDCP_MAC_I_LEN, MATH1, 4, IMMED2); + + MATHB(p, ZERO, ADD, MATH1, VSEQOUTSZ, 4, 0); + MATHB(p, ZERO, ADD, MATH1, VSEQINSZ, 4, 0); + } + + if (dir == OP_TYPE_ENCAP_PROTOCOL) + SEQFIFOSTORE(p, MSG, 0, 0, VLF); + else + SEQFIFOSTORE(p, MSG, 0, 0, VLF | CONT); + + ALG_OPERATION(p, OP_ALG_ALGSEL_SNOW_F9, + OP_ALG_AAI_F9, + OP_ALG_AS_INITFINAL, + dir == OP_TYPE_ENCAP_PROTOCOL ? + ICV_CHECK_DISABLE : ICV_CHECK_ENABLE, + DIR_DEC); + ALG_OPERATION(p, OP_ALG_ALGSEL_AES, + OP_ALG_AAI_CTR, + OP_ALG_AS_INITFINAL, + ICV_CHECK_DISABLE, + dir == OP_TYPE_ENCAP_PROTOCOL ? DIR_ENC : DIR_DEC); + + if (dir == OP_TYPE_ENCAP_PROTOCOL) { + SEQFIFOLOAD(p, MSGINSNOOP, 0, VLF | LAST2); + MOVE(p, CONTEXT2, 0, IFIFOAB1, 0, 4, LAST1 | FLUSH1 | IMMED); + } else { + SEQFIFOLOAD(p, MSGOUTSNOOP, 0, VLF | LAST2); + SEQFIFOLOAD(p, MSG1, 4, LAST1 | FLUSH1); + JUMP(p, 1, LOCAL_JUMP, ALL_TRUE, CLASS1 | NOP | NIFP); + + if (rta_sec_era >= RTA_SEC_ERA_6) + LOAD(p, 0, DCTRL, 0, LDLEN_RST_CHA_OFIFO_PTR, IMMED); + + MOVE(p, OFIFO, 0, MATH0, 0, 4, WAITCOMP | IMMED); + + NFIFOADD(p, IFIFO, ICV2, 4, LAST2); + + if (rta_sec_era <= RTA_SEC_ERA_2) { + /* Shut off automatic Info FIFO entries */ + LOAD(p, 0, DCTRL, LDOFF_DISABLE_AUTO_NFIFO, 0, IMMED); + MOVE(p, MATH0, 0, IFIFOAB2, 0, 4, WAITCOMP | IMMED); + } else { + MOVE(p, MATH0, 0, IFIFO, 0, 4, WAITCOMP | IMMED); + } + } + + return 0; +} + +static inline int +pdcp_insert_cplane_snow_zuc_op(struct program *p, + bool swap __maybe_unused, + struct alginfo *cipherdata, + struct alginfo *authdata, + unsigned int dir, + unsigned char era_2_sw_hfn_ovrd __maybe_unused) +{ + LABEL(keyjump); + REFERENCE(pkeyjump); + + if (rta_sec_era < RTA_SEC_ERA_5) { + pr_err("Invalid era for selected algorithm\n"); + return -ENOTSUP; + } + + pkeyjump = JUMP(p, keyjump, LOCAL_JUMP, ALL_TRUE, SHRD | SELF | BOTH); + KEY(p, KEY1, cipherdata->key_enc_flags, cipherdata->key, + cipherdata->keylen, INLINE_KEY(cipherdata)); + KEY(p, KEY2, authdata->key_enc_flags, authdata->key, authdata->keylen, + INLINE_KEY(authdata)); + + SET_LABEL(p, keyjump); + + if (rta_sec_era >= RTA_SEC_ERA_8) { + PROTOCOL(p, dir, OP_PCLID_LTE_PDCP_CTRL_MIXED, + ((uint16_t)cipherdata->algtype << 8) | + (uint16_t)authdata->algtype); + return 0; + } + + SEQLOAD(p, MATH0, 7, 1, 0); + JUMP(p, 1, LOCAL_JUMP, ALL_TRUE, CALM); + MOVE(p, MATH0, 7, IFIFOAB2, 0, 1, IMMED); + if (swap == false) + MATHB(p, MATH0, AND, PDCP_C_PLANE_SN_MASK, MATH1, 8, + IFB | IMMED2); + else + MATHB(p, MATH0, AND, PDCP_C_PLANE_SN_MASK, MATH1, 8, + IFB | IMMED2); + + MATHB(p, MATH1, SHLD, MATH1, MATH1, 8, 0); + MOVE(p, DESCBUF, 4, MATH2, 0, 8, WAITCOMP | IMMED); + MATHB(p, MATH1, OR, MATH2, MATH2, 8, 0); + MOVE(p, MATH2, 0, CONTEXT1, 0, 8, IMMED); + MOVE(p, MATH2, 0, CONTEXT2, 0, 8, WAITCOMP | IMMED); + + if (dir == OP_TYPE_ENCAP_PROTOCOL) + MATHB(p, SEQINSZ, ADD, PDCP_MAC_I_LEN, VSEQOUTSZ, 4, IMMED2); + else + MATHB(p, SEQINSZ, SUB, PDCP_MAC_I_LEN, VSEQOUTSZ, 4, IMMED2); + + MATHB(p, SEQINSZ, SUB, ZERO, VSEQINSZ, 4, 0); + SEQSTORE(p, MATH0, 7, 1, 0); + + if (dir == OP_TYPE_ENCAP_PROTOCOL) { + SEQFIFOSTORE(p, MSG, 0, 0, VLF); + SEQFIFOLOAD(p, MSGINSNOOP, 0, VLF | LAST2); + } else { + SEQFIFOSTORE(p, MSG, 0, 0, VLF | CONT); + SEQFIFOLOAD(p, MSGOUTSNOOP, 0, VLF | LAST1 | FLUSH1); + } + + ALG_OPERATION(p, OP_ALG_ALGSEL_ZUCA, + OP_ALG_AAI_F9, + OP_ALG_AS_INITFINAL, + dir == OP_TYPE_ENCAP_PROTOCOL ? + ICV_CHECK_DISABLE : ICV_CHECK_ENABLE, + DIR_ENC); + + ALG_OPERATION(p, OP_ALG_ALGSEL_SNOW_F8, + OP_ALG_AAI_F8, + OP_ALG_AS_INITFINAL, + ICV_CHECK_DISABLE, + dir == OP_TYPE_ENCAP_PROTOCOL ? DIR_ENC : DIR_DEC); + if (dir == OP_TYPE_ENCAP_PROTOCOL) { + MOVE(p, CONTEXT2, 0, IFIFOAB1, 0, 4, LAST1 | FLUSH1 | IMMED); + } else { + /* Save ICV */ + MOVE(p, OFIFO, 0, MATH0, 0, 4, IMMED); + LOAD(p, NFIFOENTRY_STYPE_ALTSOURCE | + NFIFOENTRY_DEST_CLASS2 | + NFIFOENTRY_DTYPE_ICV | + NFIFOENTRY_LC2 | 4, NFIFO_SZL, 0, 4, IMMED); + MOVE(p, MATH0, 0, ALTSOURCE, 0, 4, WAITCOMP | IMMED); + } + + /* Reset ZUCA mode and done interrupt */ + LOAD(p, CLRW_CLR_C2MODE, CLRW, 0, 4, IMMED); + LOAD(p, CIRQ_ZADI, ICTRL, 0, 4, IMMED); + + PATCH_JUMP(p, pkeyjump, keyjump); + return 0; +} + +static inline int +pdcp_insert_cplane_aes_zuc_op(struct program *p, + bool swap __maybe_unused, + struct alginfo *cipherdata, + struct alginfo *authdata, + unsigned int dir, + unsigned char era_2_sw_hfn_ovrd __maybe_unused) +{ + LABEL(keyjump); + REFERENCE(pkeyjump); + + if (rta_sec_era < RTA_SEC_ERA_5) { + pr_err("Invalid era for selected algorithm\n"); + return -ENOTSUP; + } + + pkeyjump = JUMP(p, keyjump, LOCAL_JUMP, ALL_TRUE, SHRD | SELF | BOTH); + KEY(p, KEY1, cipherdata->key_enc_flags, cipherdata->key, + cipherdata->keylen, INLINE_KEY(cipherdata)); + KEY(p, KEY2, authdata->key_enc_flags, authdata->key, authdata->keylen, + INLINE_KEY(authdata)); + + if (rta_sec_era >= RTA_SEC_ERA_8) { + PROTOCOL(p, dir, OP_PCLID_LTE_PDCP_CTRL_MIXED, + ((uint16_t)cipherdata->algtype << 8) | + (uint16_t)authdata->algtype); + + return 0; + } + + SET_LABEL(p, keyjump); + SEQLOAD(p, MATH0, 7, 1, 0); + JUMP(p, 1, LOCAL_JUMP, ALL_TRUE, CALM); + MOVE(p, MATH0, 7, IFIFOAB2, 0, 1, IMMED); + if (swap == false) + MATHB(p, MATH0, AND, PDCP_C_PLANE_SN_MASK, MATH1, 8, + IFB | IMMED2); + else + MATHB(p, MATH0, AND, PDCP_C_PLANE_SN_MASK, MATH1, 8, + IFB | IMMED2); + + MATHB(p, MATH1, SHLD, MATH1, MATH1, 8, 0); + MOVE(p, DESCBUF, 4, MATH2, 0, 8, WAITCOMP | IMMED); + MATHB(p, MATH1, OR, MATH2, MATH2, 8, 0); + MOVE(p, MATH2, 0, CONTEXT1, 16, 8, IMMED); + MOVE(p, MATH2, 0, CONTEXT2, 0, 8, WAITCOMP | IMMED); + + if (dir == OP_TYPE_ENCAP_PROTOCOL) + MATHB(p, SEQINSZ, ADD, PDCP_MAC_I_LEN, VSEQOUTSZ, 4, IMMED2); + else + MATHB(p, SEQINSZ, SUB, PDCP_MAC_I_LEN, VSEQOUTSZ, 4, IMMED2); + + MATHB(p, SEQINSZ, SUB, ZERO, VSEQINSZ, 4, 0); + SEQSTORE(p, MATH0, 7, 1, 0); + + if (dir == OP_TYPE_ENCAP_PROTOCOL) { + SEQFIFOSTORE(p, MSG, 0, 0, VLF); + SEQFIFOLOAD(p, MSGINSNOOP, 0, VLF | LAST2); + } else { + SEQFIFOSTORE(p, MSG, 0, 0, VLF | CONT); + SEQFIFOLOAD(p, MSGOUTSNOOP, 0, VLF | LAST1 | FLUSH1); + } + + ALG_OPERATION(p, OP_ALG_ALGSEL_ZUCA, + OP_ALG_AAI_F9, + OP_ALG_AS_INITFINAL, + dir == OP_TYPE_ENCAP_PROTOCOL ? + ICV_CHECK_DISABLE : ICV_CHECK_ENABLE, + DIR_ENC); + + ALG_OPERATION(p, OP_ALG_ALGSEL_AES, + OP_ALG_AAI_CTR, + OP_ALG_AS_INITFINAL, + ICV_CHECK_DISABLE, + dir == OP_TYPE_ENCAP_PROTOCOL ? DIR_ENC : DIR_DEC); + + if (dir == OP_TYPE_ENCAP_PROTOCOL) { + MOVE(p, CONTEXT2, 0, IFIFOAB1, 0, 4, LAST1 | FLUSH1 | IMMED); + } else { + /* Save ICV */ + MOVE(p, OFIFO, 0, MATH0, 0, 4, IMMED); + + LOAD(p, NFIFOENTRY_STYPE_ALTSOURCE | + NFIFOENTRY_DEST_CLASS2 | + NFIFOENTRY_DTYPE_ICV | + NFIFOENTRY_LC2 | 4, NFIFO_SZL, 0, 4, IMMED); + MOVE(p, MATH0, 0, ALTSOURCE, 0, 4, WAITCOMP | IMMED); + } + + /* Reset ZUCA mode and done interrupt */ + LOAD(p, CLRW_CLR_C2MODE, CLRW, 0, 4, IMMED); + LOAD(p, CIRQ_ZADI, ICTRL, 0, 4, IMMED); + + PATCH_JUMP(p, pkeyjump, keyjump); + + return 0; +} + +static inline int +pdcp_insert_cplane_zuc_snow_op(struct program *p, + bool swap __maybe_unused, + struct alginfo *cipherdata, + struct alginfo *authdata, + unsigned int dir, + unsigned char era_2_sw_hfn_ovrd __maybe_unused) +{ + LABEL(keyjump); + REFERENCE(pkeyjump); + + if (rta_sec_era < RTA_SEC_ERA_5) { + pr_err("Invalid era for selected algorithm\n"); + return -ENOTSUP; + } + + pkeyjump = JUMP(p, keyjump, LOCAL_JUMP, ALL_TRUE, SHRD | SELF | BOTH); + KEY(p, KEY1, cipherdata->key_enc_flags, cipherdata->key, + cipherdata->keylen, INLINE_KEY(cipherdata)); + KEY(p, KEY2, authdata->key_enc_flags, authdata->key, authdata->keylen, + INLINE_KEY(authdata)); + + if (rta_sec_era >= RTA_SEC_ERA_8) { + PROTOCOL(p, dir, OP_PCLID_LTE_PDCP_CTRL_MIXED, + ((uint16_t)cipherdata->algtype << 8) | + (uint16_t)authdata->algtype); + + return 0; + } + + SET_LABEL(p, keyjump); + SEQLOAD(p, MATH0, 7, 1, 0); + JUMP(p, 1, LOCAL_JUMP, ALL_TRUE, CALM); + MOVE(p, MATH0, 7, IFIFOAB2, 0, 1, IMMED); + if (swap == false) + MATHB(p, MATH0, AND, PDCP_C_PLANE_SN_MASK, MATH1, 8, + IFB | IMMED2); + else + MATHB(p, MATH0, AND, PDCP_C_PLANE_SN_MASK, MATH1, 8, + IFB | IMMED2); + + MATHB(p, MATH1, SHLD, MATH1, MATH1, 8, 0); + MOVE(p, DESCBUF, 4, MATH2, 0, 8, WAITCOMP | IMMED); + MATHB(p, MATH1, OR, MATH2, MATH1, 8, 0); + MOVE(p, MATH1, 0, CONTEXT1, 0, 8, IMMED); + MOVE(p, MATH1, 0, CONTEXT2, 0, 4, IMMED); + if (swap == false) { + MATHB(p, MATH1, AND, lower_32_bits(PDCP_BEARER_MASK), MATH2, + 4, IMMED2); + MATHB(p, MATH1, AND, upper_32_bits(PDCP_DIR_MASK), MATH3, + 4, IMMED2); + } else { + MATHB(p, MATH1, AND, lower_32_bits(PDCP_BEARER_MASK_BE), MATH2, + 4, IMMED2); + MATHB(p, MATH1, AND, upper_32_bits(PDCP_DIR_MASK_BE), MATH3, + 4, IMMED2); + } + MATHB(p, MATH3, SHLD, MATH3, MATH3, 8, 0); + MOVE(p, MATH2, 4, OFIFO, 0, 12, IMMED); + MOVE(p, OFIFO, 0, CONTEXT2, 4, 12, IMMED); + + if (dir == OP_TYPE_ENCAP_PROTOCOL) { + MATHB(p, SEQINSZ, ADD, PDCP_MAC_I_LEN, VSEQOUTSZ, 4, IMMED2); + MATHB(p, SEQINSZ, SUB, ZERO, VSEQINSZ, 4, 0); + } else { + MATHB(p, SEQINSZ, SUB, PDCP_MAC_I_LEN, VSEQOUTSZ, 4, IMMED2); + MATHB(p, VSEQOUTSZ, SUB, ZERO, VSEQINSZ, 4, 0); + } + + SEQSTORE(p, MATH0, 7, 1, 0); + + if (dir == OP_TYPE_ENCAP_PROTOCOL) { + SEQFIFOSTORE(p, MSG, 0, 0, VLF); + SEQFIFOLOAD(p, MSGINSNOOP, 0, VLF | LAST2); + } else { + SEQFIFOSTORE(p, MSG, 0, 0, VLF | CONT); + SEQFIFOLOAD(p, MSGOUTSNOOP, 0, VLF | LAST2); + } + + ALG_OPERATION(p, OP_ALG_ALGSEL_SNOW_F9, + OP_ALG_AAI_F9, + OP_ALG_AS_INITFINAL, + dir == OP_TYPE_ENCAP_PROTOCOL ? + ICV_CHECK_DISABLE : ICV_CHECK_ENABLE, + DIR_DEC); + + ALG_OPERATION(p, OP_ALG_ALGSEL_ZUCE, + OP_ALG_AAI_F8, + OP_ALG_AS_INITFINAL, + ICV_CHECK_DISABLE, + dir == OP_TYPE_ENCAP_PROTOCOL ? DIR_ENC : DIR_DEC); + + if (dir == OP_TYPE_ENCAP_PROTOCOL) { + MOVE(p, CONTEXT2, 0, IFIFOAB1, 0, 4, LAST1 | FLUSH1 | IMMED); + } else { + SEQFIFOLOAD(p, MSG1, 4, LAST1 | FLUSH1); + JUMP(p, 1, LOCAL_JUMP, ALL_TRUE, CLASS1 | NOP | NIFP); + + if (rta_sec_era >= RTA_SEC_ERA_6) + /* + * For SEC ERA 6, there's a problem with the OFIFO + * pointer, and thus it needs to be reset here before + * moving to M0. + */ + LOAD(p, 0, DCTRL, 0, LDLEN_RST_CHA_OFIFO_PTR, IMMED); + + /* Put ICV to M0 before sending it to C2 for comparison. */ + MOVE(p, OFIFO, 0, MATH0, 0, 4, WAITCOMP | IMMED); + + LOAD(p, NFIFOENTRY_STYPE_ALTSOURCE | + NFIFOENTRY_DEST_CLASS2 | + NFIFOENTRY_DTYPE_ICV | + NFIFOENTRY_LC2 | 4, NFIFO_SZL, 0, 4, IMMED); + MOVE(p, MATH0, 0, ALTSOURCE, 0, 4, IMMED); + } + + PATCH_JUMP(p, pkeyjump, keyjump); + return 0; +} + +static inline int +pdcp_insert_cplane_zuc_aes_op(struct program *p, + bool swap __maybe_unused, + struct alginfo *cipherdata, + struct alginfo *authdata, + unsigned int dir, + unsigned char era_2_sw_hfn_ovrd __maybe_unused) +{ + if (rta_sec_era < RTA_SEC_ERA_5) { + pr_err("Invalid era for selected algorithm\n"); + return -ENOTSUP; + } + + if (rta_sec_era >= RTA_SEC_ERA_8) { + KEY(p, KEY1, cipherdata->key_enc_flags, cipherdata->key, + cipherdata->keylen, INLINE_KEY(cipherdata)); + KEY(p, KEY2, authdata->key_enc_flags, authdata->key, + authdata->keylen, INLINE_KEY(authdata)); + + PROTOCOL(p, dir, OP_PCLID_LTE_PDCP_CTRL_MIXED, + ((uint16_t)cipherdata->algtype << 8) | + (uint16_t)authdata->algtype); + return 0; + } + + SEQLOAD(p, MATH0, 7, 1, 0); + JUMP(p, 1, LOCAL_JUMP, ALL_TRUE, CALM); + if (swap == false) + MATHB(p, MATH0, AND, PDCP_C_PLANE_SN_MASK, MATH1, 8, + IFB | IMMED2); + else + MATHB(p, MATH0, AND, PDCP_C_PLANE_SN_MASK, MATH1, 8, + IFB | IMMED2); + + MATHB(p, MATH1, SHLD, MATH1, MATH1, 8, 0); + MOVE(p, DESCBUF, 4, MATH2, 0, 0x08, WAITCOMP | IMMED); + MATHB(p, MATH1, OR, MATH2, MATH2, 8, 0); + SEQSTORE(p, MATH0, 7, 1, 0); + if (dir == OP_TYPE_ENCAP_PROTOCOL) { + KEY(p, KEY1, authdata->key_enc_flags, authdata->key, + authdata->keylen, INLINE_KEY(authdata)); + MOVE(p, MATH2, 0, IFIFOAB1, 0, 0x08, IMMED); + MOVE(p, MATH0, 7, IFIFOAB1, 0, 1, IMMED); + + MATHB(p, SEQINSZ, SUB, ZERO, VSEQINSZ, 4, 0); + MATHB(p, VSEQINSZ, ADD, PDCP_MAC_I_LEN, VSEQOUTSZ, 4, IMMED2); + + ALG_OPERATION(p, OP_ALG_ALGSEL_AES, + OP_ALG_AAI_CMAC, + OP_ALG_AS_INITFINAL, + ICV_CHECK_DISABLE, + DIR_DEC); + SEQFIFOLOAD(p, MSG1, 0, VLF | LAST1 | FLUSH1); + MOVE(p, CONTEXT1, 0, MATH3, 0, 4, WAITCOMP | IMMED); + LOAD(p, CLRW_RESET_CLS1_CHA | + CLRW_CLR_C1KEY | + CLRW_CLR_C1CTX | + CLRW_CLR_C1ICV | + CLRW_CLR_C1DATAS | + CLRW_CLR_C1MODE, + CLRW, 0, 4, IMMED); + + KEY(p, KEY1, cipherdata->key_enc_flags, cipherdata->key, + cipherdata->keylen, INLINE_KEY(cipherdata)); + + MOVE(p, MATH2, 0, CONTEXT1, 0, 8, IMMED); + SEQINPTR(p, 0, PDCP_NULL_MAX_FRAME_LEN, RTO); + + ALG_OPERATION(p, OP_ALG_ALGSEL_ZUCE, + OP_ALG_AAI_F8, + OP_ALG_AS_INITFINAL, + ICV_CHECK_DISABLE, + DIR_ENC); + SEQFIFOSTORE(p, MSG, 0, 0, VLF); + + SEQFIFOLOAD(p, SKIP, 1, 0); + + SEQFIFOLOAD(p, MSG1, 0, VLF); + MOVE(p, MATH3, 0, IFIFOAB1, 0, 4, LAST1 | FLUSH1 | IMMED); + } else { + MOVE(p, MATH2, 0, CONTEXT1, 0, 8, IMMED); + + MOVE(p, CONTEXT1, 0, CONTEXT2, 0, 8, IMMED); + + MATHB(p, SEQINSZ, SUB, ZERO, VSEQINSZ, 4, 0); + + MATHB(p, SEQINSZ, SUB, PDCP_MAC_I_LEN, VSEQOUTSZ, 4, IMMED2); + + KEY(p, KEY1, cipherdata->key_enc_flags, cipherdata->key, + cipherdata->keylen, INLINE_KEY(cipherdata)); + + MOVE(p, CONTEXT1, 0, CONTEXT2, 0, 8, IMMED); + + ALG_OPERATION(p, OP_ALG_ALGSEL_ZUCE, + OP_ALG_AAI_F8, + OP_ALG_AS_INITFINAL, + ICV_CHECK_DISABLE, + DIR_DEC); + SEQFIFOSTORE(p, MSG, 0, 0, VLF | CONT); + SEQFIFOLOAD(p, MSG1, 0, VLF | LAST1 | FLUSH1); + + MOVE(p, OFIFO, 0, MATH3, 0, 4, IMMED); + + LOAD(p, CLRW_RESET_CLS1_CHA | + CLRW_CLR_C1KEY | + CLRW_CLR_C1CTX | + CLRW_CLR_C1ICV | + CLRW_CLR_C1DATAS | + CLRW_CLR_C1MODE, + CLRW, 0, 4, IMMED); + + KEY(p, KEY1, authdata->key_enc_flags, authdata->key, + authdata->keylen, INLINE_KEY(authdata)); + + SEQINPTR(p, 0, 0, SOP); + + ALG_OPERATION(p, OP_ALG_ALGSEL_AES, + OP_ALG_AAI_CMAC, + OP_ALG_AS_INITFINAL, + ICV_CHECK_ENABLE, + DIR_DEC); + + MATHB(p, SEQINSZ, SUB, ZERO, VSEQINSZ, 4, 0); + + MOVE(p, CONTEXT2, 0, IFIFOAB1, 0, 8, IMMED); + + SEQFIFOLOAD(p, MSG1, 0, VLF | LAST1 | FLUSH1); + + LOAD(p, NFIFOENTRY_STYPE_ALTSOURCE | + NFIFOENTRY_DEST_CLASS1 | + NFIFOENTRY_DTYPE_ICV | + NFIFOENTRY_LC1 | + NFIFOENTRY_FC1 | 4, NFIFO_SZL, 0, 4, IMMED); + MOVE(p, MATH3, 0, ALTSOURCE, 0, 4, IMMED); + } + + return 0; +} + +static inline int +pdcp_insert_uplane_15bit_op(struct program *p, + bool swap __maybe_unused, + struct alginfo *cipherdata, + unsigned int dir) +{ + int op; + /* Insert Cipher Key */ + KEY(p, KEY1, cipherdata->key_enc_flags, cipherdata->key, + cipherdata->keylen, INLINE_KEY(cipherdata)); + + if (rta_sec_era >= RTA_SEC_ERA_8) { + PROTOCOL(p, dir, OP_PCLID_LTE_PDCP_USER, + (uint16_t)cipherdata->algtype); + return 0; + } + + SEQLOAD(p, MATH0, 6, 2, 0); + JUMP(p, 1, LOCAL_JUMP, ALL_TRUE, CALM); + if (swap == false) + MATHB(p, MATH0, AND, PDCP_U_PLANE_15BIT_SN_MASK, MATH1, 8, + IFB | IMMED2); + else + MATHB(p, MATH0, AND, PDCP_U_PLANE_15BIT_SN_MASK_BE, MATH1, 8, + IFB | IMMED2); + SEQSTORE(p, MATH0, 6, 2, 0); + MATHB(p, MATH1, SHLD, MATH1, MATH1, 8, 0); + MOVE(p, DESCBUF, 8, MATH2, 0, 8, WAITCOMP | IMMED); + MATHB(p, MATH1, OR, MATH2, MATH2, 8, 0); + + MATHB(p, SEQINSZ, SUB, MATH3, VSEQINSZ, 4, 0); + MATHB(p, SEQINSZ, SUB, MATH3, VSEQOUTSZ, 4, 0); + + SEQFIFOSTORE(p, MSG, 0, 0, VLF); + + op = dir == OP_TYPE_ENCAP_PROTOCOL ? DIR_ENC : DIR_DEC; + switch (cipherdata->algtype) { + case PDCP_CIPHER_TYPE_SNOW: + MOVE(p, MATH2, 0, CONTEXT1, 0, 8, WAITCOMP | IMMED); + ALG_OPERATION(p, OP_ALG_ALGSEL_SNOW_F8, + OP_ALG_AAI_F8, + OP_ALG_AS_INITFINAL, + ICV_CHECK_DISABLE, + op); + break; + + case PDCP_CIPHER_TYPE_AES: + MOVE(p, MATH2, 0, CONTEXT1, 0x10, 0x10, WAITCOMP | IMMED); + ALG_OPERATION(p, OP_ALG_ALGSEL_AES, + OP_ALG_AAI_CTR, + OP_ALG_AS_INITFINAL, + ICV_CHECK_DISABLE, + op); + break; + + case PDCP_CIPHER_TYPE_ZUC: + if (rta_sec_era < RTA_SEC_ERA_5) { + pr_err("Invalid era for selected algorithm\n"); + return -ENOTSUP; + } + MOVE(p, MATH2, 0, CONTEXT1, 0, 0x08, IMMED); + MOVE(p, MATH2, 0, CONTEXT1, 0x08, 0x08, WAITCOMP | IMMED); + + ALG_OPERATION(p, OP_ALG_ALGSEL_ZUCE, + OP_ALG_AAI_F8, + OP_ALG_AS_INITFINAL, + ICV_CHECK_DISABLE, + op); + break; + + default: + pr_err("%s: Invalid encrypt algorithm selected: %d\n", + "pdcp_insert_uplane_15bit_op", cipherdata->algtype); + return -EINVAL; + } + + SEQFIFOLOAD(p, MSG1, 0, VLF | LAST1 | FLUSH1); + + return 0; +} + +/* + * Function for inserting the snippet of code responsible for creating + * the HFN override code via either DPOVRD or via the input frame. + */ +static inline int +insert_hfn_ov_op(struct program *p, + uint32_t shift, + enum pdb_type_e pdb_type, + unsigned char era_2_sw_hfn_ovrd) +{ + uint32_t imm = PDCP_DPOVRD_HFN_OV_EN; + uint16_t hfn_pdb_offset; + + if (rta_sec_era == RTA_SEC_ERA_2 && !era_2_sw_hfn_ovrd) + return 0; + + switch (pdb_type) { + case PDCP_PDB_TYPE_NO_PDB: + /* + * If there is no PDB, then HFN override mechanism does not + * make any sense, thus in this case the function will + * return the pointer to the current position in the + * descriptor buffer + */ + return 0; + + case PDCP_PDB_TYPE_REDUCED_PDB: + hfn_pdb_offset = 4; + break; + + case PDCP_PDB_TYPE_FULL_PDB: + hfn_pdb_offset = 8; + break; + + default: + return -EINVAL; + } + + if (rta_sec_era > RTA_SEC_ERA_2) { + MATHB(p, DPOVRD, AND, imm, NONE, 8, IFB | IMMED2); + } else { + SEQLOAD(p, MATH0, 4, 4, 0); + JUMP(p, 1, LOCAL_JUMP, ALL_TRUE, CALM); + MATHB(p, MATH0, AND, imm, NONE, 8, IFB | IMMED2); + SEQSTORE(p, MATH0, 4, 4, 0); + } + + if (rta_sec_era >= RTA_SEC_ERA_8) + JUMP(p, 6, LOCAL_JUMP, ALL_TRUE, MATH_Z); + else + JUMP(p, 5, LOCAL_JUMP, ALL_TRUE, MATH_Z); + + if (rta_sec_era > RTA_SEC_ERA_2) + MATHB(p, DPOVRD, LSHIFT, shift, MATH0, 4, IMMED2); + else + MATHB(p, MATH0, LSHIFT, shift, MATH0, 4, IMMED2); + + MATHB(p, MATH0, SHLD, MATH0, MATH0, 8, 0); + MOVE(p, MATH0, 0, DESCBUF, hfn_pdb_offset, 4, IMMED); + + if (rta_sec_era >= RTA_SEC_ERA_8) + /* + * For ERA8, DPOVRD could be handled by the PROTOCOL command + * itself. For now, this is not done. Thus, clear DPOVRD here + * to alleviate any side-effects. + */ + MATHB(p, DPOVRD, AND, ZERO, DPOVRD, 4, STL); + + return 0; +} + +/* + * PDCP Control PDB creation function + */ +static inline enum pdb_type_e +cnstr_pdcp_c_plane_pdb(struct program *p, + uint32_t hfn, + unsigned char bearer, + unsigned char direction, + uint32_t hfn_threshold, + struct alginfo *cipherdata, + struct alginfo *authdata) +{ + struct pdcp_pdb pdb; + enum pdb_type_e + pdb_mask[PDCP_CIPHER_TYPE_INVALID][PDCP_AUTH_TYPE_INVALID] = { + { /* NULL */ + PDCP_PDB_TYPE_NO_PDB, /* NULL */ + PDCP_PDB_TYPE_FULL_PDB, /* SNOW f9 */ + PDCP_PDB_TYPE_FULL_PDB, /* AES CMAC */ + PDCP_PDB_TYPE_FULL_PDB /* ZUC-I */ + }, + { /* SNOW f8 */ + PDCP_PDB_TYPE_FULL_PDB, /* NULL */ + PDCP_PDB_TYPE_FULL_PDB, /* SNOW f9 */ + PDCP_PDB_TYPE_REDUCED_PDB, /* AES CMAC */ + PDCP_PDB_TYPE_REDUCED_PDB /* ZUC-I */ + }, + { /* AES CTR */ + PDCP_PDB_TYPE_FULL_PDB, /* NULL */ + PDCP_PDB_TYPE_REDUCED_PDB, /* SNOW f9 */ + PDCP_PDB_TYPE_FULL_PDB, /* AES CMAC */ + PDCP_PDB_TYPE_REDUCED_PDB /* ZUC-I */ + }, + { /* ZUC-E */ + PDCP_PDB_TYPE_FULL_PDB, /* NULL */ + PDCP_PDB_TYPE_REDUCED_PDB, /* SNOW f9 */ + PDCP_PDB_TYPE_REDUCED_PDB, /* AES CMAC */ + PDCP_PDB_TYPE_FULL_PDB /* ZUC-I */ + }, + }; + + if (rta_sec_era >= RTA_SEC_ERA_8) { + memset(&pdb, 0x00, sizeof(struct pdcp_pdb)); + + /* This is a HW issue. Bit 2 should be set to zero, + * but it does not work this way. Override here. + */ + pdb.opt_res.rsvd = 0x00000002; + + /* Copy relevant information from user to PDB */ + pdb.hfn_res = hfn << PDCP_C_PLANE_PDB_HFN_SHIFT; + pdb.bearer_dir_res = (uint32_t) + ((bearer << PDCP_C_PLANE_PDB_BEARER_SHIFT) | + (direction << PDCP_C_PLANE_PDB_DIR_SHIFT)); + pdb.hfn_thr_res = + hfn_threshold << PDCP_C_PLANE_PDB_HFN_THR_SHIFT; + + /* copy PDB in descriptor*/ + __rta_out32(p, pdb.opt_res.opt); + __rta_out32(p, pdb.hfn_res); + __rta_out32(p, pdb.bearer_dir_res); + __rta_out32(p, pdb.hfn_thr_res); + + return PDCP_PDB_TYPE_FULL_PDB; + } + + switch (pdb_mask[cipherdata->algtype][authdata->algtype]) { + case PDCP_PDB_TYPE_NO_PDB: + break; + + case PDCP_PDB_TYPE_REDUCED_PDB: + __rta_out32(p, (hfn << PDCP_C_PLANE_PDB_HFN_SHIFT)); + __rta_out32(p, + (uint32_t)((bearer << + PDCP_C_PLANE_PDB_BEARER_SHIFT) | + (direction << + PDCP_C_PLANE_PDB_DIR_SHIFT))); + break; + + case PDCP_PDB_TYPE_FULL_PDB: + memset(&pdb, 0x00, sizeof(struct pdcp_pdb)); + + /* This is a HW issue. Bit 2 should be set to zero, + * but it does not work this way. Override here. + */ + pdb.opt_res.rsvd = 0x00000002; + + /* Copy relevant information from user to PDB */ + pdb.hfn_res = hfn << PDCP_C_PLANE_PDB_HFN_SHIFT; + pdb.bearer_dir_res = (uint32_t) + ((bearer << PDCP_C_PLANE_PDB_BEARER_SHIFT) | + (direction << PDCP_C_PLANE_PDB_DIR_SHIFT)); + pdb.hfn_thr_res = + hfn_threshold << PDCP_C_PLANE_PDB_HFN_THR_SHIFT; + + /* copy PDB in descriptor*/ + __rta_out32(p, pdb.opt_res.opt); + __rta_out32(p, pdb.hfn_res); + __rta_out32(p, pdb.bearer_dir_res); + __rta_out32(p, pdb.hfn_thr_res); + + break; + + default: + return PDCP_PDB_TYPE_INVALID; + } + + return pdb_mask[cipherdata->algtype][authdata->algtype]; +} + +/* + * PDCP UPlane PDB creation function + */ +static inline int +cnstr_pdcp_u_plane_pdb(struct program *p, + enum pdcp_sn_size sn_size, + uint32_t hfn, unsigned short bearer, + unsigned short direction, + uint32_t hfn_threshold) +{ + struct pdcp_pdb pdb; + /* Read options from user */ + /* Depending on sequence number length, the HFN and HFN threshold + * have different lengths. + */ + memset(&pdb, 0x00, sizeof(struct pdcp_pdb)); + + switch (sn_size) { + case PDCP_SN_SIZE_7: + pdb.opt_res.opt |= PDCP_U_PLANE_PDB_OPT_SHORT_SN; + pdb.hfn_res = hfn << PDCP_U_PLANE_PDB_SHORT_SN_HFN_SHIFT; + pdb.hfn_thr_res = + hfn_threshold<algtype][authdata->algtype], 0, 0); + + pdb_type = cnstr_pdcp_c_plane_pdb(p, + hfn, + bearer, + direction, + hfn_threshold, + cipherdata, + authdata); + + SET_LABEL(p, pdb_end); + + err = insert_hfn_ov_op(p, PDCP_SN_SIZE_5, pdb_type, + era_2_sw_hfn_ovrd); + if (err) + return err; + + err = pdcp_cp_fp[cipherdata->algtype][authdata->algtype](p, + swap, + cipherdata, + authdata, + OP_TYPE_ENCAP_PROTOCOL, + era_2_sw_hfn_ovrd); + if (err) + return err; + + PATCH_HDR(p, 0, pdb_end); + + return PROGRAM_FINALIZE(p); +} + +/** + * cnstr_shdsc_pdcp_c_plane_decap - Function for creating a PDCP Control Plane + * decapsulation descriptor. + * @descbuf: pointer to buffer for descriptor construction + * @ps: if 36/40bit addressing is desired, this parameter must be true + * @swap: must be true when core endianness doesn't match SEC endianness + * @hfn: starting Hyper Frame Number to be used together with the SN from the + * PDCP frames. + * @bearer: radio bearer ID + * @direction: the direction of the PDCP frame (UL/DL) + * @hfn_threshold: HFN value that once reached triggers a warning from SEC that + * keys should be renegotiated at the earliest convenience. + * @cipherdata: pointer to block cipher transform definitions + * Valid algorithm values are those from cipher_type_pdcp enum. + * @authdata: pointer to authentication transform definitions + * Valid algorithm values are those from auth_type_pdcp enum. + * @era_2_sw_hfn_ovrd: if software HFN override mechanism is desired for + * this descriptor. Note: Can only be used for + * SEC ERA 2. + * + * Return: size of descriptor written in words or negative number on error. + * Once the function returns, the value of this parameter can be used + * for reclaiming the space that wasn't used for the descriptor. + * + * Note: descbuf must be large enough to contain a full 256 byte long + * descriptor; after the function returns, by subtracting the actual number of + * bytes used, the user can reuse the remaining buffer space for other purposes. + */ +static inline int +cnstr_shdsc_pdcp_c_plane_decap(uint32_t *descbuf, + bool ps, + bool swap, + uint32_t hfn, + unsigned char bearer, + unsigned char direction, + uint32_t hfn_threshold, + struct alginfo *cipherdata, + struct alginfo *authdata, + unsigned char era_2_sw_hfn_ovrd) +{ + static int + (*pdcp_cp_fp[PDCP_CIPHER_TYPE_INVALID][PDCP_AUTH_TYPE_INVALID]) + (struct program*, bool swap, struct alginfo *, + struct alginfo *, unsigned int, unsigned char) = { + { /* NULL */ + pdcp_insert_cplane_null_op, /* NULL */ + pdcp_insert_cplane_int_only_op, /* SNOW f9 */ + pdcp_insert_cplane_int_only_op, /* AES CMAC */ + pdcp_insert_cplane_int_only_op /* ZUC-I */ + }, + { /* SNOW f8 */ + pdcp_insert_cplane_enc_only_op, /* NULL */ + pdcp_insert_cplane_acc_op, /* SNOW f9 */ + pdcp_insert_cplane_snow_aes_op, /* AES CMAC */ + pdcp_insert_cplane_snow_zuc_op /* ZUC-I */ + }, + { /* AES CTR */ + pdcp_insert_cplane_enc_only_op, /* NULL */ + pdcp_insert_cplane_aes_snow_op, /* SNOW f9 */ + pdcp_insert_cplane_acc_op, /* AES CMAC */ + pdcp_insert_cplane_aes_zuc_op /* ZUC-I */ + }, + { /* ZUC-E */ + pdcp_insert_cplane_enc_only_op, /* NULL */ + pdcp_insert_cplane_zuc_snow_op, /* SNOW f9 */ + pdcp_insert_cplane_zuc_aes_op, /* AES CMAC */ + pdcp_insert_cplane_acc_op /* ZUC-I */ + }, + }; + static enum rta_share_type + desc_share[PDCP_CIPHER_TYPE_INVALID][PDCP_AUTH_TYPE_INVALID] = { + { /* NULL */ + SHR_WAIT, /* NULL */ + SHR_ALWAYS, /* SNOW f9 */ + SHR_ALWAYS, /* AES CMAC */ + SHR_ALWAYS /* ZUC-I */ + }, + { /* SNOW f8 */ + SHR_ALWAYS, /* NULL */ + SHR_ALWAYS, /* SNOW f9 */ + SHR_WAIT, /* AES CMAC */ + SHR_WAIT /* ZUC-I */ + }, + { /* AES CTR */ + SHR_ALWAYS, /* NULL */ + SHR_ALWAYS, /* SNOW f9 */ + SHR_ALWAYS, /* AES CMAC */ + SHR_WAIT /* ZUC-I */ + }, + { /* ZUC-E */ + SHR_ALWAYS, /* NULL */ + SHR_WAIT, /* SNOW f9 */ + SHR_WAIT, /* AES CMAC */ + SHR_ALWAYS /* ZUC-I */ + }, + }; + enum pdb_type_e pdb_type; + struct program prg; + struct program *p = &prg; + int err; + LABEL(pdb_end); + + if (rta_sec_era != RTA_SEC_ERA_2 && era_2_sw_hfn_ovrd) { + pr_err("Cannot select SW HFN override for other era than 2"); + return -EINVAL; + } + + PROGRAM_CNTXT_INIT(p, descbuf, 0); + if (swap) + PROGRAM_SET_BSWAP(p); + if (ps) + PROGRAM_SET_36BIT_ADDR(p); + + SHR_HDR(p, desc_share[cipherdata->algtype][authdata->algtype], 0, 0); + + pdb_type = cnstr_pdcp_c_plane_pdb(p, + hfn, + bearer, + direction, + hfn_threshold, + cipherdata, + authdata); + + SET_LABEL(p, pdb_end); + + err = insert_hfn_ov_op(p, PDCP_SN_SIZE_5, pdb_type, + era_2_sw_hfn_ovrd); + if (err) + return err; + + err = pdcp_cp_fp[cipherdata->algtype][authdata->algtype](p, + swap, + cipherdata, + authdata, + OP_TYPE_DECAP_PROTOCOL, + era_2_sw_hfn_ovrd); + if (err) + return err; + + PATCH_HDR(p, 0, pdb_end); + + return PROGRAM_FINALIZE(p); +} + +/** + * cnstr_shdsc_pdcp_u_plane_encap - Function for creating a PDCP User Plane + * encapsulation descriptor. + * @descbuf: pointer to buffer for descriptor construction + * @ps: if 36/40bit addressing is desired, this parameter must be true + * @swap: must be true when core endianness doesn't match SEC endianness + * @sn_size: selects Sequence Number Size: 7/12/15 bits + * @hfn: starting Hyper Frame Number to be used together with the SN from the + * PDCP frames. + * @bearer: radio bearer ID + * @direction: the direction of the PDCP frame (UL/DL) + * @hfn_threshold: HFN value that once reached triggers a warning from SEC that + * keys should be renegotiated at the earliest convenience. + * @cipherdata: pointer to block cipher transform definitions + * Valid algorithm values are those from cipher_type_pdcp enum. + * @era_2_sw_hfn_ovrd: if software HFN override mechanism is desired for + * this descriptor. Note: Can only be used for + * SEC ERA 2. + * + * Return: size of descriptor written in words or negative number on error. + * Once the function returns, the value of this parameter can be used + * for reclaiming the space that wasn't used for the descriptor. + * + * Note: descbuf must be large enough to contain a full 256 byte long + * descriptor; after the function returns, by subtracting the actual number of + * bytes used, the user can reuse the remaining buffer space for other purposes. + */ +static inline int +cnstr_shdsc_pdcp_u_plane_encap(uint32_t *descbuf, + bool ps, + bool swap, + enum pdcp_sn_size sn_size, + uint32_t hfn, + unsigned short bearer, + unsigned short direction, + uint32_t hfn_threshold, + struct alginfo *cipherdata, + unsigned char era_2_sw_hfn_ovrd) +{ + struct program prg; + struct program *p = &prg; + int err; + LABEL(pdb_end); + + if (rta_sec_era != RTA_SEC_ERA_2 && era_2_sw_hfn_ovrd) { + pr_err("Cannot select SW HFN ovrd for other era than 2"); + return -EINVAL; + } + + PROGRAM_CNTXT_INIT(p, descbuf, 0); + if (swap) + PROGRAM_SET_BSWAP(p); + if (ps) + PROGRAM_SET_36BIT_ADDR(p); + + SHR_HDR(p, SHR_ALWAYS, 0, 0); + if (cnstr_pdcp_u_plane_pdb(p, sn_size, hfn, bearer, direction, + hfn_threshold)) { + pr_err("Error creating PDCP UPlane PDB\n"); + return -EINVAL; + } + SET_LABEL(p, pdb_end); + + err = insert_hfn_ov_op(p, sn_size, PDCP_PDB_TYPE_FULL_PDB, + era_2_sw_hfn_ovrd); + if (err) + return err; + + switch (sn_size) { + case PDCP_SN_SIZE_7: + case PDCP_SN_SIZE_12: + switch (cipherdata->algtype) { + case PDCP_CIPHER_TYPE_ZUC: + if (rta_sec_era < RTA_SEC_ERA_5) { + pr_err("Invalid era for selected algorithm\n"); + return -ENOTSUP; + } + case PDCP_CIPHER_TYPE_AES: + case PDCP_CIPHER_TYPE_SNOW: + /* Insert Cipher Key */ + KEY(p, KEY1, cipherdata->key_enc_flags, + (uint64_t)cipherdata->key, cipherdata->keylen, + INLINE_KEY(cipherdata)); + PROTOCOL(p, OP_TYPE_ENCAP_PROTOCOL, + OP_PCLID_LTE_PDCP_USER, + (uint16_t)cipherdata->algtype); + break; + case PDCP_CIPHER_TYPE_NULL: + insert_copy_frame_op(p, + cipherdata, + OP_TYPE_ENCAP_PROTOCOL); + break; + default: + pr_err("%s: Invalid encrypt algorithm selected: %d\n", + "cnstr_pcl_shdsc_pdcp_u_plane_decap", + cipherdata->algtype); + return -EINVAL; + } + break; + + case PDCP_SN_SIZE_15: + switch (cipherdata->algtype) { + case PDCP_CIPHER_TYPE_NULL: + insert_copy_frame_op(p, + cipherdata, + OP_TYPE_ENCAP_PROTOCOL); + break; + + default: + err = pdcp_insert_uplane_15bit_op(p, swap, cipherdata, + OP_TYPE_ENCAP_PROTOCOL); + if (err) + return err; + break; + } + break; + + case PDCP_SN_SIZE_5: + default: + pr_err("Invalid SN size selected\n"); + return -ENOTSUP; + } + + PATCH_HDR(p, 0, pdb_end); + return PROGRAM_FINALIZE(p); +} + +/** + * cnstr_shdsc_pdcp_u_plane_decap - Function for creating a PDCP User Plane + * decapsulation descriptor. + * @descbuf: pointer to buffer for descriptor construction + * @ps: if 36/40bit addressing is desired, this parameter must be true + * @swap: must be true when core endianness doesn't match SEC endianness + * @sn_size: selects Sequence Number Size: 7/12/15 bits + * @hfn: starting Hyper Frame Number to be used together with the SN from the + * PDCP frames. + * @bearer: radio bearer ID + * @direction: the direction of the PDCP frame (UL/DL) + * @hfn_threshold: HFN value that once reached triggers a warning from SEC that + * keys should be renegotiated at the earliest convenience. + * @cipherdata: pointer to block cipher transform definitions + * Valid algorithm values are those from cipher_type_pdcp enum. + * @era_2_sw_hfn_ovrd: if software HFN override mechanism is desired for + * this descriptor. Note: Can only be used for + * SEC ERA 2. + * + * Return: size of descriptor written in words or negative number on error. + * Once the function returns, the value of this parameter can be used + * for reclaiming the space that wasn't used for the descriptor. + * + * Note: descbuf must be large enough to contain a full 256 byte long + * descriptor; after the function returns, by subtracting the actual number of + * bytes used, the user can reuse the remaining buffer space for other purposes. + */ +static inline int +cnstr_shdsc_pdcp_u_plane_decap(uint32_t *descbuf, + bool ps, + bool swap, + enum pdcp_sn_size sn_size, + uint32_t hfn, + unsigned short bearer, + unsigned short direction, + uint32_t hfn_threshold, + struct alginfo *cipherdata, + unsigned char era_2_sw_hfn_ovrd) +{ + struct program prg; + struct program *p = &prg; + int err; + LABEL(pdb_end); + + if (rta_sec_era != RTA_SEC_ERA_2 && era_2_sw_hfn_ovrd) { + pr_err("Cannot select SW HFN override for other era than 2"); + return -EINVAL; + } + + PROGRAM_CNTXT_INIT(p, descbuf, 0); + if (swap) + PROGRAM_SET_BSWAP(p); + if (ps) + PROGRAM_SET_36BIT_ADDR(p); + + SHR_HDR(p, SHR_ALWAYS, 0, 0); + if (cnstr_pdcp_u_plane_pdb(p, sn_size, hfn, bearer, direction, + hfn_threshold)) { + pr_err("Error creating PDCP UPlane PDB\n"); + return -EINVAL; + } + SET_LABEL(p, pdb_end); + + err = insert_hfn_ov_op(p, sn_size, PDCP_PDB_TYPE_FULL_PDB, + era_2_sw_hfn_ovrd); + if (err) + return err; + + switch (sn_size) { + case PDCP_SN_SIZE_7: + case PDCP_SN_SIZE_12: + switch (cipherdata->algtype) { + case PDCP_CIPHER_TYPE_ZUC: + if (rta_sec_era < RTA_SEC_ERA_5) { + pr_err("Invalid era for selected algorithm\n"); + return -ENOTSUP; + } + case PDCP_CIPHER_TYPE_AES: + case PDCP_CIPHER_TYPE_SNOW: + /* Insert Cipher Key */ + KEY(p, KEY1, cipherdata->key_enc_flags, + cipherdata->key, cipherdata->keylen, + INLINE_KEY(cipherdata)); + PROTOCOL(p, OP_TYPE_DECAP_PROTOCOL, + OP_PCLID_LTE_PDCP_USER, + (uint16_t)cipherdata->algtype); + break; + case PDCP_CIPHER_TYPE_NULL: + insert_copy_frame_op(p, + cipherdata, + OP_TYPE_DECAP_PROTOCOL); + break; + default: + pr_err("%s: Invalid encrypt algorithm selected: %d\n", + "cnstr_pcl_shdsc_pdcp_u_plane_decap", + cipherdata->algtype); + return -EINVAL; + } + break; + + case PDCP_SN_SIZE_15: + switch (cipherdata->algtype) { + case PDCP_CIPHER_TYPE_NULL: + insert_copy_frame_op(p, + cipherdata, + OP_TYPE_DECAP_PROTOCOL); + break; + + default: + err = pdcp_insert_uplane_15bit_op(p, swap, cipherdata, + OP_TYPE_DECAP_PROTOCOL); + if (err) + return err; + break; + } + break; + + case PDCP_SN_SIZE_5: + default: + pr_err("Invalid SN size selected\n"); + return -ENOTSUP; + } + + PATCH_HDR(p, 0, pdb_end); + return PROGRAM_FINALIZE(p); +} + +/** + * cnstr_shdsc_pdcp_short_mac - Function for creating a PDCP Short MAC + * descriptor. + * @descbuf: pointer to buffer for descriptor construction + * @ps: if 36/40bit addressing is desired, this parameter must be true + * @swap: must be true when core endianness doesn't match SEC endianness + * @authdata: pointer to authentication transform definitions + * Valid algorithm values are those from auth_type_pdcp enum. + * + * Return: size of descriptor written in words or negative number on error. + * Once the function returns, the value of this parameter can be used + * for reclaiming the space that wasn't used for the descriptor. + * + * Note: descbuf must be large enough to contain a full 256 byte long + * descriptor; after the function returns, by subtracting the actual number of + * bytes used, the user can reuse the remaining buffer space for other purposes. + */ +static inline int +cnstr_shdsc_pdcp_short_mac(uint32_t *descbuf, + bool ps, + bool swap, + struct alginfo *authdata) +{ + struct program prg; + struct program *p = &prg; + uint32_t iv[3] = {0, 0, 0}; + LABEL(local_offset); + REFERENCE(move_cmd_read_descbuf); + REFERENCE(move_cmd_write_descbuf); + + PROGRAM_CNTXT_INIT(p, descbuf, 0); + if (swap) + PROGRAM_SET_BSWAP(p); + if (ps) + PROGRAM_SET_36BIT_ADDR(p); + + SHR_HDR(p, SHR_ALWAYS, 1, 0); + + if (rta_sec_era > RTA_SEC_ERA_2) { + MATHB(p, SEQINSZ, SUB, ZERO, VSEQINSZ, 4, 0); + MATHB(p, SEQINSZ, SUB, ZERO, MATH1, 4, 0); + } else { + MATHB(p, SEQINSZ, ADD, ONE, MATH1, 4, 0); + MATHB(p, MATH1, SUB, ONE, MATH1, 4, 0); + MATHB(p, ZERO, ADD, MATH1, VSEQINSZ, 4, 0); + MOVE(p, MATH1, 0, MATH0, 0, 8, IMMED); + + /* + * Since MOVELEN is available only starting with + * SEC ERA 3, use poor man's MOVELEN: create a MOVE + * command dynamically by writing the length from M1 by + * OR-ing the command in the M1 register and MOVE the + * result into the descriptor buffer. Care must be taken + * wrt. the location of the command because of SEC + * pipelining. The actual MOVEs are written at the end + * of the descriptor due to calculations needed on the + * offset in the descriptor for the MOVE command. + */ + move_cmd_read_descbuf = MOVE(p, DESCBUF, 0, MATH0, 0, 6, + IMMED); + move_cmd_write_descbuf = MOVE(p, MATH0, 0, DESCBUF, 0, 8, + WAITCOMP | IMMED); + } + MATHB(p, ZERO, ADD, MATH1, VSEQOUTSZ, 4, 0); + + switch (authdata->algtype) { + case PDCP_AUTH_TYPE_NULL: + SEQFIFOSTORE(p, MSG, 0, 0, VLF); + if (rta_sec_era > RTA_SEC_ERA_2) { + MOVE(p, AB1, 0, OFIFO, 0, MATH1, 0); + } else { + SET_LABEL(p, local_offset); + + /* Shut off automatic Info FIFO entries */ + LOAD(p, 0, DCTRL, LDOFF_DISABLE_AUTO_NFIFO, 0, IMMED); + + /* Placeholder for MOVE command with length from M1 + * register + */ + MOVE(p, IFIFOAB1, 0, OFIFO, 0, 0, IMMED); + + /* Enable automatic Info FIFO entries */ + LOAD(p, 0, DCTRL, LDOFF_ENABLE_AUTO_NFIFO, 0, IMMED); + } + + LOAD(p, (uintptr_t)iv, MATH0, 0, 8, IMMED | COPY); + SEQFIFOLOAD(p, MSG1, 0, VLF | LAST1 | LAST2 | FLUSH1); + SEQSTORE(p, MATH0, 0, 4, 0); + + break; + + case PDCP_AUTH_TYPE_SNOW: + iv[0] = 0xFFFFFFFF; + iv[1] = swap ? swab32(0x04000000) : 0x04000000; + iv[2] = swap ? swab32(0xF8000000) : 0xF8000000; + + KEY(p, KEY2, authdata->key_enc_flags, authdata->key, + authdata->keylen, INLINE_KEY(authdata)); + LOAD(p, (uintptr_t)&iv, CONTEXT2, 0, 12, IMMED | COPY); + ALG_OPERATION(p, OP_ALG_ALGSEL_SNOW_F9, + OP_ALG_AAI_F9, + OP_ALG_AS_INITFINAL, + ICV_CHECK_DISABLE, + DIR_ENC); + SEQFIFOSTORE(p, MSG, 0, 0, VLF); + + if (rta_sec_era > RTA_SEC_ERA_2) { + MOVE(p, AB1, 0, OFIFO, 0, MATH1, 0); + } else { + SET_LABEL(p, local_offset); + + + /* Shut off automatic Info FIFO entries */ + LOAD(p, 0, DCTRL, LDOFF_DISABLE_AUTO_NFIFO, 0, IMMED); + + /* Placeholder for MOVE command with length from M1 + * register + */ + MOVE(p, IFIFOAB1, 0, OFIFO, 0, 0, IMMED); + + /* Enable automatic Info FIFO entries */ + LOAD(p, 0, DCTRL, LDOFF_ENABLE_AUTO_NFIFO, 0, IMMED); + } + SEQFIFOLOAD(p, MSGINSNOOP, 0, VLF | LAST1 | LAST2 | FLUSH1); + SEQSTORE(p, CONTEXT2, 0, 4, 0); + + break; + + case PDCP_AUTH_TYPE_AES: + iv[0] = 0xFFFFFFFF; + iv[1] = swap ? swab32(0xFC000000) : 0xFC000000; + iv[2] = 0x00000000; /* unused */ + + KEY(p, KEY1, authdata->key_enc_flags, authdata->key, + authdata->keylen, INLINE_KEY(authdata)); + LOAD(p, (uintptr_t)&iv, MATH0, 0, 8, IMMED | COPY); + MOVE(p, MATH0, 0, IFIFOAB1, 0, 8, IMMED); + ALG_OPERATION(p, OP_ALG_ALGSEL_AES, + OP_ALG_AAI_CMAC, + OP_ALG_AS_INITFINAL, + ICV_CHECK_DISABLE, + DIR_ENC); + SEQFIFOSTORE(p, MSG, 0, 0, VLF); + + if (rta_sec_era > RTA_SEC_ERA_2) { + MOVE(p, AB2, 0, OFIFO, 0, MATH1, 0); + } else { + SET_LABEL(p, local_offset); + + /* Shut off automatic Info FIFO entries */ + LOAD(p, 0, DCTRL, LDOFF_DISABLE_AUTO_NFIFO, 0, IMMED); + + /* Placeholder for MOVE command with length from M1 + * register + */ + MOVE(p, IFIFOAB2, 0, OFIFO, 0, 0, IMMED); + + /* Enable automatic Info FIFO entries */ + LOAD(p, 0, DCTRL, LDOFF_ENABLE_AUTO_NFIFO, 0, IMMED); + } + SEQFIFOLOAD(p, MSGINSNOOP, 0, VLF | LAST1 | LAST2 | FLUSH1); + SEQSTORE(p, CONTEXT1, 0, 4, 0); + + break; + + case PDCP_AUTH_TYPE_ZUC: + if (rta_sec_era < RTA_SEC_ERA_5) { + pr_err("Invalid era for selected algorithm\n"); + return -ENOTSUP; + } + iv[0] = 0xFFFFFFFF; + iv[1] = swap ? swab32(0xFC000000) : 0xFC000000; + iv[2] = 0x00000000; /* unused */ + + KEY(p, KEY2, authdata->key_enc_flags, authdata->key, + authdata->keylen, INLINE_KEY(authdata)); + LOAD(p, (uintptr_t)&iv, CONTEXT2, 0, 12, IMMED | COPY); + ALG_OPERATION(p, OP_ALG_ALGSEL_ZUCA, + OP_ALG_AAI_F9, + OP_ALG_AS_INITFINAL, + ICV_CHECK_DISABLE, + DIR_ENC); + SEQFIFOSTORE(p, MSG, 0, 0, VLF); + MOVE(p, AB1, 0, OFIFO, 0, MATH1, 0); + SEQFIFOLOAD(p, MSGINSNOOP, 0, VLF | LAST1 | LAST2 | FLUSH1); + SEQSTORE(p, CONTEXT2, 0, 4, 0); + + break; + + default: + pr_err("%s: Invalid integrity algorithm selected: %d\n", + "cnstr_shdsc_pdcp_short_mac", authdata->algtype); + return -EINVAL; + } + + + if (rta_sec_era < RTA_SEC_ERA_3) { + PATCH_MOVE(p, move_cmd_read_descbuf, local_offset); + PATCH_MOVE(p, move_cmd_write_descbuf, local_offset); + } + + return PROGRAM_FINALIZE(p); +} + +#endif /* __DESC_PDCP_H__ */ From patchwork Mon Oct 22 07:12:10 2018 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Hemant Agrawal X-Patchwork-Id: 149372 Delivered-To: patch@linaro.org Received: by 2002:a2e:8595:0:0:0:0:0 with SMTP id b21-v6csp2295887lji; Mon, 22 Oct 2018 00:14:53 -0700 (PDT) X-Google-Smtp-Source: ACcGV61zawY2wH5LMxI7T60glZKI6dWzjRYmtUaLp76gSUrUbCSbq/n6ddYMXp3JgR1aTUCwlbOA X-Received: by 2002:a1c:1812:: with SMTP id 18-v6mr14941651wmy.34.1540192493115; Mon, 22 Oct 2018 00:14:53 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1540192493; cv=none; d=google.com; s=arc-20160816; b=xH4bqEOsSWmGS5B2qpcoJOMKXiuNZ8C/hglamY1LFtq8KwLtwcctbHfVQpeWtF8kkC mzXlYbQWkWJESvPXgeCVB5Ex/+6ap+Cq24vvhSS0neMDcSeqfaUGWxg+jZXQU8cPSHqw 60SmgmFZc8PNvmOcVvojp8wcpas9SJwTmGkvEiwIqkR7fqUAr1kC719QX8fGJoc8Bcrz wOUz/JgXZnXy2t6Amtw00AdyrUiJ8fwhBQv2r9MBp5buxbq1dDbbazvkc4tWZceHcBfQ wVZ2rr5zZe0Cl7F8xlLNDj4RWBZCmA6GOCQdqDPbqCDxCTHYnCcZT/WNraEQeJhBojy0 EfmA== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=sender:errors-to:list-subscribe:list-help:list-post:list-archive :list-unsubscribe:list-id:precedence:subject:references:in-reply-to :message-id:date:cc:to:from; bh=c+ulLtP7B927e2FmbhkFpxH+EV2mJ5pSQ5Ixgtlnd3g=; b=vMHN8kz2hWkWG4M5CAia7e5aB47z9UxDJF3gCkT3NHcziUEw9ocYak8OIkFjNt1LJc 1YkfLKr7n8mfGHD7n+HUM3K2jQJW72ljtjEe0A6lrNlYmyTHgt4VEoNmnkXd0zPcBjWV QbLC9nl6bwvrS7UcPjjukrWKexJtNRMJ3/xHeQVy6M0dzSl1GVTw8AD2CrAyJ6YPOo3c 6uk/aeJ6JGJGLT5LMtF5beAaqTMI3Vi779+BI6bn8QjtqdF1RsIzQNQJ9T31n63HvvGG ZmTzCHVoEb1iUWEMnqF02pgL2HNvv+SS1abB5ihJVm+bRr27nBF/ocsBC+R0cfx9jMjU lCNg== ARC-Authentication-Results: i=1; mx.google.com; spf=pass (google.com: domain of dev-bounces@dpdk.org designates 92.243.14.124 as permitted sender) smtp.mailfrom=dev-bounces@dpdk.org; dmarc=fail (p=NONE sp=NONE dis=NONE) header.from=nxp.com Return-Path: Received: from dpdk.org (dpdk.org. [92.243.14.124]) by mx.google.com with ESMTP id x13-v6si558569wrn.206.2018.10.22.00.14.52; Mon, 22 Oct 2018 00:14:53 -0700 (PDT) Received-SPF: pass (google.com: domain of dev-bounces@dpdk.org designates 92.243.14.124 as permitted sender) client-ip=92.243.14.124; Authentication-Results: mx.google.com; spf=pass (google.com: domain of dev-bounces@dpdk.org designates 92.243.14.124 as permitted sender) smtp.mailfrom=dev-bounces@dpdk.org; dmarc=fail (p=NONE sp=NONE dis=NONE) header.from=nxp.com Received: from [92.243.14.124] (localhost [127.0.0.1]) by dpdk.org (Postfix) with ESMTP id E56644F9B; Mon, 22 Oct 2018 09:14:45 +0200 (CEST) Received: from inva021.nxp.com (inva021.nxp.com [92.121.34.21]) by dpdk.org (Postfix) with ESMTP id CA0744F90 for ; Mon, 22 Oct 2018 09:14:39 +0200 (CEST) Received: from inva021.nxp.com (localhost [127.0.0.1]) by inva021.eu-rdc02.nxp.com (Postfix) with ESMTP id 66F5D2001B4; Mon, 22 Oct 2018 09:14:39 +0200 (CEST) Received: from invc005.ap-rdc01.nxp.com (invc005.ap-rdc01.nxp.com [165.114.16.14]) by inva021.eu-rdc02.nxp.com (Postfix) with ESMTP id 78B5D20019B; Mon, 22 Oct 2018 09:14:34 +0200 (CEST) Received: from bf-netperf1.ap.freescale.net (bf-netperf1.ap.freescale.net [10.232.134.28]) by invc005.ap-rdc01.nxp.com (Postfix) with ESMTP id 3F06F4030B; Mon, 22 Oct 2018 15:14:28 +0800 (SGT) From: Hemant Agrawal To: dev@dpdk.org Cc: thomas@monjalon.net, pablo.de.lara.guarch@intel.com, radu.nicolau@intel.com, jerin.jacob@caviumnetworks.com, narayanaprasad.athreya@caviumnetworks.com, Shally.Verma@caviumnetworks.com, Anoob.Joseph@caviumnetworks.com, Vidya.Velumuri@caviumnetworks.com, akhil.goyal@nxp.com Date: Mon, 22 Oct 2018 12:42:10 +0530 Message-Id: <1540192330-4105-4-git-send-email-hemant.agrawal@nxp.com> X-Mailer: git-send-email 2.7.4 In-Reply-To: <1540192330-4105-1-git-send-email-hemant.agrawal@nxp.com> References: <20181016103352.2678-1-akhil.goyal@nxp.com> <1540192330-4105-1-git-send-email-hemant.agrawal@nxp.com> X-Virus-Scanned: ClamAV using ClamSMTP Subject: [dpdk-dev] [PATCH v6 3/3] crypto/dpaa2_sec: support pdcp offload X-BeenThere: dev@dpdk.org X-Mailman-Version: 2.1.15 Precedence: list List-Id: DPDK patches and discussions List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: dev-bounces@dpdk.org Sender: "dev" From: Akhil Goyal PDCP session configuration for lookaside protocol offload and data path is added. Signed-off-by: Hemant Agrawal Signed-off-by: Akhil Goyal --- drivers/crypto/dpaa2_sec/dpaa2_sec_dpseci.c | 258 ++++++++++++++++++++++++++++ drivers/crypto/dpaa2_sec/dpaa2_sec_priv.h | 208 +++++++++++++++++++++- 2 files changed, 458 insertions(+), 8 deletions(-) -- 2.7.4 diff --git a/drivers/crypto/dpaa2_sec/dpaa2_sec_dpseci.c b/drivers/crypto/dpaa2_sec/dpaa2_sec_dpseci.c index 0336d5f..e5c3e7b 100644 --- a/drivers/crypto/dpaa2_sec/dpaa2_sec_dpseci.c +++ b/drivers/crypto/dpaa2_sec/dpaa2_sec_dpseci.c @@ -35,6 +35,7 @@ typedef uint64_t dma_addr_t; /* RTA header files */ #include +#include #include /* Minimum job descriptor consists of a oneword job descriptor HEADER and @@ -74,6 +75,9 @@ build_proto_compound_fd(dpaa2_sec_session *sess, struct rte_mbuf *dst_mbuf = sym_op->m_dst; int retval; + if (!dst_mbuf) + dst_mbuf = src_mbuf; + /* Save the shared descriptor */ flc = &priv->flc_desc[0].flc; @@ -118,6 +122,15 @@ build_proto_compound_fd(dpaa2_sec_session *sess, DPAA2_SET_FD_LEN(fd, ip_fle->length); DPAA2_SET_FLE_FIN(ip_fle); +#ifdef ENABLE_HFN_OVERRIDE + if (sess->ctxt_type == DPAA2_SEC_PDCP && sess->pdcp.hfn_ovd) { + /*enable HFN override override */ + DPAA2_SET_FLE_INTERNAL_JD(ip_fle, sess->pdcp.hfn_ovd); + DPAA2_SET_FLE_INTERNAL_JD(op_fle, sess->pdcp.hfn_ovd); + DPAA2_SET_FD_INTERNAL_JD(fd, sess->pdcp.hfn_ovd); + } +#endif + return 0; } @@ -1188,6 +1201,9 @@ build_sec_fd(struct rte_crypto_op *op, case DPAA2_SEC_IPSEC: ret = build_proto_fd(sess, op, fd, bpid); break; + case DPAA2_SEC_PDCP: + ret = build_proto_compound_fd(sess, op, fd, bpid); + break; case DPAA2_SEC_HASH_CIPHER: default: DPAA2_SEC_ERR("error: Unsupported session"); @@ -2552,6 +2568,244 @@ dpaa2_sec_set_ipsec_session(struct rte_cryptodev *dev, } static int +dpaa2_sec_set_pdcp_session(struct rte_cryptodev *dev, + struct rte_security_session_conf *conf, + void *sess) +{ + struct rte_security_pdcp_xform *pdcp_xform = &conf->pdcp; + struct rte_crypto_sym_xform *xform = conf->crypto_xform; + struct rte_crypto_auth_xform *auth_xform = NULL; + struct rte_crypto_cipher_xform *cipher_xform; + dpaa2_sec_session *session = (dpaa2_sec_session *)sess; + struct ctxt_priv *priv; + struct dpaa2_sec_dev_private *dev_priv = dev->data->dev_private; + struct alginfo authdata, cipherdata; + int bufsize = -1; + struct sec_flow_context *flc; +#if RTE_BYTE_ORDER == RTE_BIG_ENDIAN + int swap = true; +#else + int swap = false; +#endif + + PMD_INIT_FUNC_TRACE(); + + memset(session, 0, sizeof(dpaa2_sec_session)); + + priv = (struct ctxt_priv *)rte_zmalloc(NULL, + sizeof(struct ctxt_priv) + + sizeof(struct sec_flc_desc), + RTE_CACHE_LINE_SIZE); + + if (priv == NULL) { + DPAA2_SEC_ERR("No memory for priv CTXT"); + return -ENOMEM; + } + + priv->fle_pool = dev_priv->fle_pool; + flc = &priv->flc_desc[0].flc; + + /* find xfrm types */ + if (xform->type == RTE_CRYPTO_SYM_XFORM_CIPHER && xform->next == NULL) { + cipher_xform = &xform->cipher; + } else if (xform->type == RTE_CRYPTO_SYM_XFORM_CIPHER && + xform->next->type == RTE_CRYPTO_SYM_XFORM_AUTH) { + session->ext_params.aead_ctxt.auth_cipher_text = true; + cipher_xform = &xform->cipher; + auth_xform = &xform->next->auth; + } else if (xform->type == RTE_CRYPTO_SYM_XFORM_AUTH && + xform->next->type == RTE_CRYPTO_SYM_XFORM_CIPHER) { + session->ext_params.aead_ctxt.auth_cipher_text = false; + cipher_xform = &xform->next->cipher; + auth_xform = &xform->auth; + } else { + DPAA2_SEC_ERR("Invalid crypto type"); + return -EINVAL; + } + + session->ctxt_type = DPAA2_SEC_PDCP; + if (cipher_xform) { + session->cipher_key.data = rte_zmalloc(NULL, + cipher_xform->key.length, + RTE_CACHE_LINE_SIZE); + if (session->cipher_key.data == NULL && + cipher_xform->key.length > 0) { + DPAA2_SEC_ERR("No Memory for cipher key"); + rte_free(priv); + return -ENOMEM; + } + session->cipher_key.length = cipher_xform->key.length; + memcpy(session->cipher_key.data, cipher_xform->key.data, + cipher_xform->key.length); + session->dir = + (cipher_xform->op == RTE_CRYPTO_CIPHER_OP_ENCRYPT) ? + DIR_ENC : DIR_DEC; + session->cipher_alg = cipher_xform->algo; + } else { + session->cipher_key.data = NULL; + session->cipher_key.length = 0; + session->cipher_alg = RTE_CRYPTO_CIPHER_NULL; + session->dir = DIR_ENC; + } + + session->pdcp.domain = pdcp_xform->domain; + session->pdcp.bearer = pdcp_xform->bearer; + session->pdcp.pkt_dir = pdcp_xform->pkt_dir; + session->pdcp.sn_size = pdcp_xform->sn_size; +#ifdef ENABLE_HFN_OVERRIDE + session->pdcp.hfn_ovd = pdcp_xform->hfn_ovd; +#endif + session->pdcp.hfn = pdcp_xform->hfn; + session->pdcp.hfn_threshold = pdcp_xform->hfn_threshold; + + cipherdata.key = (size_t)session->cipher_key.data; + cipherdata.keylen = session->cipher_key.length; + cipherdata.key_enc_flags = 0; + cipherdata.key_type = RTA_DATA_IMM; + + switch (session->cipher_alg) { + case RTE_CRYPTO_CIPHER_SNOW3G_UEA2: + cipherdata.algtype = PDCP_CIPHER_TYPE_SNOW; + break; + case RTE_CRYPTO_CIPHER_ZUC_EEA3: + cipherdata.algtype = PDCP_CIPHER_TYPE_ZUC; + break; + case RTE_CRYPTO_CIPHER_AES_CTR: + cipherdata.algtype = PDCP_CIPHER_TYPE_AES; + break; + case RTE_CRYPTO_CIPHER_NULL: + cipherdata.algtype = PDCP_CIPHER_TYPE_NULL; + break; + default: + DPAA2_SEC_ERR("Crypto: Undefined Cipher specified %u", + session->cipher_alg); + goto out; + } + + /* Auth is only applicable for control mode operation. */ + if (pdcp_xform->domain == RTE_SECURITY_PDCP_MODE_CONTROL) { + if (pdcp_xform->sn_size != RTE_SECURITY_PDCP_SN_SIZE_5) { + DPAA2_SEC_ERR( + "PDCP Seq Num size should be 5 bits for cmode"); + goto out; + } + if (auth_xform) { + session->auth_key.data = rte_zmalloc(NULL, + auth_xform->key.length, + RTE_CACHE_LINE_SIZE); + if (session->auth_key.data == NULL && + auth_xform->key.length > 0) { + DPAA2_SEC_ERR("No Memory for auth key"); + rte_free(session->cipher_key.data); + rte_free(priv); + return -ENOMEM; + } + session->auth_key.length = auth_xform->key.length; + memcpy(session->auth_key.data, auth_xform->key.data, + auth_xform->key.length); + session->auth_alg = auth_xform->algo; + } else { + session->auth_key.data = NULL; + session->auth_key.length = 0; + session->auth_alg = RTE_CRYPTO_AUTH_NULL; + } + authdata.key = (size_t)session->auth_key.data; + authdata.keylen = session->auth_key.length; + authdata.key_enc_flags = 0; + authdata.key_type = RTA_DATA_IMM; + + switch (session->auth_alg) { + case RTE_CRYPTO_AUTH_SNOW3G_UIA2: + authdata.algtype = PDCP_AUTH_TYPE_SNOW; + break; + case RTE_CRYPTO_AUTH_ZUC_EIA3: + authdata.algtype = PDCP_AUTH_TYPE_ZUC; + break; + case RTE_CRYPTO_AUTH_AES_CMAC: + authdata.algtype = PDCP_AUTH_TYPE_AES; + break; + case RTE_CRYPTO_AUTH_NULL: + authdata.algtype = PDCP_AUTH_TYPE_NULL; + break; + default: + DPAA2_SEC_ERR("Crypto: Unsupported auth alg %u", + session->auth_alg); + goto out; + } + + if (session->dir == DIR_ENC) + bufsize = cnstr_shdsc_pdcp_c_plane_encap( + priv->flc_desc[0].desc, 1, swap, + pdcp_xform->hfn, + pdcp_xform->bearer, + pdcp_xform->pkt_dir, + pdcp_xform->hfn_threshold, + &cipherdata, &authdata, + 0); + else if (session->dir == DIR_DEC) + bufsize = cnstr_shdsc_pdcp_c_plane_decap( + priv->flc_desc[0].desc, 1, swap, + pdcp_xform->hfn, + pdcp_xform->bearer, + pdcp_xform->pkt_dir, + pdcp_xform->hfn_threshold, + &cipherdata, &authdata, + 0); + } else { + if (session->dir == DIR_ENC) + bufsize = cnstr_shdsc_pdcp_u_plane_encap( + priv->flc_desc[0].desc, 1, swap, + (enum pdcp_sn_size)pdcp_xform->sn_size, + pdcp_xform->hfn, + pdcp_xform->bearer, + pdcp_xform->pkt_dir, + pdcp_xform->hfn_threshold, + &cipherdata, 0); + else if (session->dir == DIR_DEC) + bufsize = cnstr_shdsc_pdcp_u_plane_decap( + priv->flc_desc[0].desc, 1, swap, + (enum pdcp_sn_size)pdcp_xform->sn_size, + pdcp_xform->hfn, + pdcp_xform->bearer, + pdcp_xform->pkt_dir, + pdcp_xform->hfn_threshold, + &cipherdata, 0); + } + + if (bufsize < 0) { + DPAA2_SEC_ERR("Crypto: Invalid buffer length"); + goto out; + } + + /* Enable the stashing control bit */ + DPAA2_SET_FLC_RSC(flc); + flc->word2_rflc_31_0 = lower_32_bits( + (size_t)&(((struct dpaa2_sec_qp *) + dev->data->queue_pairs[0])->rx_vq) | 0x14); + flc->word3_rflc_63_32 = upper_32_bits( + (size_t)&(((struct dpaa2_sec_qp *) + dev->data->queue_pairs[0])->rx_vq)); + + flc->word1_sdl = (uint8_t)bufsize; + + /* Set EWS bit i.e. enable write-safe */ + DPAA2_SET_FLC_EWS(flc); + /* Set BS = 1 i.e reuse input buffers as output buffers */ + DPAA2_SET_FLC_REUSE_BS(flc); + /* Set FF = 10; reuse input buffers if they provide sufficient space */ + DPAA2_SET_FLC_REUSE_FF(flc); + + session->ctxt = priv; + + return 0; +out: + rte_free(session->auth_key.data); + rte_free(session->cipher_key.data); + rte_free(priv); + return -1; +} + +static int dpaa2_sec_security_session_create(void *dev, struct rte_security_session_conf *conf, struct rte_security_session *sess, @@ -2573,6 +2827,10 @@ dpaa2_sec_security_session_create(void *dev, break; case RTE_SECURITY_PROTOCOL_MACSEC: return -ENOTSUP; + case RTE_SECURITY_PROTOCOL_PDCP: + ret = dpaa2_sec_set_pdcp_session(cdev, conf, + sess_private_data); + break; default: return -EINVAL; } diff --git a/drivers/crypto/dpaa2_sec/dpaa2_sec_priv.h b/drivers/crypto/dpaa2_sec/dpaa2_sec_priv.h index bce9633..5175110 100644 --- a/drivers/crypto/dpaa2_sec/dpaa2_sec_priv.h +++ b/drivers/crypto/dpaa2_sec/dpaa2_sec_priv.h @@ -137,6 +137,19 @@ struct dpaa2_sec_aead_ctxt { uint8_t auth_cipher_text; /**< Authenticate/cipher ordering */ }; +/* + * The structure is to be filled by user for PDCP Protocol + */ +struct dpaa2_pdcp_ctxt { + enum rte_security_pdcp_domain domain; /*!< Data/Control mode*/ + int8_t bearer; /*!< PDCP bearer ID */ + int8_t pkt_dir;/*!< PDCP Frame Direction 0:UL 1:DL*/ + int8_t hfn_ovd;/*!< Overwrite HFN per packet*/ + uint32_t hfn; /*!< Hyper Frame Number */ + uint32_t hfn_threshold; /*!< HFN Threashold for key renegotiation */ + uint8_t sn_size; /*!< Sequence number size, 7/12/15 */ +}; + typedef struct dpaa2_sec_session_entry { void *ctxt; uint8_t ctxt_type; @@ -160,15 +173,20 @@ typedef struct dpaa2_sec_session_entry { } auth_key; }; }; - struct { - uint16_t length; /**< IV length in bytes */ - uint16_t offset; /**< IV offset in bytes */ - } iv; - uint16_t digest_length; - uint8_t status; union { - struct dpaa2_sec_aead_ctxt aead_ctxt; - } ext_params; + struct { + struct { + uint16_t length; /**< IV length in bytes */ + uint16_t offset; /**< IV offset in bytes */ + } iv; + uint16_t digest_length; + uint8_t status; + union { + struct dpaa2_sec_aead_ctxt aead_ctxt; + } ext_params; + }; + struct dpaa2_pdcp_ctxt pdcp; + }; } dpaa2_sec_session; static const struct rte_cryptodev_capabilities dpaa2_sec_capabilities[] = { @@ -392,6 +410,162 @@ static const struct rte_cryptodev_capabilities dpaa2_sec_capabilities[] = { RTE_CRYPTODEV_END_OF_CAPABILITIES_LIST() }; +static const struct rte_cryptodev_capabilities dpaa2_pdcp_capabilities[] = { + { /* SNOW 3G (UIA2) */ + .op = RTE_CRYPTO_OP_TYPE_SYMMETRIC, + {.sym = { + .xform_type = RTE_CRYPTO_SYM_XFORM_AUTH, + {.auth = { + .algo = RTE_CRYPTO_AUTH_SNOW3G_UIA2, + .block_size = 16, + .key_size = { + .min = 16, + .max = 16, + .increment = 0 + }, + .digest_size = { + .min = 4, + .max = 4, + .increment = 0 + }, + .iv_size = { + .min = 16, + .max = 16, + .increment = 0 + } + }, } + }, } + }, + { /* SNOW 3G (UEA2) */ + .op = RTE_CRYPTO_OP_TYPE_SYMMETRIC, + {.sym = { + .xform_type = RTE_CRYPTO_SYM_XFORM_CIPHER, + {.cipher = { + .algo = RTE_CRYPTO_CIPHER_SNOW3G_UEA2, + .block_size = 16, + .key_size = { + .min = 16, + .max = 16, + .increment = 0 + }, + .iv_size = { + .min = 16, + .max = 16, + .increment = 0 + } + }, } + }, } + }, + { /* AES CTR */ + .op = RTE_CRYPTO_OP_TYPE_SYMMETRIC, + {.sym = { + .xform_type = RTE_CRYPTO_SYM_XFORM_CIPHER, + {.cipher = { + .algo = RTE_CRYPTO_CIPHER_AES_CTR, + .block_size = 16, + .key_size = { + .min = 16, + .max = 32, + .increment = 8 + }, + .iv_size = { + .min = 16, + .max = 16, + .increment = 0 + } + }, } + }, } + }, + { /* NULL (AUTH) */ + .op = RTE_CRYPTO_OP_TYPE_SYMMETRIC, + {.sym = { + .xform_type = RTE_CRYPTO_SYM_XFORM_AUTH, + {.auth = { + .algo = RTE_CRYPTO_AUTH_NULL, + .block_size = 1, + .key_size = { + .min = 0, + .max = 0, + .increment = 0 + }, + .digest_size = { + .min = 0, + .max = 0, + .increment = 0 + }, + .iv_size = { 0 } + }, }, + }, }, + }, + { /* NULL (CIPHER) */ + .op = RTE_CRYPTO_OP_TYPE_SYMMETRIC, + {.sym = { + .xform_type = RTE_CRYPTO_SYM_XFORM_CIPHER, + {.cipher = { + .algo = RTE_CRYPTO_CIPHER_NULL, + .block_size = 1, + .key_size = { + .min = 0, + .max = 0, + .increment = 0 + }, + .iv_size = { + .min = 0, + .max = 0, + .increment = 0 + } + }, }, + }, } + }, + { /* ZUC (EEA3) */ + .op = RTE_CRYPTO_OP_TYPE_SYMMETRIC, + {.sym = { + .xform_type = RTE_CRYPTO_SYM_XFORM_CIPHER, + {.cipher = { + .algo = RTE_CRYPTO_CIPHER_ZUC_EEA3, + .block_size = 16, + .key_size = { + .min = 16, + .max = 16, + .increment = 0 + }, + .iv_size = { + .min = 16, + .max = 16, + .increment = 0 + } + }, } + }, } + }, + { /* ZUC (EIA3) */ + .op = RTE_CRYPTO_OP_TYPE_SYMMETRIC, + {.sym = { + .xform_type = RTE_CRYPTO_SYM_XFORM_AUTH, + {.auth = { + .algo = RTE_CRYPTO_AUTH_ZUC_EIA3, + .block_size = 16, + .key_size = { + .min = 16, + .max = 16, + .increment = 0 + }, + .digest_size = { + .min = 4, + .max = 4, + .increment = 0 + }, + .iv_size = { + .min = 16, + .max = 16, + .increment = 0 + } + }, } + }, } + }, + + RTE_CRYPTODEV_END_OF_CAPABILITIES_LIST() +}; + static const struct rte_security_capability dpaa2_sec_security_cap[] = { { /* IPsec Lookaside Protocol offload ESP Transport Egress */ .action = RTE_SECURITY_ACTION_TYPE_LOOKASIDE_PROTOCOL, @@ -415,6 +589,24 @@ static const struct rte_security_capability dpaa2_sec_security_cap[] = { }, .crypto_capabilities = dpaa2_sec_capabilities }, + { /* PDCP Lookaside Protocol offload Data */ + .action = RTE_SECURITY_ACTION_TYPE_LOOKASIDE_PROTOCOL, + .protocol = RTE_SECURITY_PROTOCOL_PDCP, + .pdcp = { + .domain = RTE_SECURITY_PDCP_MODE_DATA, + .capa_flags = 0 + }, + .crypto_capabilities = dpaa2_pdcp_capabilities + }, + { /* PDCP Lookaside Protocol offload Control */ + .action = RTE_SECURITY_ACTION_TYPE_LOOKASIDE_PROTOCOL, + .protocol = RTE_SECURITY_PROTOCOL_PDCP, + .pdcp = { + .domain = RTE_SECURITY_PDCP_MODE_CONTROL, + .capa_flags = 0 + }, + .crypto_capabilities = dpaa2_pdcp_capabilities + }, { .action = RTE_SECURITY_ACTION_TYPE_NONE }