[][openwrt][mt7988][crypto][EIP197 DDK Porting]

[Description]
Add eip197 DDK(Driver Development Kit) and firmware
to eip197 package(crypto-eip)

eip197 DDK v5.6.1
eip197b-iew firmware v3.5

[Release-log]
N/A

Change-Id: I662327ecfbdac69742bf0b50362d7c28fc06372b
Reviewed-on: https://gerrit.mediatek.inc/c/openwrt/feeds/mtk_openwrt_feeds/+/7895272
diff --git a/package-21.02/kernel/crypto-eip/src/ddk/slad/DMABuf API Implementation Notes.txt b/package-21.02/kernel/crypto-eip/src/ddk/slad/DMABuf API Implementation Notes.txt
new file mode 100644
index 0000000..74aa78d
--- /dev/null
+++ b/package-21.02/kernel/crypto-eip/src/ddk/slad/DMABuf API Implementation Notes.txt
@@ -0,0 +1,118 @@
++=============================================================================+
+| Copyright (c) 2010-2020 Rambus, Inc. and/or its subsidiaries.               |
+|                                                                             |
+| Subject   : DMABuf API Implementation Notes                                 |
+| Product   : SLAD API                                                        |
+| Date      : 18 November, 2020                                               |
+|                                                                             |
++=============================================================================+
+
+SLAD API Implementation Notes : DMABuf API
+==========================================
+
+The SLAD API is a set of the API's one of which is the DMA Buffer
+Allocation (DMABuf) API. The driver implementation specifics of these APIs
+are described in short documents that serve as an addendum to the API
+specifications. This document describes the DMABuf API.
+
+
+DMABuf API
+----------
+
+The implementation of this API is fully re-entrant.
+
+Supported properties:
+     Alignment must be 1, 2, 4, 8, 16, 32, 64 or 128.
+     Bank is used to select a memory pool suitable for certain data types.
+     fCached can be used to indicate whether a DMA resource is cached.
+     Implementations of the DMAResource API can ignore the fCached parameter
+     and force all buffers to be allocated or registered either
+     cached or non-cached.
+
+DMABuf_NULLHandle:
+     Implemented as a NULL handle that can be assigned to a variable
+     of type DMABuf_Handle_t
+
+DMABuf_Handle_IsSame:
+     Two pointers to memory locations where the handles are stored
+     should be provided to this function as parameters.
+     The function will do byte comparison for the size of the handle type.
+
+DMABuf_Alloc:
+     Maximum buffer size supported is 1 megabyte.
+     Implementation uses the DMAResource API
+
+DMABuf_Register:
+     Supported values for AllocatorRef:
+     'N' to register a buffer that is not intended to be DMA-safe but for
+         which a DMABuf handle is desired nevertheless.
+     'R' to register a (subrange of) a buffer previously allocated with
+         DMABuf_Alloc. This buffer is known to be DMA-safe.
+     'k' to register a buffer allocated with Linux kmalloc.
+     'C' to register a coherent DMA-mapped buffer. The application must
+         provide the bus address in Alternative_p.
+
+     Alternative_p is only used with allocator ref 'C' and should be set to
+     "NULL" for other allocators.
+
+     All implementations of the DMAResource API support the 'N' and 'R'
+     allocators. The 'k' and 'C' allocators are only supported by
+     the Linux kernel implementation.
+
+DMABuf_Release:
+     The implementation is protected against invalid handles and also detects
+     and warns when handles are used after release (does not work well when
+     all available handles are in use).
+
+Banks:
+     The implementation supports several banks. The banks are configurable,
+     an example default configuration is as follows
+     (bank values in DMABuf_Properties_t):
+
+     - Bank 0 allocates buffers anywhere in physical RAM without restrictions.
+
+     - Bank 1 allocates buffers suitable for SA records and Transform records.
+       All these are required to lie in a single 4GB segment on 64-bit systems.
+
+     - Bank 2 allocates buffers suitable for flow records. All these are
+       required to lie in a single 4GB segment on 64-bit systems.
+
+The following properties of the static (fixed-size) DMA banks are implemented:
+
+     - One static bank contains one DMA pool;
+
+     - One DMA Pool contains a fixed compile-time configurable number of blocks;
+
+     - All blocks in one DMA pool have the same fixed compile-time configurable
+       size;
+
+     - The DMA pools for all the configured static banks are allocated
+       in DMAResource_Init() and freed in DMAResource_Uninit();
+
+     - DMA resources can be allocated in a static bank using
+       DMABuf_Alloc() and they must be freed using DMABuf_Release();
+
+     - Only sub-sets of DMA resources allocated in a static bank can be
+       registered in that bank using DMABuf_Register();
+       If the DMABuf_Register() function is called for a static
+       bank then it must use allocator type 82 ('R') and the required memory
+       block must belong to an already allocated DMA resource in that bank;
+
+     - The DMABuf_Register() function can be called for a static
+       bank also using allocator type 78 ('N') to register a DMA-unsafe buffer;
+       These DMA resources must be subsequently freed using the DMABuf_Release()
+       function;
+
+     - An "all-pool" DMA resource of size (nr_of_blocks * block_size) can be
+       allocated in a static bank using DMABuf_Alloc() where nr_of_blocks
+       and block_size are compile-time configuration parameters
+       (see HWPAL_DMARESOURCE_BANKS in c_dmares_gen.h);
+       The DMABuf_Register() function can be used to register
+       sub-sets of this DMA resource; Only one such a all-pool DMA resource
+       can be allocated in one static bank and must be freed using
+       DMABuf_Release() function;
+
+     - No other DMA resources can be allocated in a static bank
+       where an all-pool DMA resource is allocated.
+
+<end of document>
diff --git a/package-21.02/kernel/crypto-eip/src/ddk/slad/PCL API Implementation Notes.txt b/package-21.02/kernel/crypto-eip/src/ddk/slad/PCL API Implementation Notes.txt
new file mode 100644
index 0000000..c1db340
--- /dev/null
+++ b/package-21.02/kernel/crypto-eip/src/ddk/slad/PCL API Implementation Notes.txt
@@ -0,0 +1,150 @@
++=============================================================================+
+| Copyright (c) 2012-2020 Rambus, Inc. and/or its subsidiaries.               |
+|                                                                             |
+| Subject   : PCL API Implementation Notes                                    |
+| Product   : PCL API                                                         |
+| Date      : 18 November, 2020                                               |
+|                                                                             |
++=============================================================================+
+
+The SLAD API is a set of the APIs one of which is the Packet Classification
+(PCL) API. The driver implementation specifics of these APIs are
+described in short documents that serve as an addendum to the API
+specifications. This document describes the PCL API.
+
+This document uses the phrase "configurable" to indicate that a parameter or
+option is build-time configurable in the driver. Please refer to the User Guide
+of the driver for details.
+
+
+PCL API
+-------
+
+The PCL API manages two types of data structures relevant to the
+Packet Classification Engine: flow data structures and transform data
+structures.
+
+The PCL API is not used to submit packets (command descriptors) to the
+Packet Engine and to retrieve result descriptors (referring to
+processed packets). This is performed by the PEC API (see the PEC API
+Implementation Notes for details.
+
+Transform records
+     Transform records are allocated outside the Driver (using the
+     DMABuf API) and are initialized outside the Driver by the
+     Extended SA Builder. The Extended SA Builder is the SA Builder
+     that is compiled with the "Extended" configuration option
+     enabled. Transform records are represented by their DMABuf
+     Handle. They can be registered with PCL_Transform_Register() before
+     they are used and they are unregistered by
+     PCL_Transform_Unregister() after use. A subset of the contents
+     (sequence number and statistics) can be read with
+     PCL_Transform_Get_ReadOnly().
+
+Flow records
+     Flow Records are represented by an internal data structure
+     (represented by PCL_FlowHandle_t), which is invisible to the application.
+     The internal data structure is allocated within the Driver.
+     A DMA-safe buffer is associated with it and this is also allocated
+     within the Driver and invisible to the application.
+
+     The Driver makes use of the internal DMAResource API to allocate
+     the DMA-safe buffer and of an internal memory allocation API
+     (adapter_alloc.h) to allocate the data structure.
+
+     Allocation of flow records can be a time consuming operation and
+     it may not be allowed at all in certain situations (e.g. in
+     interrupt context). Therefore allocating and deallocating the
+     resources for a flow record is decoupled from adding and removing
+     flow records in the flow record table.
+
+     When a flow record is allocated with PCL_Flow_Alloc() its
+     resources (internal data structure and DMA-safe buffer) are
+     allocated, but the flow record is not initialized, is not part of
+     the flow table and is inaccessible to the Packet Classification
+     Engine. PCL_Flow_Add() initializes the record and adds it to a
+     lookup table. The size of the hash table from which flow lookup
+     is started has a configurable size.
+
+     PCL_Flow_Get_ReadOnly() reads the variable fields (last used time,
+     packet statistics) from a flow record. PCL_Flow_Remove() removes it
+     from the lookup table. At this time the resources are still allocated
+     and can be reused by another flow record. PCL_Flow_Release() deallocates
+     all flow resources.
+
+     This implementation does not implement the PCL_Flow_Lookup() function.
+
+Direct Transform Lookup
+     Transform records can be looked up directly (without the need for
+     a flow record). Use the function PCL_DTL_Transform_Add to add an
+     existing record (already registered with PCL_Transform_Register)
+     to the lookup table. PCL_DTL_Transform_Remove removes the transform
+     record from the lookup table again.
+
+Record invalidation
+     When flow records or transform records must be removed from the
+     system, they must also be removed from the record cache of the packet
+     engine, by means of a special command descriptor. The following
+     steps are required:
+     - Prevent the record from being looked up again. Use PCL_Flow_Remove
+       to remove a flow record from the lookup table. Use
+       PCL_DTL_Transform_Remove to remove a transform record from the lookup
+       table.
+     - Submit a special command descriptor containing a record invalidation
+       command with PEC_Packet_Put.
+     - Wait until the corresponding result descriptor is received with
+       PEC_Packet_Get.
+
+Byte ordering (endianness)
+     The transform buffers are considered arrays of 32-bit integers, in host-
+     native byte ordering. The driver will change the byte order if this is
+     required (configurable). The data buffers are considered byte arrays and
+     the driver will not touch these. Flow records are allocated and managed
+     entirely by the driver and their internal representation is never used by
+     the application.
+
+Bounce Buffers
+     The PCL API does not use bounce buffers. Transform buffers can be
+     allocated by the application in a DMA-safe way and buffers for the
+     flow table are allocated entirely within the Driver.
+
+Banks for DMA resources.
+     The PCL API requires that all DMA buffers for transform records
+     are allocated in Bank 1 (Bank parameter in
+     DMABuf_Properties_t). Internally the PCL adapter takes care of
+     allocating DMA-safe buffers for flow records in Bank 2. Memory
+     allocations in Bank 1 and Bank 2 are taken from special-purpose
+     memory pools. On 64-bit systems these pools are guaranteed to lay
+     in a 4GB address range. The PCL implementation takes care to convert
+     64-bit bus addresses for flow and transform records to 32-bit offsets
+     with respect to the base address of the pool.
+
+Concurrent Context Synchronization (CCS)
+     The PCL API implementation supports one single multi-threaded application,
+     allowing concurrent and independent use of PCL_Init/UnInit, PCL_Flow and
+     PCL_Transform functions. Multiple applications for the PCL API are
+     not supported.
+
+     The PCL API implementation provides synchronization mechanisms for
+     concurrent contexts invoking the API functions. The API can be used
+     by multi-threaded user-space or kernel-space applications. The latter
+     can invoke the API functions from the user process as well as from softirq
+     contexts. Mixing user process execution with softirq contexts is also
+     supported. Both Linux Uni-Processor (UP) and Symmetric Multi-Processor
+     (SMP) kernel configurations are supported.
+
+     All the PCL API functions allow for just one execution context at a time.
+     Note that although the API functions take the interface ID as an input
+     parameter it is not used in the current implementation.
+
+     The PCL API implementation serializes the access from concurrent execution
+     contexts to the classification device so having multiple contexts using
+     this API will not result in better performance.
+
+     When a function from the PCL API detects that it competes for a resource
+     already used at the time by another context executing the PCL code it will
+     not block and return PCL_STATUS_BUSY return code. The caller should try
+     calling this function again short after.
+
+
+<end of document>
diff --git a/package-21.02/kernel/crypto-eip/src/ddk/slad/PEC API Implementation Notes.txt b/package-21.02/kernel/crypto-eip/src/ddk/slad/PEC API Implementation Notes.txt
new file mode 100644
index 0000000..67c1e5e
--- /dev/null
+++ b/package-21.02/kernel/crypto-eip/src/ddk/slad/PEC API Implementation Notes.txt
@@ -0,0 +1,347 @@
++=============================================================================+
+| Copyright (c) 2010-2022 Rambus, Inc. and/or its subsidiaries.               |
+|                                                                             |
+| Subject   : PEC API Implementation Notes                                    |
+| Product   : SLAD API                                                        |
+| Date      : 02 December, 2022                                               |
+|                                                                             |
++=============================================================================+
+
+The SLAD API is a set of the API's one of which is the Packet Engine
+Control (PEC) API. The driver implementation specifics of these APIs are
+described in short documents that serve as an addendum to the API
+specifications. This document describes the PEC API.
+
+This document uses the phrase "configurable" to indicate that a parameter or
+option is build-time configurable in the driver. Please refer to the User Guide
+of the driver for details.
+
+
+PEC API
+-------
+
+One PEC implementation is available: ARM (Autonomous Ring Mode).
+
+Packet engine device
+     The PEC API implementation can support multiple packet processing
+     devices. These devices are identified by the interface ID parameter
+     in the PEC API functions and are sometimes referred to as rings.
+
+ARM mode
+     ARM mode uses DMA, can queue many jobs, handles commands and
+     results asynchronously (but always in-order) and also supports
+     fragmented data buffers (scatter / gather). The implementation
+     supports a single multi-threaded application per ring, allowing
+     concurrent and independent use of PEC_SA_Register,
+     PEC_SA_UnRegister, PEC_Packet_Put and PEC_Packet_Get. Both
+     PEC_Packet_Put and PEC_Packet_Get are not re-entrant, but
+     individual threads can use these functions concurrently.
+
+     Ensure that the Token Data, Packet Data and Context Data DMA
+     buffers are not re-used or freed by the execution context using
+     the PEC and DMABuf API's functions or by another execution
+     context until the processed result descriptor(s) referring to the
+     packet associated with these buffers is(are) fully processed by
+     the engine. This is required not only when in-place packet
+     transform is done using the same Packet Data DMA buffer as input
+     and output buffer but also when different DMA buffers are used
+     for the packet processing input and output data.
+
+Byte ordering (endianess)
+     The SA and Token buffers are considered arrays of 32bit integers,
+     in host-native byte ordering. The driver will change the byte
+     order if required if this is required (configurable).  The data
+     buffers are considered byte arrays and the driver will not touch
+     these.
+
+Bounce Buffers
+     Bounce Buffer support can be removed (configurable) from the driver to
+     reduce footprint.
+     For ARM mode, the implementation can bounce the SA, Token and data buffers
+     if these are not DMA-safe. This requires that the buffer was registered
+     using DMABuf_Register with an unsupported AllocatorRef.
+     When bouncing an SA buffer, it will be copied to a bounce buffer in
+     PEC_SA_Register and copied back by PEC_SA_UnRegister.
+     When bouncing a token buffer, a bounce buffer is created by
+     PEC_Packet_Put and released by PEC_Packet_Get.
+     When bouncing a data buffer (because either the source or destination
+     requires bouncing), a single bounce buffer is created by PEC_Packet_Put
+     based on the largest of the source and destination buffers. The engine
+     then performs an in-place operation in the bounce buffer. PEC_Packet_Get
+     copies the result to the destination buffer and releases the bounce
+     buffer.
+
+Descriptor grouping
+     PEC_Packet_Get and PEC_Packet_Put can process up to a
+     configurable number of descriptors in one call.
+
+Queuing
+     The ring can queue a configurable number of jobs. This can be set to
+     hundreds or even thousands, at the cost of some memory footprint. This
+     can avoid queuing in software and can also give better performance
+     (avoids idle engine due to empty ring).
+
+Scatter / Gather support
+     The ARM mode supports the scatter/gather extension (configurable) of the
+     PEC API.
+     If the SrcPkt_Handle in the command descriptor is a PEC SG_List, a
+     packet is assumed to used gather.
+     If the DstPkt_Handle in the command descriptor is a PEC SG_List, a
+     packet is assumed to used scatter.
+
+     The application is responsible for setting up both the gather list
+     in SrcPkt_Handle and the scatter list in DstPkt_Handle for each packet.
+     The application is responsible for allocating and releasing the individual
+     gather and scatter buffers.
+
+     The buffers used for the Scatter and/or Gather data are not bounced and
+     must be allocated and provided to the driver as DMA-safe buffers. This
+     can be achieved by using the driver's DMABuf API.
+
+Continuous Scatter mode
+     The ARM mode supports continuous scatter mode, which can be enabled per
+     ring. When continuous scatter mode is enabled for a ring, the result
+     packets are written to a sequence of destination buffers supplied by the
+     function PEC_Scatter_Preload(). Each result packet will occupy one
+     or more destination buffers (it will be scattered), depending on the
+     packet length and the sizes of the destination buffers.
+
+     It is not determined in advance which destination buffers will be
+     used for the result packet of a certain PEC_Packet_Put(). In a
+     typical use case, the application will pre-allocate a number of
+     buffers, each of the same size, and submits them to the
+     PEC_Scatter_Preload() function. It will regularly call
+     PEC_Scatter_Preload() to refill the supply of destination buffers, after
+     buffers are used by result packets.
+
+     Continuous scatter mode can be used even if the driver is configured
+     without scatter-gather support, but in that case each packet is required
+     to fit into a single destination buffer.
+
+     Continuous scatter mode is not supported with LAC flows.
+
+Redirection
+     Some configurations of the hardware support redirection. A packet,
+     originally submitted with PEC_Packet_Put() can have its result appear
+     on a different ring or on the inline interface. A packet, originally
+     received on the inline interface, can have its result appear on
+     a ring.
+
+     Any ring from which packets can be redirected, must be configured with
+     continuous scatter mode. Any ring towards which packets can be redirected,
+     must be configured with continuous scatter mode. When redirection is
+     possible, the sequence of packets submitted with PEC_Packet_Put() and
+     the sequence of result packets retrieved with PEC_Packet_Get()
+     on the same ring are no longer related to one another.
+
+     When a packet submitted with PEC_Packet_Put() is redirected to the
+     inline interface, no result descriptor will be received with
+     PEC_Packet_Get(). When a packet is received on the inline interface and
+     it is redirected to a ring, a result descriptor will appear with no
+     corresponding command descriptor in PEC_Packet_Put().
+
+Command Descriptor fields
+     User_p is fully supported on rings that do not use continuous scatter mode
+     and allows the user to match results to commands. User_p is not supported
+     on rings with continuous scatter mode.
+
+     The Control1 field is not used by this implementation. The PEC
+     API function PEC_CD_Control_Write is not implemented. Instead use
+     the IOToken API to pass an array of 32-bit words via the
+     InputToken_p field. The application is responsible for allocating
+     this array. The HW_Services field in the data structure passed to
+     the IOToken API specifies the exact packet flow or alternatively
+     it can specify a record invalidation command instead.  The values
+     to be filled in are provided by the firmware API.
+
+     Control2 can be used to specify the engine on which a packet must be
+     processed. This can be useful for protocols like TLS, where subsequent
+     packets of the same data stream must be processed on the same engine to
+     ensure in-order processing and in-order assignment of the sequence numbers.
+     Bit 5 in Control2 can be set if the engine is specified. The engine ID
+     is put in bits 4..0. Otherwise, the Control2 field should be all zero.
+
+     LAC packet flow:
+     - A valid Token_Handle must always be provided for each packet and
+       Token_WordCount must be set to the exact size in words of the token.
+     - SA_Handle1 must point to the main SA, which must be registered by
+       PEC_SA_Register.
+     - SA_Handle2 must be a null handle
+     - SA_WordCount is not used.
+     - DstPkt_Handle must always be provided, also for input-only operations.
+       When no destination buffer is required, it can be set to SrcPkt_Handle.
+     - The TokenHeaderWord passed to the IOToken API must be filled in.
+     - The Offset_ByteCount passed to the IOToken API is not used.
+
+     Other packet flows:
+     - Token_Handle is the null handle and Token_WordCount is zero.
+     - SA_Handle1 is the null handle if classification is used, else it is the
+       DMABuf handle representing a transform record.
+     - SA_Handle2 must be a null handle
+     - SA_WordCount is not used.
+     - DstPkt_Handle must always be provided (except for continuous
+       scatter mode), also for input-only operations.
+       When no destination buffer is required, it can be set to SrcPkt_Handle.
+       When continuous scatter mode is enabled, no destination handle must be
+       provided.
+     - The Offset_ByteCount field passed to the IOTOken API specifies the
+       number of bytes at the start of each packet that will be passed
+       unchanged and are not part of the packet to be processed.
+     - The NextHeader field passed to the IOToken API specifies the Next
+       Header field for IPsec packet flows that do not use network header
+       processing.
+
+     Record invalidation commands:
+     - Token_Handle is the null handle and Token_WordCount is zero.
+     - SA_Handle must point to the SA, transform or flow record to be
+       invalidated.
+     - SA_Handle2 must be a null handle
+     - SA_WordCount is not used.
+     - SrcPkt_Handle and DstPkt_Handle must both be null handles.
+     - SrcPkt_ByteCount is zero.
+
+     Note: A record invalidation command may be submitted via the PEC API
+           to the engine only when the engine has no packets being processed
+           for this record.
+
+Result Descriptor fields
+     User_p is fully supported on rings that do not use continuous scatter mode
+     and allows the user to match results to commands. User_p is not supported
+     on rings with continuous scatter mode.
+
+     SrcPkt_Handle and DstPkt_Handle are the same as provided in the command
+     descriptor. DstPkt_p is the host address for DstPkt_Handle.
+     On ring with continuous scatter mode, these fields are the NULL handle
+     and NULL pointer. On rings with continuous scatter mode, the NumParticles
+     field will be the number of scatter buffers used by the result packet.
+     At least one scatter buffer will be used, even if the result packet
+     has zero length. In some cases, the number of scatter buffer is
+     higher that would be required by the result packet.
+
+     DstPkt_ByteCount and Bypass_WordCount have been extracted from the engine
+     result descriptor as described in the engine datasheet under PE_LENGTH.
+     Bypass_WordCount should be the same as was provided in the command
+     descriptor.
+
+     For operations that do not require output buffers such as hash operations
+     the SrcPkt_Handle and DstPkt_Handle parameters in the
+     PEC_CommandDescriptor_t descriptor must be set equal by applications.
+     The advantage of this solution is that the driver still checks that
+     the output buffer handle is not NULL for all operations and can detect
+     errors in applications that do not do provide correct output buffer handle.
+     The disadvantage is that for hash operations this will degrade performance
+     because the driver will have to perform bounce buffer copy back to
+     the original buffer which is not needed and the driver will also
+     perform the PostDMA operation which is also not needed.
+
+     Status1 and Status2 reflect up to two words from the result token that
+     contain relevant status information. Use the function
+     PEC_RD_Status_Read to extract this information in an
+     engine-independent form.
+
+     More status information is passed in an array of 32-bit words via
+     the OutputToken_p field. The IOToken API can be used to extract
+     information from this array. The application is responsible for allocating
+     this array before the call to PEC_Packet_Get.
+
+Notify Requests (callbacks)
+     In ARM mode, two notify requests (commands and results) are
+     supported.  The result notification callback is only invoked in
+     interrupt mode.  The command notification callback is invoked
+     from within PEC_Packet_Get.
+
+SA Invalidation
+     In order to remove an SA from the system, it is required to carry out
+     the following operations in the specified order.
+     - Submit a special command descriptor with a transform record invalidation
+       command via PEC_Packet_Put(). This command will remove the record from
+       the record cache of the packet engine.
+     - Wait until the corresponding result descriptor is received via
+       PEC_Packet_Get().
+     - Call PEC_SA_UnRegister(). This command will take care of CPU cache
+       coherency, endianness conversion and bounce buffers, whichever applies.
+     - At this time the DMA buffer of the SA can be reused for a different
+       purpose or it can be freed.
+
+Banks for DMA resources
+     DMA-safe buffers for each data type must be allocated with the
+     correct Bank parameter (in DAMBuf_Properties_t).
+     Buffers for SA records must be allocated with Bank=1, all other
+     buffers must be allocated with Bank=0. On 64-bit hosts, SA buffers
+     must be allocated in a 4GB memory range, which is taken care of by
+     using Bank=1.
+
+SA resources
+     The functions PEC_SA_Register and PEC_SA_UnRegister take three
+     DMABuf handles as parameters. The first of these is always the
+     DMABuf handle representing the SA, the second is always a null
+     handle and the third is the null handle if the SA does not have
+     an ARC4 state record.
+
+     If the SA does have an ARC4 state record, the SA_Handle3
+     parameter represents the ARC4 state record. However this DMABuf
+     handle is supposed to represent the ARC4 state part within the SA
+     buffer. The application is supposed to use DMABuf_Register
+     (AllocatorRef=='R') to register a subset of the SA buffer as a
+     DMA Handle.
+
+Multiple Applications
+     The current implementation supports multiple rings (tested with
+     two rings) and each ring can be used by a separate application,
+     independently of other rings. The applications can run
+     concurrently, as long as each application uses a different
+     ring. The use of PEC_Packet_Put and PEC_Packet_Get by different
+     concurrent applications requires no locking. The implementation
+     of PEC_SA_UnRegister contains the required locking to support
+     multiple applications.
+
+Concurrent Context Synchronization (CCS)
+     The PEC API implementation supports a single multi-threaded application
+     per interface ID, allowing concurrent and independent use of
+     PEC_SA_Register, PEC_SA_UnRegister, PEC_Packet_Put and PEC_Packet_Get.
+     Multiple applications using the PEC API are also supported but they must
+     use different interface ID each.
+
+     Note: although the PEC_SA_Register and PEC_SA_UnRegister functions take
+           InterfaceId as an input parameter it is ignored by these functions
+           since this functions do nothing what is specific to an packet I/O
+           (ring) interface.
+
+     The PEC API implementation provides synchronization mechanisms for
+     concurrent contexts invoking the API functions. The API can be used
+     by multi-threaded user-space and kernel-space applications. The latter
+     can invoke the API functions from the user process as well as from softirq
+     contexts. Mixing user process execution with softirq contexts is also
+     supported. Both Linux Uni-Processor (UP) and Symmetric Multi-Processor
+     (SMP) kernel configurations are supported.
+
+     The PEC API allows for non-blocking synchronization concurrent context
+     invoking the API functions for different interface ID's. The only
+     exception are the PEC_Init and PEC_UnInit functions which both allow
+     for just one execution context at a time even for different interface ID's.
+     Also there should be no contexts executing the PEC_Packet_Put
+     or PEC_Packet_Get function code in order for the PEC_UnInit function
+     to succeed for the same interface ID.
+
+     For optimal utilization of the packet engine the PEC API user should allow
+     for concurrent contexts for the PEC_Packet_Put and PEC_Packet_Get
+     functions for the same interface ID. Note that having multiple concurrent
+     contexts invoking the PEC_Packet_Put function for the same interface ID
+     will not improve performance because this function does not allow more
+     than one execution context at a time for one interface ID. The same
+     applies for the PEC_Packet_Get function.
+
+     When a function from the PEC API detects that it competes for a resource
+     already used at the time by another context executing the PEC code it will
+     not block and return PEC_STATUS_BUSY return code. The caller should try
+     calling this function again short after.
+
+Debugging
+     The PEC_Put_Dump() and PEC_Get_Dump() functions can be used to print
+     the command ring and result ring administration and cached data as well
+     as the content of the ring buffers respectively. A slot corresponds to
+     a descriptor in the ring. These functions can be used to debug the packet
+     I/O functionality.
+
+
+<end of document>
diff --git a/package-21.02/kernel/crypto-eip/src/ddk/slad/adapter_dmabuf.c b/package-21.02/kernel/crypto-eip/src/ddk/slad/adapter_dmabuf.c
new file mode 100644
index 0000000..790f478
--- /dev/null
+++ b/package-21.02/kernel/crypto-eip/src/ddk/slad/adapter_dmabuf.c
@@ -0,0 +1,404 @@
+/* adapter_dmabuf.c
+ *
+ * Implementation of the DMA Buffer Allocation API.
+ */
+
+/*****************************************************************************
+* Copyright (c) 2008-2020 by Rambus, Inc. and/or its subsidiaries.
+*
+* This program is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 2 of the License, or
+* any later version.
+*
+* This program is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with this program. If not, see <http://www.gnu.org/licenses/>.
+*****************************************************************************/
+
+/*----------------------------------------------------------------------------
+ * This module implements (provides) the following interface(s):
+ */
+
+// DMABuf API
+#include "api_dmabuf.h"
+
+// Adapter DMABuf internal API
+#include "adapter_dmabuf.h"
+
+
+/*----------------------------------------------------------------------------
+ * This module uses (requires) the following interface(s):
+ */
+
+// Logging API
+#include "log.h"
+
+// Driver Framework DMAResource API
+#include "dmares_types.h"
+#include "dmares_mgmt.h"
+#include "dmares_buf.h"
+#include "dmares_addr.h"
+
+// Driver Framework Basic Definitions API
+#include "basic_defs.h"
+
+// Driver Framework C Run-Time Library API
+#include "clib.h"               // memcmp
+
+
+/*----------------------------------------------------------------------------
+ * Definitions and macros
+ */
+
+
+/*----------------------------------------------------------------------------
+ * Local variables
+ */
+
+/*----------------------------------------------------------------------------
+ * DMABuf_NULLHandle
+ *
+ */
+const DMABuf_Handle_t DMABuf_NULLHandle = { NULL };
+
+// Initial DMA buffer alignment setting
+static int Adapter_DMABuf_Alignment = ADAPTER_DMABUF_ALIGNMENT_INVALID;
+
+
+/*----------------------------------------------------------------------------
+ * Adapter_DMABuf_Handle2DMAResourceHandle
+ */
+DMAResource_Handle_t
+Adapter_DMABuf_Handle2DMAResourceHandle(
+        DMABuf_Handle_t Handle)
+{
+    if (Handle.p == NULL)
+    {
+        return NULL;
+    }
+    else
+    {
+        return (DMAResource_Handle_t)Handle.p;
+    }
+}
+
+
+/*----------------------------------------------------------------------------
+ * Adapter_DMAResource_Handle2DMABufHandle
+ */
+DMABuf_Handle_t
+Adapter_DMAResource_Handle2DMABufHandle(
+        DMAResource_Handle_t Handle)
+{
+    DMABuf_Handle_t DMABuf_Handle;
+
+    DMABuf_Handle.p = Handle;
+
+    return DMABuf_Handle;
+}
+
+
+/*----------------------------------------------------------------------------
+ * Adapter_DMAResource_IsForeignAllocated
+ */
+bool
+Adapter_DMAResource_IsForeignAllocated(
+        DMAResource_Handle_t Handle)
+{
+    DMAResource_Record_t * Rec_p;
+
+    Rec_p = DMAResource_Handle2RecordPtr(Handle);
+
+    if(!Rec_p)
+    {
+        return false;
+    }
+    else
+    {
+        return (Rec_p->AllocatorRef != 'A' && Rec_p->AllocatorRef != 'R');
+    }
+}
+
+
+/*----------------------------------------------------------------------------
+ * Adapter_DMAResource_HostAddr
+ */
+void *
+Adapter_DMAResource_HostAddr(
+        DMAResource_Handle_t Handle)
+{
+    DMAResource_AddrPair_t HostAddr;
+
+    DMAResource_Translate(Handle, DMARES_DOMAIN_HOST, &HostAddr);
+
+    return HostAddr.Address_p;
+}
+
+
+/*----------------------------------------------------------------------------
+ * Adapter_DMAResource_IsSubRangeOf
+ *
+ * Return true if the address range defined by Handle1 is
+ * within the address range defined by Handle2.
+ */
+bool
+Adapter_DMAResource_IsSubRangeOf(
+        const DMAResource_Handle_t Handle1,
+        const DMAResource_Handle_t Handle2)
+{
+    DMAResource_AddrPair_t AddrPair1, AddrPair2;
+
+    DMAResource_Translate(Handle1, DMARES_DOMAIN_HOST, &AddrPair1);
+    DMAResource_Translate(Handle2, DMARES_DOMAIN_HOST, &AddrPair2);
+
+    if (AddrPair1.Domain == AddrPair2.Domain)
+    {
+        const uint8_t * Addr1 = AddrPair1.Address_p;
+        const uint8_t * Addr2 = AddrPair2.Address_p;
+        const DMAResource_Record_t * const Rec1_p =
+                                DMAResource_Handle2RecordPtr(Handle1);
+        const DMAResource_Record_t * const Rec2_p =
+                                DMAResource_Handle2RecordPtr(Handle2);
+
+        if ((Rec1_p->Props.Size <= Rec2_p->Props.Size) &&
+            (Addr2 <= Addr1) &&
+            ((Addr1 + Rec1_p->Props.Size) <= (Addr2 + Rec2_p->Props.Size)))
+        {
+            return true;
+        }
+    }
+
+    return false;
+}
+
+
+/*----------------------------------------------------------------------------
+ * Adapter_DMAResource_Alignment_Set
+ */
+void
+Adapter_DMAResource_Alignment_Set(
+        const int Alignment)
+{
+    Adapter_DMABuf_Alignment = Alignment;
+
+    return;
+}
+
+
+/*----------------------------------------------------------------------------
+ * Adapter_DMAResource_Alignment_Get
+ */
+int
+Adapter_DMAResource_Alignment_Get(void)
+{
+    return Adapter_DMABuf_Alignment;
+}
+
+
+/*----------------------------------------------------------------------------
+ * DMABuf_Handle_IsSame
+ */
+bool
+DMABuf_Handle_IsSame(
+        const DMABuf_Handle_t * const Handle1_p,
+        const DMABuf_Handle_t * const Handle2_p)
+{
+    if (memcmp(Handle1_p, Handle2_p, sizeof(DMABuf_Handle_t)) == 0)
+    {
+        return true;
+    }
+
+    return false;
+}
+
+
+/*----------------------------------------------------------------------------
+ * DMABuf_Alloc
+ */
+DMABuf_Status_t
+DMABuf_Alloc(
+        const DMABuf_Properties_t RequestedProperties,
+        DMABuf_HostAddress_t * const Buffer_p,
+        DMABuf_Handle_t * const Handle_p)
+{
+    DMAResource_Handle_t DMAHandle;
+    DMAResource_AddrPair_t AddrPair;
+    DMAResource_Properties_t ActualProperties;
+
+    ZEROINIT(AddrPair);
+    ZEROINIT(ActualProperties);
+
+    if (Handle_p == NULL ||
+        Buffer_p == NULL)
+    {
+        return DMABUF_ERROR_BAD_ARGUMENT;
+    }
+
+    // initialize the output parameters
+    Handle_p->p = NULL;
+    Buffer_p->p = NULL;
+
+    ActualProperties.Size       = RequestedProperties.Size;
+    ActualProperties.Bank       = RequestedProperties.Bank;
+    ActualProperties.fCached    = RequestedProperties.fCached;
+
+    if (Adapter_DMABuf_Alignment != ADAPTER_DMABUF_ALIGNMENT_INVALID &&
+        RequestedProperties.Alignment < Adapter_DMABuf_Alignment)
+        ActualProperties.Alignment = Adapter_DMABuf_Alignment;
+    else
+        ActualProperties.Alignment = RequestedProperties.Alignment;
+
+    if( !DMAResource_Alloc(ActualProperties,&AddrPair,&DMAHandle) )
+    {
+        // set the output parameters
+        Handle_p->p = (void*)DMAHandle;
+        Buffer_p->p = AddrPair.Address_p;
+
+        LOG_INFO("DMABuf_Alloc: allocated handle=%p, host addr=%p, "
+                 "alignment requested/actual %d/%d, "
+                 "bank requested %d, cached requested %d\n",
+                 Handle_p->p,
+                 Buffer_p->p,
+                 RequestedProperties.Alignment,
+                 ActualProperties.Alignment,
+                 RequestedProperties.Bank,
+                 RequestedProperties.fCached);
+
+        return DMABUF_STATUS_OK;
+    }
+    else
+    {
+        return DMABUF_ERROR_OUT_OF_MEMORY;
+    }
+}
+
+
+/*----------------------------------------------------------------------------
+ * DMABuf_Register
+ */
+DMABuf_Status_t
+DMABuf_Register(
+        const DMABuf_Properties_t RequestedProperties,
+        void * Buffer_p,
+        void * Alternative_p,
+        const char AllocatorRef,
+        DMABuf_Handle_t * const Handle_p)
+{
+    DMAResource_Handle_t DMAHandle;
+    char ActualAllocator;
+    DMAResource_AddrPair_t AddrPair;
+    DMAResource_Properties_t ActualProperties;
+
+    ZEROINIT(AddrPair);
+    ZEROINIT(ActualProperties);
+
+    if (Handle_p == NULL ||
+        Buffer_p == NULL)
+    {
+        return DMABUF_ERROR_BAD_ARGUMENT;
+    }
+
+    // initialize the output parameter
+    Handle_p->p = NULL;
+
+    ActualProperties.Size       = RequestedProperties.Size;
+    ActualProperties.Bank       = RequestedProperties.Bank;
+    ActualProperties.fCached    = RequestedProperties.fCached;
+
+    if (Adapter_DMABuf_Alignment != ADAPTER_DMABUF_ALIGNMENT_INVALID &&
+        RequestedProperties.Alignment < Adapter_DMABuf_Alignment)
+        ActualProperties.Alignment = Adapter_DMABuf_Alignment;
+    else
+        ActualProperties.Alignment = RequestedProperties.Alignment;
+
+    ActualAllocator = AllocatorRef;
+
+    if( AllocatorRef == 'k'  || AllocatorRef == 'N' || AllocatorRef == 'R'
+        || AllocatorRef == 'C')
+    {
+        // 'N' is used to register buffers that do not need to be DMA-safe.
+        // 'R' is used to register (subranges of) buffers that are already
+        //     allocated with DMAResource_Alloc()/DMABuf_Alloc().
+        // 'k' is supported for Linux kmalloc() allocator only,
+        //     e.g. AllocatorRef = 'k' for streaming DMA mappings
+        // 'C' is supported for coherent buffers.
+        AddrPair.Domain     = DMARES_DOMAIN_HOST;
+        AddrPair.Address_p  = Buffer_p;
+    }
+    else if( AllocatorRef == 0 )
+    {
+        // Linux kmalloc() allocator is used,
+        // e.g. AllocatorRef = 'k' for streaming DMA mappings
+        ActualAllocator = 'k';
+        AddrPair.Domain     = DMARES_DOMAIN_HOST;
+        AddrPair.Address_p  = Buffer_p;
+    }
+    else
+    {
+        return DMABUF_ERROR_BAD_ARGUMENT;
+    }
+
+    if( DMAResource_CheckAndRegister(ActualProperties,AddrPair,
+            ActualAllocator,&DMAHandle) == 0 )
+    {
+        if( ActualAllocator == 'C' )
+        {
+            // Add bus address for the resource for AllocatorRef = 'C'
+            AddrPair.Domain     = DMARES_DOMAIN_BUS;
+            AddrPair.Address_p  = Alternative_p;
+
+            DMAResource_AddPair(DMAHandle,AddrPair);
+        }
+
+        // set the output parameters
+        Handle_p->p = (void*)DMAHandle;
+
+        LOG_INFO("DMABuf_Register: registered handle=%p, host addr=%p, "
+                 "allocator=%d, alignment requested/actual %d/%d, "
+                 "bank requested %d, cached requested %d\n",
+                 Handle_p->p,
+                 Buffer_p,
+                 AllocatorRef,
+                 RequestedProperties.Alignment,
+                 ActualProperties.Alignment,
+                 RequestedProperties.Bank,
+                 RequestedProperties.fCached);
+
+        return DMABUF_STATUS_OK;
+    }
+    else
+    {
+        return DMABUF_ERROR_OUT_OF_MEMORY;
+    }
+}
+
+
+/*----------------------------------------------------------------------------
+ * DMABuf_Release
+ */
+DMABuf_Status_t
+DMABuf_Release(
+        DMABuf_Handle_t Handle)
+{
+    DMAResource_Handle_t DMAHandle =
+            Adapter_DMABuf_Handle2DMAResourceHandle(Handle);
+
+    LOG_INFO("DMABuf_Release: handle to release=%p\n",Handle.p);
+
+    if( DMAResource_Release(DMAHandle) == 0 )
+    {
+        return DMABUF_STATUS_OK;
+    }
+    else
+    {
+        return DMABUF_ERROR_INVALID_HANDLE;
+    }
+}
+
+
+/* end of file adapter_dmabuf.c */
diff --git a/package-21.02/kernel/crypto-eip/src/ddk/slad/adapter_driver197_init.c b/package-21.02/kernel/crypto-eip/src/ddk/slad/adapter_driver197_init.c
new file mode 100644
index 0000000..369d167
--- /dev/null
+++ b/package-21.02/kernel/crypto-eip/src/ddk/slad/adapter_driver197_init.c
@@ -0,0 +1,113 @@
+/* adapter_driver197_init.c
+ *
+ * Adapter top level module, Security-IP-197 driver's entry point.
+ */
+
+/*****************************************************************************
+* Copyright (c) 2011-2020 by Rambus, Inc. and/or its subsidiaries.
+*
+* This program is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 2 of the License, or
+* any later version.
+*
+* This program is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with this program. If not, see <http://www.gnu.org/licenses/>.
+*****************************************************************************/
+
+/*----------------------------------------------------------------------------
+ * This module implements (provides) the following interface(s):
+ */
+
+#include "api_driver197_init.h"    // Driver Init API
+
+
+/*----------------------------------------------------------------------------
+ * This module uses (requires) the following interface(s):
+ */
+
+// Top-level Adapter configuration
+#include "cs_adapter.h"             // ADAPTER_DRIVER_NAME
+
+// Adapter Initialization API
+#include "adapter_init.h"           // Adapter_*
+#include "adapter_global_init.h"    // Adapter_Global_Init/UnInit()
+#include "adapter_global_cs_init.h" // Adapter_Global_Cs_Init/UnInit()
+#include "adapter_global_drbg_init.h" // Adapter_Global_DRBG_Init/UnInit()
+
+// Logging API
+#include "log.h"            // LOG_INFO
+
+
+/*----------------------------------------------------------------------------
+ * Driver197_Init
+ */
+int
+Driver197_Init(void)
+{
+    LOG_INFO("\n\t Driver197_Init \n");
+
+    LOG_INFO("%s driver: initializing\n", ADAPTER_DRIVER_NAME);
+
+    Adapter_Report_Build_Params();
+
+    if (!Adapter_Init())
+    {
+        return -1;
+    }
+
+    if (!Adapter_Global_Init())
+    {
+        Adapter_UnInit();
+        return -1;
+    }
+
+    if (!Adapter_Global_Cs_Init())
+    {
+        Adapter_Global_UnInit();
+        Adapter_UnInit();
+        return -1;
+    }
+
+    if (!Adapter_Global_DRBG_Init())
+    {
+        Adapter_Global_Cs_UnInit();
+        Adapter_Global_UnInit();
+        Adapter_UnInit();
+        return -1;
+    }
+
+    LOG_INFO("\n\t Driver197_Init done \n");
+
+    return 0;   // success
+}
+
+
+/*----------------------------------------------------------------------------
+ * Driver197_Exit
+ */
+void
+Driver197_Exit(void)
+{
+    LOG_INFO("\n\t Driver197_Exit \n");
+
+    LOG_INFO("%s driver: exit\n", ADAPTER_DRIVER_NAME);
+
+    Adapter_Global_DRBG_UnInit();
+    Adapter_Global_Cs_UnInit();
+    Adapter_Global_UnInit();
+    Adapter_UnInit();
+
+    LOG_INFO("\n\t Driver197_Exit done \n");
+}
+
+
+#include "adapter_driver197_init_ext.h"
+
+
+/* end of file adapter_driver197_init.c */
diff --git a/package-21.02/kernel/crypto-eip/src/ddk/slad/adapter_driver197_pec_init.c b/package-21.02/kernel/crypto-eip/src/ddk/slad/adapter_driver197_pec_init.c
new file mode 100644
index 0000000..0ff732f
--- /dev/null
+++ b/package-21.02/kernel/crypto-eip/src/ddk/slad/adapter_driver197_pec_init.c
@@ -0,0 +1,86 @@
+/* adapter_driver197_pec_init.c
+ *
+ * Adapter top level module, Security-IP-197 driver's entry point.
+ */
+
+/*****************************************************************************
+* Copyright (c) 2012-2020 by Rambus, Inc. and/or its subsidiaries.
+*
+* This program is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 2 of the License, or
+* any later version.
+*
+* This program is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with this program. If not, see <http://www.gnu.org/licenses/>.
+*****************************************************************************/
+
+/*----------------------------------------------------------------------------
+ * This module implements (provides) the following interface(s):
+ */
+
+#include "api_driver197_pec_init.h"    // Driver Init API
+
+
+/*----------------------------------------------------------------------------
+ * This module uses (requires) the following interface(s):
+ */
+
+// Top-level Adapter configuration
+#include "cs_adapter.h"             // ADAPTER_DRIVER_NAME
+
+// Adapter Initialization API
+#include "adapter_init.h"           // Adapter_*
+
+// Logging API
+#include "log.h"            // LOG_INFO
+
+
+/*----------------------------------------------------------------------------
+ * DrivDriver197_PEC_Init
+ */
+int
+Driver197_PEC_Init(void)
+{
+    LOG_INFO("\n\t Driver197_PEC_Init \n");
+
+    LOG_INFO("%s driver: initializing\n", ADAPTER_DRIVER_NAME);
+
+    Adapter_Report_Build_Params();
+
+    if (!Adapter_Init())
+    {
+        return -1;
+    }
+
+    LOG_INFO("\n\t Driver197_PEC_Init done \n");
+
+    return 0;   // success
+}
+
+
+/*----------------------------------------------------------------------------
+ * Driver197_PEC_Exit
+ */
+void
+Driver197_PEC_Exit(void)
+{
+    LOG_INFO("\n\t Driver197_PEC_Exit \n");
+
+    LOG_INFO("%s driver: exit\n", ADAPTER_DRIVER_NAME);
+
+    Adapter_UnInit();
+
+    LOG_INFO("\n\t Driver197_PEC_Exit done \n");
+}
+
+
+#include "adapter_driver197_pec_init_ext.h"
+
+
+/* end of file adapter_driver197_pec_init.c */
diff --git a/package-21.02/kernel/crypto-eip/src/ddk/slad/adapter_driver197_pec_pcl_init.c b/package-21.02/kernel/crypto-eip/src/ddk/slad/adapter_driver197_pec_pcl_init.c
new file mode 100644
index 0000000..cff7787
--- /dev/null
+++ b/package-21.02/kernel/crypto-eip/src/ddk/slad/adapter_driver197_pec_pcl_init.c
@@ -0,0 +1,86 @@
+/* adapter_driver197_pec_pcl_init.c
+ *
+ * Adapter top level module, Security-IP-197 driver's entry point.
+ */
+
+/*****************************************************************************
+* Copyright (c) 2012-2020 by Rambus, Inc. and/or its subsidiaries.
+*
+* This program is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 2 of the License, or
+* any later version.
+*
+* This program is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with this program. If not, see <http://www.gnu.org/licenses/>.
+*****************************************************************************/
+
+/*----------------------------------------------------------------------------
+ * This module implements (provides) the following interface(s):
+ */
+
+#include "api_driver197_pec_pcl_init.h"    // Driver Init API
+
+
+/*----------------------------------------------------------------------------
+ * This module uses (requires) the following interface(s):
+ */
+
+// Top-level Adapter configuration
+#include "cs_adapter.h"             // ADAPTER_DRIVER_NAME
+
+// Adapter Initialization API
+#include "adapter_init.h"           // Adapter_*
+
+// Logging API
+#include "log.h"            // LOG_INFO
+
+
+/*----------------------------------------------------------------------------
+ * DrivDriver197_PEC_PCL_Initer197_Init
+ */
+int
+Driver197_PEC_PCL_Init(void)
+{
+    LOG_INFO("\n\t Driver197_PEC_PCL_Init \n");
+
+    LOG_INFO("%s driver: initializing\n", ADAPTER_DRIVER_NAME);
+
+    Adapter_Report_Build_Params();
+
+    if (!Adapter_Init())
+    {
+        return -1;
+    }
+
+    LOG_INFO("\n\t Driver197_PEC_PCL_Init done \n");
+
+    return 0;   // success
+}
+
+
+/*----------------------------------------------------------------------------
+ * Driver197_PEC_PCL_Exit
+ */
+void
+Driver197_PEC_PCL_Exit(void)
+{
+    LOG_INFO("\n\t Driver197_PEC_PCL_Exit \n");
+
+    LOG_INFO("%s driver: exit\n", ADAPTER_DRIVER_NAME);
+
+    Adapter_UnInit();
+
+    LOG_INFO("\n\t Driver197_PEC_PCL_Exit done \n");
+}
+
+
+#include "adapter_driver197_pec_pcl_init_ext.h"
+
+
+/* end of file adapter_driver197_pec_pcl_init.c */
diff --git a/package-21.02/kernel/crypto-eip/src/ddk/slad/adapter_driver97_init.c b/package-21.02/kernel/crypto-eip/src/ddk/slad/adapter_driver97_init.c
new file mode 100644
index 0000000..ff6b3b4
--- /dev/null
+++ b/package-21.02/kernel/crypto-eip/src/ddk/slad/adapter_driver97_init.c
@@ -0,0 +1,92 @@
+/* adapter_driver97_init.c
+ *
+ * Adapter top level module, Security-IP-97 driver's entry point.
+ */
+
+/*****************************************************************************
+* Copyright (c) 2011-2020 by Rambus, Inc. and/or its subsidiaries.
+*
+* This program is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 2 of the License, or
+* any later version.
+*
+* This program is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with this program. If not, see <http://www.gnu.org/licenses/>.
+*****************************************************************************/
+
+/*----------------------------------------------------------------------------
+ * This module implements (provides) the following interface(s):
+ */
+
+#include "api_driver97_init.h"    // Driver Init API
+
+
+/*----------------------------------------------------------------------------
+ * This module uses (requires) the following interface(s):
+ */
+
+// Default Adapter configuration
+#include "cs_adapter.h"      // ADAPTER_DRIVER_NAME
+
+// Adapter Initialization API
+#include "adapter_init.h"   // Adapter_*
+#include "adapter_global_init.h"
+
+// Logging API
+#include "log.h"            // LOG_INFO
+
+
+/*----------------------------------------------------------------------------
+ * Driver97_Init
+ */
+int
+Driver97_Init(void)
+{
+    LOG_INFO("\n\t Driver97_Init \n");
+
+    LOG_INFO("%s driver: initializing\n", ADAPTER_DRIVER_NAME);
+
+    Adapter_Report_Build_Params();
+
+    if (!Adapter_Init())
+    {
+        return -1;
+    }
+
+    if (!Adapter_Global_Init())
+    {
+        Adapter_UnInit();
+        return -1;
+    }
+
+    LOG_INFO("\n\t Driver97_Init done \n");
+
+    return 0;   // success
+}
+
+
+/*----------------------------------------------------------------------------
+ * Driver97_Exit
+ */
+void
+Driver97_Exit(void)
+{
+    LOG_INFO("\n\t Driver97_Exit \n");
+
+    LOG_INFO("%s driver: exit\n", ADAPTER_DRIVER_NAME);
+
+    Adapter_Global_UnInit();
+    Adapter_UnInit();
+
+    LOG_INFO("\n\t Driver97_Exit done \n");
+}
+
+#include "adapter_driver97_init_ext.h"
+
+/* end of file adapter_driver97_init.c */
diff --git a/package-21.02/kernel/crypto-eip/src/ddk/slad/adapter_driver97_pec_init.c b/package-21.02/kernel/crypto-eip/src/ddk/slad/adapter_driver97_pec_init.c
new file mode 100644
index 0000000..65b099d
--- /dev/null
+++ b/package-21.02/kernel/crypto-eip/src/ddk/slad/adapter_driver97_pec_init.c
@@ -0,0 +1,86 @@
+/* adapter_driver97_pec_init.c
+ *
+ * Adapter top level module, Security-IP-97 driver's entry point.
+ */
+
+/*****************************************************************************
+* Copyright (c) 2012-2020 by Rambus, Inc. and/or its subsidiaries.
+*
+* This program is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 2 of the License, or
+* any later version.
+*
+* This program is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with this program. If not, see <http://www.gnu.org/licenses/>.
+*****************************************************************************/
+
+/*----------------------------------------------------------------------------
+ * This module implements (provides) the following interface(s):
+ */
+
+#include "api_driver97_pec_init.h"    // Driver Init API
+
+
+/*----------------------------------------------------------------------------
+ * This module uses (requires) the following interface(s):
+ */
+
+// Top-level Adapter configuration
+#include "cs_adapter.h"             // ADAPTER_DRIVER_NAME
+
+// Adapter Initialization API
+#include "adapter_init.h"           // Adapter_*
+
+// Logging API
+#include "log.h"            // LOG_INFO
+
+
+/*----------------------------------------------------------------------------
+ * DrivDriver97_PEC_Init
+ */
+int
+Driver97_PEC_Init(void)
+{
+    LOG_INFO("\n\t Driver97_PEC_Init \n");
+
+    LOG_INFO("%s driver: initializing\n", ADAPTER_DRIVER_NAME);
+
+    Adapter_Report_Build_Params();
+
+    if (!Adapter_Init())
+    {
+        return -1;
+    }
+
+    LOG_INFO("\n\t Driver97_PEC_Init done \n");
+
+    return 0;   // success
+}
+
+
+/*----------------------------------------------------------------------------
+ * Driver97_PEC_Exit
+ */
+void
+Driver97_PEC_Exit(void)
+{
+    LOG_INFO("\n\t Driver97_PEC_Exit \n");
+
+    LOG_INFO("%s driver: exit\n", ADAPTER_DRIVER_NAME);
+
+    Adapter_UnInit();
+
+    LOG_INFO("\n\t Driver97_PEC_Exit done \n");
+}
+
+
+#include "adapter_driver97_pec_init_ext.h"
+
+
+/* end of file adapter_driver97_pec_init.c */
diff --git a/package-21.02/kernel/crypto-eip/src/ddk/slad/adapter_global_cs_init.c b/package-21.02/kernel/crypto-eip/src/ddk/slad/adapter_global_cs_init.c
new file mode 100644
index 0000000..ab91673
--- /dev/null
+++ b/package-21.02/kernel/crypto-eip/src/ddk/slad/adapter_global_cs_init.c
@@ -0,0 +1,385 @@
+/* adapter_global_cs_init.c
+ *
+ * Initialize Global Classification Control functionality.
+ */
+
+/*****************************************************************************
+* Copyright (c) 2011-2021 by Rambus, Inc. and/or its subsidiaries.
+*
+* This program is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 2 of the License, or
+* any later version.
+*
+* This program is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with this program. If not, see <http://www.gnu.org/licenses/>.
+*****************************************************************************/
+
+/*----------------------------------------------------------------------------
+ * This module implements (provides) the following interface(s):
+ */
+
+#include "adapter_global_cs_init.h"
+
+
+/*----------------------------------------------------------------------------
+ * This module uses (requires) the following interface(s):
+ */
+
+// Default configuration
+#include "c_adapter_cs.h"
+
+// Global Control API
+#include "api_global_eip97.h"
+
+// Global Control Classification API
+#include "api_global_eip207.h"
+
+// Driver Framework Basic Definitions API
+#include "basic_defs.h"         // uint8_t, uint32_t, bool
+
+// Driver Framework C Library API
+#include "clib.h"               // memcpy, ZEROINIT
+
+#include "device_types.h"       // Device_Handle_t
+#include "device_mgmt.h"        // Device_find
+#include "log.h"                // Log API
+
+
+/*----------------------------------------------------------------------------
+ * Definitions and macros
+ */
+
+
+/*----------------------------------------------------------------------------
+ * Local variables
+ */
+
+static const uint32_t Global_IV_Data[4] = ADAPTER_CS_IV;
+
+
+/*----------------------------------------------------------------------------
+ * YesNo
+ *
+ * Convert boolean value to string.
+ */
+static const char *
+YesNo(
+        const bool b)
+{
+    if (b)
+        return "YES";
+    else
+        return "no";
+}
+
+
+/*----------------------------------------------------------------------------
+ * Adapter_Global_Cs_StatusReport()
+ *
+ * Obtain all available global status information from the Global Classification
+ * hardware and report it.
+ */
+static void
+Adapter_Global_Cs_StatusReport(void)
+{
+    GlobalControl207_Error_t rc;
+    unsigned int i;
+    unsigned int NofCEs;
+
+    LOG_INFO("\n\t\t Adapter_Global_Cs_StatusReport \n");
+
+    LOG_CRIT("Global Classification Control Status\n");
+    GlobalControl97_Interfaces_Get(&NofCEs, NULL, NULL, NULL);
+
+    for (i = 0; i < NofCEs; i++)
+    {
+        GlobalControl207_Status_t CE_Status;
+        GlobalControl207_GlobalStats_t CE_GlobalStats;
+        GlobalControl207_Clock_t CE_Clock;
+
+        ZEROINIT(CE_Status);
+        ZEROINIT(CE_GlobalStats);
+        ZEROINIT(CE_Clock);
+
+        LOG_CRIT("Classification Engine %d status\n", i);
+
+        rc = GlobalControl207_Status_Get(i, &CE_Status);
+        if (rc != EIP207_GLOBAL_CONTROL_NO_ERROR)
+            LOG_CRIT("%s: GlobalControl207_Status_Get() failed\n", __func__);
+        else
+        {
+            if (CE_Status.ICE.fPUE_EccCorr          ||
+                CE_Status.ICE.fPUE_EccDerr          ||
+                CE_Status.ICE.fFPP_EccCorr          ||
+                CE_Status.ICE.fFPP_EccDerr          ||
+                CE_Status.ICE.fTimerOverflow        ||
+                CE_Status.OCE.fPUE_EccCorr          ||
+                CE_Status.OCE.fPUE_EccDerr          ||
+                CE_Status.OCE.fFPP_EccCorr          ||
+                CE_Status.OCE.fFPP_EccDerr          ||
+                CE_Status.OCE.fTimerOverflow        ||
+                CE_Status.FLUE.Error1 != 0          ||
+                CE_Status.FLUE.Error2 != 0          ||
+                CE_Status.FRC[0].fDMAReadError      ||
+                CE_Status.FRC[0].fDMAWriteError     ||
+                CE_Status.FRC[0].fDataEccOflo       ||
+                CE_Status.FRC[0].fDataEccErr        ||
+                CE_Status.FRC[0].fAdminEccErr       ||
+                CE_Status.TRC[0].fDMAReadError      ||
+                CE_Status.TRC[0].fDMAWriteError     ||
+                CE_Status.TRC[0].fDataEccOflo       ||
+                CE_Status.TRC[0].fDataEccErr        ||
+                CE_Status.TRC[0].fAdminEccErr       ||
+                CE_Status.ARC4RC[0].fDMAReadError   ||
+                CE_Status.ARC4RC[0].fDMAWriteError  ||
+                CE_Status.ARC4RC[0].fDataEccOflo    ||
+                CE_Status.ARC4RC[0].fDataEccErr     ||
+                CE_Status.ARC4RC[0].fAdminEccErr)
+            {
+                LOG_CRIT("%s: error(s) detected\n", __func__);
+                LOG_CRIT(
+                 "\tICE Pull-Up ECC Correctable Err:        %s\n"
+                 "\tICE Pull-Up ECC Non-Corr Err:           %s\n"
+                 "\tICE Post-Processor ECC Correctable Err: %s\n"
+                 "\tICE Post-Processor ECC Non-Corr Err:    %s\n"
+                 "\tICE Timer ovf detected:                 %s\n"
+                 "\tOCE Pull-Up ECC Correctable Err:        %s\n"
+                 "\tOCE Pull-Up ECC Non-Corr Err:           %s\n"
+                 "\tOCE Post-Processor ECC Correctable Err: %s\n"
+                 "\tOCE Post-Processor ECC Non-Corr Err:    %s\n"
+                 "\tOCE Timer ovf detected:                 %s\n"
+                 "\tFLUE Err 1:                             %s (mask=0x%08x)\n"
+                 "\tFLUE Err 2:                             %s (mask=0x%08x)\n"
+                 "\tFRC#0 DMA Read Err:                     %s\n"
+                 "\tFRC#0 DMA Write Err:                    %s\n"
+                 "\tFRC#0 Data RAM ECC Non-Corr Ovf Err:    %s\n"
+                 "\tFRC#0 Data RAM ECC Non-Corr Err:        %s\n"
+                 "\tFRC#0 Admin RAM ECC Non-Corr Err:       %s\n"
+                 "\tTRC#0 DMA Read Err:                     %s\n"
+                 "\tTRC#0 DMA Write Err:                    %s\n"
+                 "\tTRC#0 Data RAM ECC Non-Corr Ovf Err:    %s\n"
+                 "\tTRC#0 Data RAM ECC Non-Corr Err:        %s\n"
+                 "\tTRC#0 Admin RAM ECC Non-Corr Err:       %s\n"
+                 "\tARC4RC#0 DMA Read Err:                  %s\n"
+                 "\tARC4RC#0 DMA Write Err:                 %s\n"
+                 "\tARC4RC#0 Data RAM ECC Non-Corr Ovf Err: %s\n"
+                 "\tARC4RC#0 Data RAM ECC Non-Corr Err:     %s\n"
+                 "\tARC4RC#0 Admin RAM ECC Non-Corr Err:    %s\n\n",
+                 YesNo(CE_Status.ICE.fPUE_EccCorr),
+                 YesNo(CE_Status.ICE.fPUE_EccDerr),
+                 YesNo(CE_Status.ICE.fFPP_EccCorr),
+                 YesNo(CE_Status.ICE.fFPP_EccDerr),
+                 YesNo(CE_Status.ICE.fTimerOverflow),
+                 YesNo(CE_Status.OCE.fPUE_EccCorr),
+                 YesNo(CE_Status.OCE.fPUE_EccDerr),
+                 YesNo(CE_Status.OCE.fFPP_EccCorr),
+                 YesNo(CE_Status.OCE.fFPP_EccDerr),
+                 YesNo(CE_Status.OCE.fTimerOverflow),
+                 YesNo(CE_Status.FLUE.Error1 != 0),
+                 CE_Status.FLUE.Error1,
+                 YesNo(CE_Status.FLUE.Error2 != 0),
+                 CE_Status.FLUE.Error2,
+                 YesNo(CE_Status.FRC[0].fDMAReadError),
+                 YesNo(CE_Status.FRC[0].fDMAWriteError),
+                 YesNo(CE_Status.FRC[0].fDataEccOflo),
+                 YesNo(CE_Status.FRC[0].fDataEccErr),
+                 YesNo(CE_Status.FRC[0].fAdminEccErr),
+                 YesNo(CE_Status.TRC[0].fDMAReadError),
+                 YesNo(CE_Status.TRC[0].fDMAWriteError),
+                 YesNo(CE_Status.TRC[0].fDataEccOflo),
+                 YesNo(CE_Status.TRC[0].fDataEccErr),
+                 YesNo(CE_Status.TRC[0].fAdminEccErr),
+                 YesNo(CE_Status.ARC4RC[0].fDMAReadError),
+                 YesNo(CE_Status.ARC4RC[0].fDMAWriteError),
+                 YesNo(CE_Status.ARC4RC[0].fDataEccOflo),
+                 YesNo(CE_Status.ARC4RC[0].fDataEccErr),
+                 YesNo(CE_Status.ARC4RC[0].fAdminEccErr));
+            }
+            else
+                LOG_CRIT("%s: all OK\n", __func__);
+            if (CE_Status.FRCStats[0].PrefetchExec ||
+                CE_Status.FRCStats[0].PrefetchBlock ||
+                CE_Status.FRCStats[0].PrefetchDMA ||
+                CE_Status.FRCStats[0].SelectOps ||
+                CE_Status.FRCStats[0].SelectDMA ||
+                CE_Status.FRCStats[0].IntDMAWrite ||
+                CE_Status.FRCStats[0].ExtDMAWrite ||
+                CE_Status.FRCStats[0].InvalidateOps)
+            {
+                LOG_CRIT("FRC statistics:\n"
+                         "\tPrefetches executed: %u\n"
+                         "\tPrefetches blocked:  %u\n"
+                         "\tPrefetches with DMA: %u\n"
+                         "\tSelect ops:          %u\n"
+                         "\tSelect ops with DMA: %u\n"
+                         "\tInternal DMA writes: %u\n"
+                         "\tExternal DMA writes: %u\n"
+                         "\tInvalidate ops:      %u\n"
+                         "\tDMA err flags        0x%x\n"
+                         "\tRead DMA errs:       %u\n"
+                         "\tWrite DMA errs:      %u\n"
+                         "\tECC invalidates:     %u\n"
+                         "\tECC Data RAM Corr:   %u\n"
+                         "\tECC Admin RAM Corr:  %u\n",
+                         (uint32_t)CE_Status.FRCStats[0].PrefetchExec,
+                         (uint32_t)CE_Status.FRCStats[0].PrefetchBlock,
+                         (uint32_t)CE_Status.FRCStats[0].PrefetchDMA,
+                         (uint32_t)CE_Status.FRCStats[0].SelectOps,
+                         (uint32_t)CE_Status.FRCStats[0].SelectDMA,
+                         (uint32_t)CE_Status.FRCStats[0].IntDMAWrite,
+                         (uint32_t)CE_Status.FRCStats[0].ExtDMAWrite,
+                         (uint32_t)CE_Status.FRCStats[0].InvalidateOps,
+                         (uint32_t)CE_Status.FRCStats[0].ReadDMAErrFlags,
+                         (uint32_t)CE_Status.FRCStats[0].ReadDMAErrors,
+                         (uint32_t)CE_Status.FRCStats[0].WriteDMAErrors,
+                         (uint32_t)CE_Status.FRCStats[0].InvalidateECC,
+                         (uint32_t)CE_Status.FRCStats[0].DataECCCorr,
+                         (uint32_t)CE_Status.FRCStats[0].AdminECCCorr);
+            }
+            if (CE_Status.TRCStats[0].PrefetchExec ||
+                CE_Status.TRCStats[0].PrefetchBlock ||
+                CE_Status.TRCStats[0].PrefetchDMA ||
+                CE_Status.TRCStats[0].SelectOps ||
+                CE_Status.TRCStats[0].SelectDMA ||
+                CE_Status.TRCStats[0].IntDMAWrite ||
+                CE_Status.TRCStats[0].ExtDMAWrite ||
+                CE_Status.TRCStats[0].InvalidateOps)
+            {
+                LOG_CRIT("TRC statistics:\n"
+                         "\tPrefetches executed: %u\n"
+                         "\tPrefetches blocked:  %u\n"
+                         "\tPrefetches with DMA: %u\n"
+                         "\tSelect ops:          %u\n"
+                         "\tSelect ops with DMA: %u\n"
+                         "\tInternal DMA writes: %u\n"
+                         "\tExternal DMA writes: %u\n"
+                         "\tInvalidate ops:      %u\n"
+                         "\tDMA err flags        0x%x\n"
+                         "\tRead DMA errs:       %u\n"
+                         "\tWrite DMA errs:      %u\n"
+                         "\tECC invalidates:     %u\n"
+                         "\tECC Data RAM Corr:   %u\n"
+                         "\tECC Admin RAM Corr:  %u\n",
+                         (uint32_t)CE_Status.TRCStats[0].PrefetchExec,
+                         (uint32_t)CE_Status.TRCStats[0].PrefetchBlock,
+                         (uint32_t)CE_Status.TRCStats[0].PrefetchDMA,
+                         (uint32_t)CE_Status.TRCStats[0].SelectOps,
+                         (uint32_t)CE_Status.TRCStats[0].SelectDMA,
+                         (uint32_t)CE_Status.TRCStats[0].IntDMAWrite,
+                         (uint32_t)CE_Status.TRCStats[0].ExtDMAWrite,
+                         (uint32_t)CE_Status.TRCStats[0].InvalidateOps,
+                         (uint32_t)CE_Status.TRCStats[0].ReadDMAErrFlags,
+                         (uint32_t)CE_Status.TRCStats[0].ReadDMAErrors,
+                         (uint32_t)CE_Status.TRCStats[0].WriteDMAErrors,
+                         (uint32_t)CE_Status.TRCStats[0].InvalidateECC,
+                         (uint32_t)CE_Status.TRCStats[0].DataECCCorr,
+                         (uint32_t)CE_Status.TRCStats[0].AdminECCCorr);
+            }
+        }
+
+        rc = GlobalControl207_GlobalStats_Get(i, &CE_GlobalStats);
+        if (rc != EIP207_GLOBAL_CONTROL_NO_ERROR)
+            LOG_CRIT("Adapter_Global_Cs_StatusReport: "
+                     "GlobalControl207_GlobalStats_Get() failed\n");
+        else
+            LOG_CRIT(
+                 "\tICE Dropped Packets Counter (low 32-bits):     0x%08x\n"
+                 "\tICE Dropped Packets Counter (high 32-bits):    0x%08x\n"
+                 "\tICE Inbound Packets Counter:                   0x%08x\n"
+                 "\tICE Outbound Packets Counter:                  0x%08x\n"
+                 "\tICE Inbound Octets Counter (low 32-bits):      0x%08x\n"
+                 "\tICE Inbound Octets Counter (high 32-bits):     0x%08x\n"
+                 "\tICE Outbound Octets Counter (low 32-bits):     0x%08x\n"
+                 "\tICE Outbound Octets Counter (high 32-bits):    0x%08x\n"
+                 "\tOCE Dropped Packets Counter (low 32-bits):     0x%08x\n"
+                 "\tOCE Dropped Packets Counter (high 32-bits):    0x%08x\n\n",
+                 CE_GlobalStats.ICE.DroppedPacketsCounter.Value64_Lo,
+                 CE_GlobalStats.ICE.DroppedPacketsCounter.Value64_Hi,
+                 CE_GlobalStats.ICE.InboundPacketsCounter,
+                 CE_GlobalStats.ICE.OutboundPacketCounter,
+                 CE_GlobalStats.ICE.InboundOctetsCounter.Value64_Lo,
+                 CE_GlobalStats.ICE.InboundOctetsCounter.Value64_Hi,
+                 CE_GlobalStats.ICE.OutboundOctetsCounter.Value64_Lo,
+                 CE_GlobalStats.ICE.OutboundOctetsCounter.Value64_Hi,
+                 CE_GlobalStats.OCE.DroppedPacketsCounter.Value64_Lo,
+                 CE_GlobalStats.OCE.DroppedPacketsCounter.Value64_Hi);
+
+        rc = GlobalControl207_ClockCount_Get(i, &CE_Clock);
+        if (rc != EIP207_GLOBAL_CONTROL_NO_ERROR)
+            LOG_CRIT("Adapter_Global_Cs_StatusReport: "
+                     "GlobalControl207_ClockCount_Get() failed\n");
+        else
+            LOG_CRIT(
+                 "\tICE Clock Count (low 32-bits):   0x%08x\n"
+                 "\tICE Clock Count (high 32-bits):  0x%08x\n"
+                 "\tOCE Clock Count (low 32-bits):   0x%08x\n"
+                 "\tOCE Clock Count (high 32-bits):  0x%08x\n\n",
+                 CE_Clock.ICE.Value64_Lo,
+                 CE_Clock.ICE.Value64_Hi,
+                 CE_Clock.OCE.Value64_Lo,
+                 CE_Clock.OCE.Value64_Hi);
+    } // for
+}
+
+
+/*----------------------------------------------------------------------------
+ * Adapter_Global_Cs_Init()
+ *
+ */
+bool
+Adapter_Global_Cs_Init(void)
+{
+    GlobalControl207_Error_t rc;
+    GlobalControl207_Capabilities_t Capabilities;
+    GlobalControl207_IV_t Data;
+
+    LOG_INFO("\n\t\t Adapter_Global_Cs_Init \n");
+
+    Data.IV[0] = Global_IV_Data[0];
+    Data.IV[1] = Global_IV_Data[1];
+    Data.IV[2] = Global_IV_Data[2];
+    Data.IV[3] = Global_IV_Data[3];
+
+    // Request the classification firmware download during the initialization
+    rc = GlobalControl207_Init(true, &Data);
+    if (rc != EIP207_GLOBAL_CONTROL_NO_ERROR)
+    {
+        LOG_CRIT("Adaptar_Global_Init: Classification initialization failed\n");
+        return false;
+    }
+
+    Capabilities.szTextDescription[0] = 0;
+
+    GlobalControl207_Capabilities_Get(&Capabilities);
+
+    LOG_CRIT("Global Classification capabilities: %s\n",
+             Capabilities.szTextDescription);
+
+    Adapter_Global_Cs_StatusReport();
+
+    return true;
+}
+
+
+/*----------------------------------------------------------------------------
+ * Adapter_Global_Cs_UnInit()
+ *
+ */
+void
+Adapter_Global_Cs_UnInit(void)
+{
+    LOG_INFO("\n\t\t Adapter_Global_Cs_UnInit \n");
+
+    Adapter_Global_Cs_StatusReport();
+
+    GlobalControl207_UnInit();
+}
+
+
+/* end of file adapter_global_cs_init.c */
diff --git a/package-21.02/kernel/crypto-eip/src/ddk/slad/adapter_global_drbg_init.c b/package-21.02/kernel/crypto-eip/src/ddk/slad/adapter_global_drbg_init.c
new file mode 100644
index 0000000..a210faa
--- /dev/null
+++ b/package-21.02/kernel/crypto-eip/src/ddk/slad/adapter_global_drbg_init.c
@@ -0,0 +1,209 @@
+/* adapter_global drbg_init.c
+ *
+ * Initialize Global DRBG Control functionality.
+ */
+
+/*****************************************************************************
+* Copyright (c) 2017-2020 by Rambus, Inc. and/or its subsidiaries.
+*
+* This program is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 2 of the License, or
+* any later version.
+*
+* This program is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with this program. If not, see <http://www.gnu.org/licenses/>.
+*****************************************************************************/
+
+/*----------------------------------------------------------------------------
+ * This module implements (provides) the following interface(s):
+ */
+
+#include "adapter_global_drbg_init.h"
+
+
+/*----------------------------------------------------------------------------
+ * This module uses (requires) the following interface(s):
+ */
+
+// Default configuration
+#include "c_adapter_global.h"
+
+// Global Control DRBG API
+#include "api_global_eip74.h"
+
+// Driver Framework Basic Definitions API
+#include "basic_defs.h"         // uint8_t, uint32_t, bool
+
+// Driver Framework C Library API
+#include "clib.h"               // memcpy, ZEROINIT
+
+// Log API
+#include "log.h"
+
+/*----------------------------------------------------------------------------
+ * Definitions and macros
+ */
+
+
+/*----------------------------------------------------------------------------
+ * Local variables
+ */
+
+static bool fDRBGPresent;
+
+#ifdef MODULE
+#include <linux/random.h>
+#define Global_DRBG_Entropy_Get(p) get_random_bytes(p, 48);
+#else
+#include <stdio.h>
+/*----------------------------------------------------------------------------
+ * Global_DRBG_Entropy_Get
+ *
+ * Get 48 bytes of entropy to initialize/reseed DRBG.
+ */
+static void
+Global_DRBG_Entropy_Get(
+    uint8_t * Key_p)
+{
+    FILE *rng = fopen("/dev/urandom","rb");
+    if (rng==NULL)
+    {
+        LOG_CRIT("/dev/urandom not available\n");
+        return;
+    }
+    if (fread(Key_p, 1, 48, rng) < 48)
+    {
+        LOG_CRIT("random data not read\n");
+        return;
+    }
+    Log_HexDump("Entropy",0,Key_p,48);
+
+    fclose(rng);
+}
+
+#endif
+
+/*----------------------------------------------------------------------------
+ * BoolToString()
+ *
+ * Convert boolean value to string.
+ */
+static const char *
+BoolToString(
+        const bool b)
+{
+    if (b)
+        return "true";
+    else
+        return "false";
+}
+
+
+/*----------------------------------------------------------------------------
+ * Adapter_Global_DRBG_StatusReport()
+ *
+ * Obtain all available global status information from the Global DRBG
+ * hardware and report it.
+ */
+void
+Adapter_Global_DRBG_StatusReport(void)
+{
+    GlobalControl74_Error_t Rc;
+    GlobalControl74_Status_t Status;
+
+    LOG_INFO("DA_GC: Global_DRBG_StatusReport \n");
+
+    LOG_CRIT("DA_GC: Global DRBG Status\n");
+    Rc = GlobalControl74_Status_Get(&Status);
+    if (Rc != GLOBAL_CONTROL_EIP74_NO_ERROR)
+    {
+        LOG_CRIT("EIP74 status get error\n");
+        return;
+    }
+    Log_FormattedMessage(
+        "EIP 74 status: GenBlockCount=%u StuckOut=%s\n"
+        "\t\tNotInitialized=%s ReseedErr=%s ReseedWarn=%s\n"
+        "\t\tInstantiated=%s AvailableCount=%u\n",
+        Status.GenerateBlockCount,
+        BoolToString(Status.fStuckOut),
+        BoolToString(Status.fNotInitialized),
+        BoolToString(Status.fReseedError),
+        BoolToString(Status.fReseedWarning),
+        BoolToString(Status.fInstantiated),
+        Status.AvailableCount);
+}
+
+
+/*----------------------------------------------------------------------------
+ * Adapter_Global_DRBG_Init()
+ *
+ */
+bool
+Adapter_Global_DRBG_Init(void)
+{
+    GlobalControl74_Error_t rc;
+    GlobalControl74_Capabilities_t Capabilities;
+    GlobalControl74_Configuration_t Configuration;
+    uint8_t Entropy[48];
+
+    LOG_INFO("DA_GC: Global_DRBG_Init \n");
+
+    ZEROINIT(Configuration);
+    Configuration.fStuckOut = true;
+
+    Global_DRBG_Entropy_Get(Entropy);
+
+    rc = GlobalControl74_Init(&Configuration, Entropy);
+    if (rc == GLOBAL_CONTROL_EIP74_ERROR_NOT_IMPLEMENTED)
+    {
+        LOG_CRIT("EIP74 not present\n");
+        return true;
+    }
+    if (rc == GLOBAL_CONTROL_EIP74_NO_ERROR)
+    {
+        fDRBGPresent = true;
+        Log_FormattedMessage("EIP74 initialized OK\n");
+    }
+    else
+    {
+        LOG_CRIT("EIP74 initialization error\n");
+    }
+
+    Capabilities.szTextDescription[0] = 0;
+
+    GlobalControl74_Capabilities_Get(&Capabilities);
+
+    LOG_CRIT("DA_GC: Global DRBG capabilities: %s\n",
+             Capabilities.szTextDescription);
+
+    Adapter_Global_DRBG_StatusReport();
+
+    return true;
+}
+
+
+/*----------------------------------------------------------------------------
+ * Adapter_Global_DRBG_UnInit()
+ *
+ */
+void
+Adapter_Global_DRBG_UnInit(void)
+{
+    LOG_INFO("\n\t\t Adapter_Global_DRBG_UnInit \n");
+
+    if (fDRBGPresent)
+    {
+        Adapter_Global_DRBG_StatusReport();
+
+        GlobalControl74_UnInit();
+    }
+}
+
+
+/* end of file adapter_global_drbg_init.c */
diff --git a/package-21.02/kernel/crypto-eip/src/ddk/slad/adapter_global_driver197_init.c b/package-21.02/kernel/crypto-eip/src/ddk/slad/adapter_global_driver197_init.c
new file mode 100644
index 0000000..158dc38
--- /dev/null
+++ b/package-21.02/kernel/crypto-eip/src/ddk/slad/adapter_global_driver197_init.c
@@ -0,0 +1,87 @@
+/* adapter_global_driver197_init.c
+ *
+ * Adapter top level module,
+ * Security-IP-197 global control driver's entry point.
+ */
+
+/*****************************************************************************
+* Copyright (c) 2012-2020 by Rambus, Inc. and/or its subsidiaries.
+*
+* This program is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 2 of the License, or
+* any later version.
+*
+* This program is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with this program. If not, see <http://www.gnu.org/licenses/>.
+*****************************************************************************/
+
+/*----------------------------------------------------------------------------
+ * This module implements (provides) the following interface(s):
+ */
+
+#include "api_global_driver197_init.h"    // Driver Init API
+
+
+/*----------------------------------------------------------------------------
+ * This module uses (requires) the following interface(s):
+ */
+
+// Top-level Adapter configuration
+#include "c_adapter_global.h"             // ADAPTER_GLOBAL_DRIVER_NAME
+
+// Adapter Initialization API - for global only tjc
+#include "adapter_global_control_init.h"  // Adapter_* for global only
+
+// Logging API
+#include "log.h"                          // LOG_INFO
+
+
+/*----------------------------------------------------------------------------
+ * Driver197_Global_Init
+ */
+int
+Driver197_Global_Init(void)
+{
+    LOG_INFO("\n\t Driver197_Global_Init \n");
+
+    LOG_INFO("%s driver: initializing\n", ADAPTER_GLOBAL_DRIVER_NAME);
+
+    Adapter_Global_Control_Report_Build_Params();
+
+    if (!Adapter_Global_Control_Init())
+    {
+        return -1;
+    }
+
+    LOG_INFO("\n\t Driver197_Global_Init done \n");
+
+    return 0;   // success
+}
+
+
+/*----------------------------------------------------------------------------
+ * Driver197_Global_Exit
+ */
+void
+Driver197_Global_Exit(void)
+{
+    LOG_INFO("\n\t Driver197_Global_Exit \n");
+
+    LOG_INFO("%s driver: exit\n", ADAPTER_GLOBAL_DRIVER_NAME);
+
+    Adapter_Global_Control_UnInit();
+
+    LOG_INFO("\n\t Driver197_Globt done \n");
+}
+
+
+#include "adapter_driver197_global_init_ext.h"
+
+
+/* end of file adapter_global_driver197_init.c */
diff --git a/package-21.02/kernel/crypto-eip/src/ddk/slad/adapter_global_driver97_init.c b/package-21.02/kernel/crypto-eip/src/ddk/slad/adapter_global_driver97_init.c
new file mode 100644
index 0000000..bb38914
--- /dev/null
+++ b/package-21.02/kernel/crypto-eip/src/ddk/slad/adapter_global_driver97_init.c
@@ -0,0 +1,87 @@
+/* adapter_global_driver97_init.c
+ *
+ * Adapter top level module,
+ * Security-IP-97 global control driver's entry point.
+ */
+
+/*****************************************************************************
+* Copyright (c) 2012-2020 by Rambus, Inc. and/or its subsidiaries.
+*
+* This program is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 2 of the License, or
+* any later version.
+*
+* This program is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with this program. If not, see <http://www.gnu.org/licenses/>.
+*****************************************************************************/
+
+/*----------------------------------------------------------------------------
+ * This module implements (provides) the following interface(s):
+ */
+
+#include "api_global_driver97_init.h"    // Driver Init API
+
+
+/*----------------------------------------------------------------------------
+ * This module uses (requires) the following interface(s):
+ */
+
+// Top-level Adapter configuration
+#include "c_adapter_global.h"             // ADAPTER_GLOBAL_DRIVER_NAME
+
+// Adapter Initialization API - for global only tjc
+#include "adapter_global_control_init.h"  // Adapter_* for global only
+
+// Logging API
+#include "log.h"                          // LOG_INFO
+
+
+/*----------------------------------------------------------------------------
+ * Driver97_Global_Init
+ */
+int
+Driver97_Global_Init(void)
+{
+    LOG_INFO("\n\t Driver97_Global_Init \n");
+
+    LOG_INFO("%s driver: initializing\n", ADAPTER_GLOBAL_DRIVER_NAME);
+
+    Adapter_Global_Control_Report_Build_Params();
+
+    if (!Adapter_Global_Control_Init())
+    {
+        return -1;
+    }
+
+    LOG_INFO("\n\t Driver97_Global_Init done \n");
+
+    return 0;   // success
+}
+
+
+/*----------------------------------------------------------------------------
+ * Driver97_Global_Exit
+ */
+void
+Driver97_Global_Exit(void)
+{
+    LOG_INFO("\n\t Driver97_Global_Exit \n");
+
+    LOG_INFO("%s driver: exit\n", ADAPTER_GLOBAL_DRIVER_NAME);
+
+    Adapter_Global_Control_UnInit();
+
+    LOG_INFO("\n\t Driver97_Global_Exit done \n");
+}
+
+
+#include "adapter_driver97_global_init_ext.h"
+
+
+/* end of file adapter_global_driver97_init.c */
diff --git a/package-21.02/kernel/crypto-eip/src/ddk/slad/adapter_global_eip207.c b/package-21.02/kernel/crypto-eip/src/ddk/slad/adapter_global_eip207.c
new file mode 100644
index 0000000..11b8139
--- /dev/null
+++ b/package-21.02/kernel/crypto-eip/src/ddk/slad/adapter_global_eip207.c
@@ -0,0 +1,740 @@
+/* adapter_global_eip207.c
+ *
+ * Security-IP-207 Global Control Adapter
+ */
+
+/*****************************************************************************
+* Copyright (c) 2011-2022 by Rambus, Inc. and/or its subsidiaries.
+*
+* This program is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 2 of the License, or
+* any later version.
+*
+* This program is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with this program. If not, see <http://www.gnu.org/licenses/>.
+*****************************************************************************/
+
+/*----------------------------------------------------------------------------
+ * This module implements (provides) the following interface(s):
+ */
+
+// Classification (EIP-207) Global Control Initialization API
+#include "api_global_eip207.h"
+
+// Classification (EIP-207) Global Control Status API
+#include "api_global_status_eip207.h"
+
+
+/*----------------------------------------------------------------------------
+ * This module uses (requires) the following interface(s):
+ */
+#include "c_adapter_cs.h"
+
+#ifndef GLOBALCONTROL_BUILD
+#include "adapter_rc_eip207.h"  // Record Cache EIP-207 interface to pass
+                                // config params from Global Control
+#endif
+
+// Global Control API
+#include "api_global_eip97.h"
+
+// Driver Framework Basic Definitions API
+#include "basic_defs.h"          // uint8_t, uint32_t, bool
+
+// Driver Framework C Library API
+#include "clib.h"                // memcpy, ZEROINIT
+
+// EIP-207 Driver Library Global Control API
+#include "eip207_global_init.h"  // Init/Uninit/Status/FW download
+
+// EIP-207 Driver Library Global Control API: Configuration
+#include "eip207_global_config.h" // EIP207_Global_MetaData_Configure
+
+#include "device_types.h"        // Device_Handle_t
+#include "device_mgmt.h"         // Device_find
+
+// Logging API
+#include "log.h"                 // Log_*, LOG_*
+
+// Firmware load API.
+#include "adapter_firmware.h"
+#include "firmware_eip207_api_dwld.h"
+
+// Runtime Power Management Device Macros API
+#include "rpm_device_macros.h"  // RPM_*
+
+// EIP97_Supported_Funcs_Get()
+#include "eip97_global_init.h"
+
+
+/*----------------------------------------------------------------------------
+ * Definitions and macros
+ */
+
+/* Support legacy firmware packages without name parameters in download API */
+#ifndef FIRMWARE_EIP207_IPUE_NAME
+#define FIRMWARE_EIP207_IPUE_NAME "firmware_eip207_ipue.bin"
+#define FIRMWARE_EIP207_IFPP_NAME "firmware_eip207_ifpp.bin"
+#endif
+#ifndef FIRMWARE_EIP207_OPUE_NAME
+#define FIRMWARE_EIP207_OPUE_NAME "firmware_eip207_opue.bin"
+#define FIRMWARE_EIP207_OFPP_NAME "firmware_eip207_ofpp.bin"
+#endif
+
+/*----------------------------------------------------------------------------
+ * Local variables
+ */
+
+static EIP207_Global_IOArea_t Global_IOArea;
+static bool Global_IsInitialized;
+
+// Cached values during initialization will be used for RPM device resume
+static EIP207_Global_CacheConfig_t RC_Conf;
+static EIP207_Global_FLUEConfig_t FLUE_Conf;
+
+static const  GlobalControl207_Capabilities_t Global_CapabilitiesString =
+{
+    "EIP-207 v_._p_  #cache sets=__ #lookup tables=__" // szTextDescription
+};
+
+
+/*----------------------------------------------------------------------------
+ * YesNo
+ */
+static const char *
+YesNo(
+        const bool b)
+{
+    if (b)
+        return "Yes";
+    else
+        return "No";
+}
+
+
+/*----------------------------------------------------------------------------
+ * GlobalControl207Lib_Init
+ *
+ */
+static int
+GlobalControl207Lib_Init(void)
+{
+    EIP207_Global_Error_t rc;
+    unsigned int i;
+
+    LOG_INFO("\n\t\t\t\t EIP207_Global_Init \n");
+
+    rc = EIP207_Global_Init(&Global_IOArea,
+                            Device_Find(ADAPTER_CS_GLOBAL_DEVICE_NAME),
+                            &RC_Conf,
+                            &FLUE_Conf);
+
+    for (i = 0; i < EIP207_GLOBAL_MAX_NOF_CACHE_SETS_TO_USE; i++)
+    {
+        Log_FormattedMessage("GlobalControl_EIP207_Init cache set %d:\n"
+                             "\t\tFRC  AdminWords=%5d DataWords=%5d\n"
+                             "\t\tTRC  AdminWords=%5d DataWords=%5d\n"
+                             "\t\tARC4 AdminWords=%5d DataWords=%5d\n",
+                             i,
+                             RC_Conf.FRC[i].AdminWordCount,
+                             RC_Conf.FRC[i].DataWordCount,
+                             RC_Conf.TRC[i].AdminWordCount,
+                             RC_Conf.TRC[i].DataWordCount,
+                             RC_Conf.ARC4[i].AdminWordCount,
+                             RC_Conf.ARC4[i].DataWordCount);
+    }
+
+    if (rc != EIP207_GLOBAL_NO_ERROR)
+    {
+        LOG_CRIT("%s: EIP207_Global_Init() returned error %d\n", __func__, rc);
+        return -1; // error
+    }
+
+    return 0; // success
+}
+
+
+/*----------------------------------------------------------------------------
+ * GlobalControl207Lib_Firmware_Load
+ *
+ */
+static int
+GlobalControl207Lib_Firmware_Load(bool fVerbose)
+{
+    Adapter_Firmware_t IPUE_Handle, IFPP_Handle,OPUE_Handle, OFPP_Handle;
+    EIP207_Firmware_t IPUE_Firmware, IFPP_Firmware;
+    EIP207_Firmware_t OPUE_Firmware, OFPP_Firmware;
+    EIP207_Global_Error_t rc;
+
+    ZEROINIT(IPUE_Firmware);
+    ZEROINIT(IFPP_Firmware);
+    ZEROINIT(OPUE_Firmware);
+    ZEROINIT(OFPP_Firmware);
+
+#ifdef FIRMWARE_EIP207_VERSION_MAJOR
+    // If version numbers are provided, then fill them in, so they
+    // will be checked against the actual firmware, else leave them
+    // at zero.
+    IPUE_Firmware.Major = FIRMWARE_EIP207_VERSION_MAJOR;
+    IPUE_Firmware.Minor = FIRMWARE_EIP207_VERSION_MINOR;
+    IPUE_Firmware.PatchLevel = FIRMWARE_EIP207_VERSION_PATCH;
+    IFPP_Firmware.Major = FIRMWARE_EIP207_VERSION_MAJOR;
+    IFPP_Firmware.Minor = FIRMWARE_EIP207_VERSION_MINOR;
+    IFPP_Firmware.PatchLevel = FIRMWARE_EIP207_VERSION_PATCH;
+    OPUE_Firmware.Major = FIRMWARE_EIP207_VERSION_MAJOR;
+    OPUE_Firmware.Minor = FIRMWARE_EIP207_VERSION_MINOR;
+    OPUE_Firmware.PatchLevel = FIRMWARE_EIP207_VERSION_PATCH;
+    OFPP_Firmware.Major = FIRMWARE_EIP207_VERSION_MAJOR;
+    OFPP_Firmware.Minor = FIRMWARE_EIP207_VERSION_MINOR;
+    OFPP_Firmware.PatchLevel = FIRMWARE_EIP207_VERSION_PATCH;
+#endif
+    IPUE_Handle = Adapter_Firmware_Acquire(FIRMWARE_EIP207_IPUE_NAME,
+                                           &IPUE_Firmware.Image_p,
+                                           &IPUE_Firmware.ImageWordCount);
+    IFPP_Handle = Adapter_Firmware_Acquire(FIRMWARE_EIP207_IFPP_NAME,
+                                           &IFPP_Firmware.Image_p,
+                                           &IFPP_Firmware.ImageWordCount);
+    if ((EIP97_SupportedFuncs_Get() & BIT_1) != 0)
+    {
+        OPUE_Handle = Adapter_Firmware_Acquire(FIRMWARE_EIP207_OPUE_NAME,
+                                               &OPUE_Firmware.Image_p,
+                                               &OPUE_Firmware.ImageWordCount);
+        OFPP_Handle = Adapter_Firmware_Acquire(FIRMWARE_EIP207_OFPP_NAME,
+                                               &OFPP_Firmware.Image_p,
+                                               &OFPP_Firmware.ImageWordCount);
+    }
+    else
+    {
+        OPUE_Handle = Adapter_Firmware_NULL;
+        OFPP_Handle = Adapter_Firmware_NULL;
+    }
+
+    LOG_INFO("\n\t\t\t\t EIP207_Global_Firmware_Load \n");
+
+    rc = EIP207_Global_Firmware_Load(&Global_IOArea,
+                                     ADAPTER_CS_TIMER_PRESCALER,
+                                     &IPUE_Firmware,
+                                     &IFPP_Firmware,
+                                     &OPUE_Firmware,
+                                     &OFPP_Firmware);
+    Adapter_Firmware_Release(IPUE_Handle);
+    Adapter_Firmware_Release(IFPP_Handle);
+    Adapter_Firmware_Release(OPUE_Handle);
+    Adapter_Firmware_Release(OFPP_Handle);
+    if (rc != EIP207_GLOBAL_NO_ERROR)
+    {
+        LOG_CRIT("GlobalControl207_Init: "
+                 "EIP207_Global_Firmware_Load() failed\n");
+        return -3; // error
+    }
+    else if (fVerbose)
+    {
+        LOG_CRIT("GlobalControl207_Init: firmware "
+                 "downloaded successfully\n");
+
+        LOG_CRIT("\tIPUE firmware v%d.%d.%d, image byte count %d\n",
+                 IPUE_Firmware.Major,
+                 IPUE_Firmware.Minor,
+                 IPUE_Firmware.PatchLevel,
+                 (int)(IPUE_Firmware.ImageWordCount * sizeof(uint32_t)));
+
+        LOG_CRIT("\tIFPP firmware v%d.%d.%d, image byte count %d\n\n",
+                 IFPP_Firmware.Major,
+                     IFPP_Firmware.Minor,
+                 IFPP_Firmware.PatchLevel,
+                 (int)(IFPP_Firmware.ImageWordCount * sizeof(uint32_t)));
+
+        LOG_CRIT("\tOPUE firmware v%d.%d.%d, image byte count %d\n",
+                 OPUE_Firmware.Major,
+                 OPUE_Firmware.Minor,
+                 OPUE_Firmware.PatchLevel,
+                     (int)(OPUE_Firmware.ImageWordCount * sizeof(uint32_t)));
+
+        LOG_CRIT("\tOFPP firmware v%d.%d.%d, image byte count %d\n\n",
+                 OFPP_Firmware.Major,
+                 OFPP_Firmware.Minor,
+                 OFPP_Firmware.PatchLevel,
+                 (int)(OFPP_Firmware.ImageWordCount * sizeof(uint32_t)));
+    }
+    return 0;
+}
+
+#ifdef ADAPTER_GLOBAL_RPM_EIP207_DEVICE_ID
+/*----------------------------------------------------------------------------
+ * GlobalControl207Lib_Resume
+ *
+ */
+static int
+GlobalControl207Lib_Resume(void * p)
+{
+    EIP207_Global_Error_t rc;
+    EIP207_Firmware_t IPUE_Firmware, IFPP_Firmware;
+    EIP207_Firmware_t OPUE_Firmware, OFPP_Firmware;
+
+    IDENTIFIER_NOT_USED(p);
+
+    if (GlobalControl207Lib_Init() != 0)
+        return -1; // error
+
+    if (GlobalControl207Lib_Firmware_Load(false) != 0)
+        return -2; // error
+
+    return 0; // success
+}
+#endif
+
+
+/*----------------------------------------------------------------------------
+ * GlobalControl207_Capabilities_Get
+ */
+void
+GlobalControl207_Capabilities_Get(
+        GlobalControl207_Capabilities_t * const Capabilities_p)
+{
+    uint8_t Versions[7];
+
+    LOG_INFO("\n\t\t\t %s \n", __func__);
+
+    memcpy(Capabilities_p, &Global_CapabilitiesString,
+           sizeof(Global_CapabilitiesString));
+
+    {
+        EIP207_Global_Error_t rc;
+        EIP207_Global_Capabilities_t Capabilities;
+
+        if (RPM_DEVICE_IO_START_MACRO(ADAPTER_GLOBAL_RPM_EIP207_DEVICE_ID,
+                                RPM_FLAG_SYNC) != RPM_SUCCESS)
+            return;
+
+        LOG_INFO("\n\t\t\t\t EIP207_Global_HWRevision_Get \n");
+
+        rc = EIP207_Global_HWRevision_Get(&Global_IOArea, &Capabilities);
+
+        (void)RPM_DEVICE_IO_STOP_MACRO(ADAPTER_GLOBAL_RPM_EIP207_DEVICE_ID,
+                                       RPM_FLAG_ASYNC);
+
+        if (rc != EIP207_GLOBAL_NO_ERROR)
+        {
+            LOG_CRIT("GlobalControl207_Capabilities_Get: "
+                     "EIP207_Global_HWRevision_Get() failed\n");
+            return;
+        }
+
+        // Show those capabilities not propagated to higher layer.
+        LOG_CRIT("EIP-207 capabilities\n");
+        LOG_CRIT("\tLookup cached:            %s\n"
+                 "\tFRC combined with TRC:    %s\n"
+                 "\tARC4RC present:           %s\n"
+                 "\tFRC combined with ARC4RC: %s\n"
+                 "\tTRC combined with ARC4RC: %s\n"
+                 "\tFRC clients:              %d\n"
+                 "\tTRC clients:              %d\n"
+                 "\tARC4RC clients:           %d\n"
+                 "\tLookup clients:           %d\n\n",
+                 YesNo(Capabilities.EIP207_Options.fLookupCached),
+                 YesNo(Capabilities.EIP207_Options.fCombinedFRC_TRC),
+                 YesNo(Capabilities.EIP207_Options.fARC4Present),
+                 YesNo(Capabilities.EIP207_Options.fCombinedFRC_ARC4),
+                 YesNo(Capabilities.EIP207_Options.fCombinedTRC_ARC4),
+                 Capabilities.EIP207_Options.NofFRC_Clients,
+                 Capabilities.EIP207_Options.NofTRC_Clients,
+                 Capabilities.EIP207_Options.NofARC4_Clients,
+                 Capabilities.EIP207_Options.NofLookupClients);
+
+        Versions[0] = Capabilities.EIP207_Version.MajHWRevision;
+        Versions[1] = Capabilities.EIP207_Version.MinHWRevision;
+        Versions[2] = Capabilities.EIP207_Version.HWPatchLevel;
+
+        Versions[3] = Capabilities.EIP207_Options.NofCacheSets / 10;
+        Versions[4] = Capabilities.EIP207_Options.NofCacheSets % 10;
+
+        Versions[5] = Capabilities.EIP207_Options.NofLookupTables / 10;
+        Versions[6] = Capabilities.EIP207_Options.NofLookupTables % 10;
+    }
+
+    {
+        char * p = Capabilities_p->szTextDescription;
+        int VerIndex = 0;
+        int i = 0;
+
+        while(p[i])
+        {
+            if (p[i] == '_')
+            {
+                if (Versions[VerIndex] > 9)
+                    p[i] = '?';
+                else
+                    p[i] = '0' + Versions[VerIndex++];
+
+                if (VerIndex >= 7)
+                    break;
+            }
+
+            i++;
+        }
+    }
+
+    return;
+}
+
+/*----------------------------------------------------------------------------
+ * GlobalControl207_Init
+ */
+GlobalControl207_Error_t
+GlobalControl207_Init(
+        const bool fLoadFirmware,
+        const GlobalControl207_IV_t * const IV_p)
+{
+    unsigned int i;
+    GlobalControl207_Error_t GC207_Rc = EIP207_GLOBAL_CONTROL_ERROR_INTERNAL;
+    EIP207_Global_Error_t rc;
+    Device_Handle_t Device;
+    unsigned int NofCEs,NofRings,NofLAInterfaces,NofInlineInterfaces;
+
+    LOG_INFO("\n\t\t\t %s \n", __func__);
+
+    if (Global_IsInitialized)
+    {
+        LOG_CRIT("GlobalControl207_Init: called while already initialized\n");
+        return EIP207_GLOBAL_CONTROL_ERROR_BAD_USE_ORDER;
+    }
+
+    Device = Device_Find(ADAPTER_CS_GLOBAL_DEVICE_NAME);
+    if (Device == NULL)
+    {
+        LOG_CRIT("GlobalControl207_Init: Could not find device\n");
+        return EIP207_GLOBAL_CONTROL_ERROR_INTERNAL;
+    }
+
+    ZEROINIT(RC_Conf);
+    ZEROINIT(FLUE_Conf);
+
+    // Record Caches initialization parameters
+    for (i = 0; i < EIP207_GLOBAL_MAX_NOF_CACHE_SETS_TO_USE; i++)
+    {
+        RC_Conf.FRC[i].fEnable = (ADAPTER_CS_FRC_ENABLED != 0);
+        RC_Conf.FRC[i].fNonBlock = false;
+        RC_Conf.FRC[i].BlockClockCount = ADAPTER_CS_RC_BLOCK_CLOCK_COUNT;
+        RC_Conf.FRC[i].RecBaseAddr.Value64_Lo = 0;
+        RC_Conf.FRC[i].RecBaseAddr.Value64_Hi = 0;
+
+        RC_Conf.TRC[i].fEnable = (ADAPTER_CS_TRC_ENABLED != 0);
+        RC_Conf.TRC[i].fNonBlock = false;
+        RC_Conf.TRC[i].BlockClockCount = ADAPTER_CS_RC_BLOCK_CLOCK_COUNT;
+        RC_Conf.TRC[i].RecBaseAddr.Value64_Lo = 0;
+        RC_Conf.TRC[i].RecBaseAddr.Value64_Hi = 0;
+
+        RC_Conf.ARC4[i].fEnable = (ADAPTER_CS_ARC4RC_ENABLED != 0);
+        RC_Conf.ARC4[i].fNonBlock = false;
+        RC_Conf.ARC4[i].BlockClockCount = ADAPTER_CS_RC_BLOCK_CLOCK_COUNT;
+        RC_Conf.ARC4[i].RecBaseAddr.Value64_Lo = 0;
+        RC_Conf.ARC4[i].RecBaseAddr.Value64_Hi = 0;
+    }
+
+    // Flow Look-Up Engine initialization parameters
+    FLUE_Conf.CacheChain = ADAPTER_CS_FLUE_CACHE_CHAIN;
+    FLUE_Conf.fDelayMemXS = (ADAPTER_CS_FLUE_MEMXS_DELAY != 0);
+    FLUE_Conf.IV.IV_Word32[0] = IV_p->IV[0];
+    FLUE_Conf.IV.IV_Word32[1] = IV_p->IV[1];
+    FLUE_Conf.IV.IV_Word32[2] = IV_p->IV[2];
+    FLUE_Conf.IV.IV_Word32[3] = IV_p->IV[3];
+
+    // Hash table initialization parameters
+    FLUE_Conf.HashTablesCount = ADAPTER_CS_MAX_NOF_FLOW_HASH_TABLES_TO_USE;
+    for (i = 0; i < FLUE_Conf.HashTablesCount; i++)
+    {
+        FLUE_Conf.HashTable[i].fLookupCached =
+                                    (ADAPTER_CS_FLUE_LOOKUP_CACHED != 0);
+        FLUE_Conf.HashTable[i].fPrefetchXform =
+                                    (ADAPTER_CS_FLUE_PREFETCH_XFORM != 0);
+        FLUE_Conf.HashTable[i].fPrefetchARC4State =
+                                    (ADAPTER_CS_FLUE_PREFETCH_ARC4 != 0);
+    }
+
+    GlobalControl97_Interfaces_Get(&NofCEs, &NofRings, &NofLAInterfaces, &NofInlineInterfaces);
+    LOG_CRIT("GlobalControl_EIP207_Init:\n"
+             "Number of Rings: %u, LA Interfaces: %u, Inline interfaces: %u\n",
+             NofRings,NofLAInterfaces,NofInlineInterfaces);
+
+    FLUE_Conf.InterfacesCount = NofRings + NofLAInterfaces +
+                                                    NofInlineInterfaces;
+    if (FLUE_Conf.InterfacesCount == 0)
+    {
+        LOG_CRIT("GlobalControl207_Init: Device not initialized\n");
+        return EIP207_GLOBAL_CONTROL_ERROR_INTERNAL;
+    }
+
+    for (i = 0; i < FLUE_Conf.InterfacesCount; i++)
+        FLUE_Conf.InterfaceIndex[i] = 0;
+
+    if (RPM_DEVICE_INIT_START_MACRO(ADAPTER_GLOBAL_RPM_EIP207_DEVICE_ID,
+                                    NULL, // Suspend callback not used
+                                    GlobalControl207Lib_Resume) != RPM_SUCCESS)
+        return EIP207_GLOBAL_CONTROL_ERROR_INTERNAL;
+
+    if (GlobalControl207Lib_Init() != 0)
+        goto exit; // error
+
+    // Configure the Record Cache functionality at the Ring Control
+    {
+        EIP207_Global_Capabilities_t Capabilities;
+
+        LOG_INFO("\n\t\t\t\t EIP207_Global_HWRevision_Get \n");
+
+        rc = EIP207_Global_HWRevision_Get(&Global_IOArea, &Capabilities);
+        if (rc != EIP207_GLOBAL_NO_ERROR)
+        {
+            LOG_CRIT("GlobalControl207_Init: "
+                     "EIP207_Global_HWRevision_Get() failed\n");
+            goto exit; // error
+        }
+
+#ifndef GLOBALCONTROL_BUILD
+#ifdef ADAPTER_CS_RC_SUPPORT
+        Adapter_RC_EIP207_Configure(
+                (ADAPTER_CS_TRC_ENABLED != 0),
+                (ADAPTER_CS_ARC4RC_ENABLED != 0) &&
+                                 Capabilities.EIP207_Options.fARC4Present,
+                Capabilities.EIP207_Options.fCombinedTRC_ARC4);
+#endif // ADAPTER_CS_RC_SUPPORT
+#endif // GLOBALCONTROL_BUILD
+    }
+
+    if (fLoadFirmware)
+    {
+        if (GlobalControl207Lib_Firmware_Load(true) != 0)
+            goto exit;
+    }
+
+    {
+        EIP207_Firmware_Config_t FWConfig;
+        ZEROINIT(FWConfig);
+#if defined(ADAPTER_CS_GLOBAL_IOTOKEN_METADATA_ENABLE) || \
+    defined(ADAPTER_CS_GLOBAL_CFH_ENABLE)
+        FWConfig.fTokenExtensionsEnable = true;
+#else
+        FWConfig.fTokenExtensionsEnable = false;
+#endif
+#ifdef ADAPTER_CS_GLOBAL_INCREMENT_PKTID
+        FWConfig.fIncrementPktID = true;
+#else
+        FWConfig.fIncrementPktID = false;
+#endif
+#ifdef ADAPTER_CS_GLOBAL_ECN_CONTROL
+        FWConfig.ECNControl = ADAPTER_CS_GLOBAL_ECN_CONTROL;
+#endif
+#ifdef ADAPTER_CS_GLOBAL_DTLS_DEFER_CCS
+        FWConfig.fDTLSDeferCCS = true;
+#endif
+#ifdef ADAPTER_CS_GLOBAL_DTLS_DEFER_ALERT
+        FWConfig.fDTLSDeferAlert = true;
+#endif
+#ifdef ADAPTER_CS_GLOBAL_DTLS_DEFER_HANDSHAKE
+        FWConfig.fDTLSDeferHandshake = true;
+#endif
+#ifdef ADAPTER_CS_GLOBAL_DTLS_DEFER_APPDATA
+        FWConfig.fDTLSDeferAppData = true;
+#endif
+#ifdef ADAPTER_CS_GLOBAL_DTLS_DEFER_CAPWAP
+        FWConfig.fDTLSDeferCAPWAP = true;
+#endif
+#ifdef ADAPTER_CS_GLOBAL_DTLS_HDR_ALIGN
+        FWConfig.DTLSRecordHeaderAlign = ADAPTER_CS_GLOBAL_DTLS_HDR_ALIGN;
+#endif
+        FWConfig.TransformRedirEnable = ADAPTER_CS_GLOBAL_TRANSFORM_REDIRECT_ENABLE;
+#ifdef ADAPTER_CS_GLOBAL_REDIR_RING
+        FWConfig.fRedirRingEnable = true;
+        FWConfig.RedirRing = ADAPTER_CS_GLOBAL_REDIR_RING;
+#endif
+        // Configure the EIP-207 Firmware meta-data or CFH presence
+        // in the ICE scratch-path RAM
+        for (i = 0; i < NofCEs; i++)
+        {
+            EIP207_Global_Firmware_Configure(Device, i, &FWConfig);
+            if (FWConfig.fIncrementPktID)
+            {   /* Give each engine its own range of PktID values */
+                FWConfig.PktID += 4096;
+            }
+        }
+    }
+    Global_IsInitialized = true;
+    GC207_Rc = EIP207_GLOBAL_CONTROL_NO_ERROR; // success
+
+exit:
+    (void)RPM_DEVICE_INIT_STOP_MACRO(ADAPTER_GLOBAL_RPM_EIP207_DEVICE_ID);
+
+    return GC207_Rc;
+}
+
+
+/*----------------------------------------------------------------------------
+ * GlobalControl207_UnInit
+ */
+GlobalControl207_Error_t
+GlobalControl207_UnInit(void)
+{
+    LOG_INFO("\n\t\t\t %s \n", __func__);
+
+    if (!Global_IsInitialized)
+    {
+        LOG_CRIT("GlobalControl207_UnInit: called while not initialized\n");
+        return EIP207_GLOBAL_CONTROL_ERROR_BAD_USE_ORDER;
+    }
+
+    (void)RPM_DEVICE_UNINIT_START_MACRO(ADAPTER_GLOBAL_RPM_EIP207_DEVICE_ID, false);
+    (void)RPM_DEVICE_UNINIT_STOP_MACRO(ADAPTER_GLOBAL_RPM_EIP207_DEVICE_ID);
+
+    Global_IsInitialized = false;
+
+    return EIP207_GLOBAL_CONTROL_NO_ERROR;
+}
+
+
+/*----------------------------------------------------------------------------
+ * GlobalControl207_Status_Get
+ */
+GlobalControl207_Error_t
+GlobalControl207_Status_Get(
+        const unsigned int CE_Number,
+        GlobalControl207_Status_t * const Status_p)
+{
+    EIP207_Global_Error_t rc;
+    bool fFatalError;
+
+    LOG_INFO("\n\t\t\t %s \n", __func__);
+
+    if (RPM_DEVICE_IO_START_MACRO(ADAPTER_GLOBAL_RPM_EIP207_DEVICE_ID,
+                            RPM_FLAG_SYNC) != RPM_SUCCESS)
+        return EIP207_GLOBAL_CONTROL_ERROR_INTERNAL;
+
+    LOG_INFO("\n\t\t\t\t EIP207_Global_Status_Get \n");
+
+    rc = EIP207_Global_Status_Get(&Global_IOArea,
+                                  CE_Number,
+                                  Status_p,
+                                  &fFatalError);
+
+    (void)RPM_DEVICE_IO_STOP_MACRO(ADAPTER_GLOBAL_RPM_EIP207_DEVICE_ID,
+                                   RPM_FLAG_ASYNC);
+
+    if (rc == EIP207_GLOBAL_NO_ERROR)
+    {
+        if (fFatalError)
+            LOG_CRIT("GlobalControl207_Status_Get: Fatal Error detected, "
+                     "reset required!\n");
+
+        return EIP207_GLOBAL_CONTROL_NO_ERROR;
+    }
+    else if (rc == EIP207_GLOBAL_ARGUMENT_ERROR)
+        return EIP207_GLOBAL_CONTROL_ERROR_BAD_PARAMETER;
+    else
+        return EIP207_GLOBAL_CONTROL_ERROR_INTERNAL;
+}
+
+
+/*----------------------------------------------------------------------------
+ * GlobalControl207_GlobalStats_Get
+ */
+GlobalControl207_Error_t
+GlobalControl207_GlobalStats_Get(
+        const unsigned int CE_Number,
+        GlobalControl207_GlobalStats_t * const GlobalStats_p)
+{
+    EIP207_Global_Error_t rc;
+
+    LOG_INFO("\n\t\t\t %s \n", __func__);
+
+    if (RPM_DEVICE_IO_START_MACRO(ADAPTER_GLOBAL_RPM_EIP207_DEVICE_ID,
+                            RPM_FLAG_SYNC) != RPM_SUCCESS)
+        return EIP207_GLOBAL_CONTROL_ERROR_INTERNAL;
+
+    LOG_INFO("\n\t\t\t\t EIP207_Global_GlobalStats_Get \n");
+
+    rc = EIP207_Global_GlobalStats_Get(&Global_IOArea,
+                                       CE_Number,
+                                       GlobalStats_p);
+
+    (void)RPM_DEVICE_IO_STOP_MACRO(ADAPTER_GLOBAL_RPM_EIP207_DEVICE_ID,
+                                   RPM_FLAG_ASYNC);
+
+    if (rc == EIP207_GLOBAL_NO_ERROR)
+        return EIP207_GLOBAL_CONTROL_NO_ERROR;
+    else if (rc == EIP207_GLOBAL_ARGUMENT_ERROR)
+        return EIP207_GLOBAL_CONTROL_ERROR_BAD_PARAMETER;
+    else
+        return EIP207_GLOBAL_CONTROL_ERROR_INTERNAL;
+}
+
+
+/*----------------------------------------------------------------------------
+ * GlobalControl207_ClockCount_Get
+ */
+GlobalControl207_Error_t
+GlobalControl207_ClockCount_Get(
+        const unsigned int CE_Number,
+        GlobalControl207_Clock_t * const Clock_p)
+{
+    EIP207_Global_Error_t rc;
+
+    LOG_INFO("\n\t\t\t %s \n", __func__);
+
+    if (RPM_DEVICE_IO_START_MACRO(ADAPTER_GLOBAL_RPM_EIP207_DEVICE_ID,
+                            RPM_FLAG_SYNC) != RPM_SUCCESS)
+        return EIP207_GLOBAL_CONTROL_ERROR_INTERNAL;
+
+    LOG_INFO("\n\t\t\t\t EIP207_Global_ClockCount_Get \n");
+
+    rc = EIP207_Global_ClockCount_Get(&Global_IOArea,
+                                      CE_Number,
+                                      Clock_p);
+
+    (void)RPM_DEVICE_IO_STOP_MACRO(ADAPTER_GLOBAL_RPM_EIP207_DEVICE_ID,
+                                   RPM_FLAG_ASYNC);
+
+    if (rc == EIP207_GLOBAL_NO_ERROR)
+        return EIP207_GLOBAL_CONTROL_NO_ERROR;
+    else if (rc == EIP207_GLOBAL_ARGUMENT_ERROR)
+        return EIP207_GLOBAL_CONTROL_ERROR_BAD_PARAMETER;
+    else
+        return EIP207_GLOBAL_CONTROL_ERROR_INTERNAL;
+}
+
+
+/*--------------------- -------------------------------------------------------
+ * GlobalControl207_Firmware_Configure
+ */
+GlobalControl207_Error_t
+GlobalControl207_Firmware_Configure(
+        GlobalControl_Firmware_Config_t * const FWConfig_p)
+{
+    unsigned i;
+    Device_Handle_t Device;
+    unsigned int NofCEs;
+    Device = Device_Find(ADAPTER_CS_GLOBAL_DEVICE_NAME);
+    GlobalControl97_Interfaces_Get(&NofCEs, NULL, NULL, NULL);
+    if (FWConfig_p == NULL)
+        return EIP207_GLOBAL_CONTROL_ERROR_BAD_PARAMETER;
+    FWConfig_p->PktID = 0;
+    // Configure the EIP-207 Firmware meta-data or CFH presence
+    // in the ICE scratch-path RAM
+    for (i = 0; i < NofCEs; i++)
+    {
+        EIP207_Global_Firmware_Configure(Device, i, FWConfig_p);
+        if (FWConfig_p->fIncrementPktID)
+        {   /* Give each engine its own range of PktID values */
+            FWConfig_p->PktID += 4096;
+        }
+    }
+
+    return EIP207_GLOBAL_CONTROL_NO_ERROR;
+
+}
+
+
+/* end of file adapter_global_eip207.c */
diff --git a/package-21.02/kernel/crypto-eip/src/ddk/slad/adapter_global_eip74.c b/package-21.02/kernel/crypto-eip/src/ddk/slad/adapter_global_eip74.c
new file mode 100644
index 0000000..f31fa52
--- /dev/null
+++ b/package-21.02/kernel/crypto-eip/src/ddk/slad/adapter_global_eip74.c
@@ -0,0 +1,630 @@
+/* api_global_eip74.c
+ *
+ * Deterministic Random Bit Generator (EIP-74) Global Control Initialization
+ * Adapter. The EIP-74 is used to generate pseudo-random IVs for outbound
+ * operations in CBC mode.
+ */
+
+/*****************************************************************************
+* Copyright (c) 2017-2020 by Rambus, Inc. and/or its subsidiaries.
+*
+* This program is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 2 of the License, or
+* any later version.
+*
+* This program is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with this program. If not, see <http://www.gnu.org/licenses/>.
+*****************************************************************************/
+
+/*----------------------------------------------------------------------------
+ * This module implements (provides) the following interface(s):
+ */
+#include "api_global_eip74.h"
+
+
+/*----------------------------------------------------------------------------
+ * This module uses (requires) the following interface(s):
+ */
+
+// Configuration.
+#include "c_adapter_eip74.h"
+
+// Driver Framework Basic Definitions API
+#include "basic_defs.h"         // bool, uint8_t
+
+// memcpy
+#include "clib.h"
+
+// EIP-73 Driver Library.
+#include "eip74.h"
+
+#include "device_types.h"       // Device_Handle_t
+#include "device_mgmt.h"        // Device_find
+
+// Logging API
+#include "log.h"                // Log_*, LOG_*
+
+// Adapter interrupts API
+#include "adapter_interrupts.h" // Adapter_Interrupt_*
+
+// Runtime Power Management Device Macros API
+#include "rpm_device_macros.h"  // RPM_*
+
+
+/*----------------------------------------------------------------------------
+ * Definitions and macros
+ */
+
+
+/*----------------------------------------------------------------------------
+ * Local variables
+ */
+
+/* Put all adapter local variables in one structure */
+static struct {
+    EIP74_IOArea_t IOArea;
+#ifdef ADAPTER_EIP74_INTERRUPTS_ENABLE
+    GlobalControl74_NotifyFunction_t Notify_CBFunc;
+#endif
+#ifdef ADAPTER_PEC_RPM_EIP74_DEVICE0_ID
+    GlobalControl74_Configuration_t CachedConfig;
+    bool fInitialized;
+#ifdef ADAPTER_EIP74_INTERRUPTS_ENABLE
+    bool fInterruptEnabled;
+#endif
+#endif
+} EIP74State;
+
+
+static const  GlobalControl74_Capabilities_t Global_CapabilitiesString =
+{
+  "EIP-74 v_._p_"// szTextDescription
+};
+
+
+/*----------------------------------------------------------------------------
+ * GlobalControl74Lib_Init
+ */
+static GlobalControl74_Error_t
+GlobalControl74Lib_Init(
+        const GlobalControl74_Configuration_t * const Configuration_p,
+        const uint8_t * const Entropy_p);
+
+
+#ifdef ADAPTER_PEC_RPM_EIP74_DEVICE0_ID
+/*----------------------------------------------------------------------------
+ * GlobalControl74Lib_Resune
+ */
+static int
+GlobalControl74Lib_Resune(
+        void *p)
+{
+    uint8_t Entropy[48];
+    IDENTIFIER_NOT_USED(p);
+    if (EIP74State.fInitialized)
+    {
+        /* Note we should add fresh random data here */
+        ZEROINIT(Entropy);
+        if (GlobalControl74Lib_Init(&EIP74State.CachedConfig, Entropy) !=
+            GLOBAL_CONTROL_EIP74_NO_ERROR)
+        {
+            return -1;
+        }
+
+#ifdef ADAPTER_EIP74_INTERRUPTS_ENABLE
+        if (EIP74State.fInitialized && EIP74State.fInterruptEnabled)
+        {
+            Adapter_Interrupt_Disable(ADAPTER_EIP74_ERR_IRQ, 0);
+            Adapter_Interrupt_Disable(ADAPTER_EIP74_RES_IRQ, 0);
+        }
+#endif
+    }
+    return 0;
+}
+
+
+/*----------------------------------------------------------------------------
+ * GlobalControl74Lib_Suspend
+ */
+static int
+GlobalControl74Lib_Suspend(
+        void *p)
+{
+    IDENTIFIER_NOT_USED(p);
+#ifdef ADAPTER_EIP74_INTERRUPTS_ENABLE
+    if (EIP74State.fInitialized && EIP74State.fInterruptEnabled)
+    {
+        Adapter_Interrupt_Disable(ADAPTER_EIP74_ERR_IRQ, 0);
+        Adapter_Interrupt_Disable(ADAPTER_EIP74_RES_IRQ, 0);
+    }
+#endif
+    return 0;
+}
+
+#endif
+
+/*----------------------------------------------------------------------------
+ * GlobalControl74Lib_CopyKeyMat
+ *
+ * Copy a key represented as a byte array into a word array..
+ *
+ * Destination_p (input)
+ *   Destination (word-aligned) of the word array
+ *
+ * Source_p (input)
+ *   Source (byte aligned) of the data.
+ *
+ * KeyByteCount (input)
+ *   Size of the key in bytes.
+ *
+ * Destination_p is allowed to be a null pointer, in which case no key
+ * will be written.
+ */
+static void
+GlobalControl74Lib_CopyKeyMat(
+        uint32_t * const Destination_p,
+        const uint8_t * const Source_p,
+        const unsigned int KeyByteCount)
+{
+    uint32_t *dst = Destination_p;
+    const uint8_t *src = Source_p;
+    unsigned int i,j;
+    uint32_t w;
+    if (Destination_p == NULL)
+        return;
+    for(i=0; i < KeyByteCount / sizeof(uint32_t); i++)
+    {
+        w=0;
+        for(j=0; j<sizeof(uint32_t); j++)
+            w=(w<<8)|(*src++);
+        *dst++ = w;
+    }
+}
+
+#ifdef ADAPTER_EIP74_INTERRUPTS_ENABLE
+/*----------------------------------------------------------------------------
+ * GlobalControl74_InterruptHandlerNotify
+ */
+static void
+GlobalControl74_InterruptHandlerNotify(
+        const int nIRQ,
+        const unsigned int flags)
+{
+    GlobalControl74_NotifyFunction_t CB_Func = EIP74State.Notify_CBFunc;
+
+    IDENTIFIER_NOT_USED(nIRQ);
+    IDENTIFIER_NOT_USED(flags);
+
+    LOG_INFO("GlobalControl74_InterruptHandlerNotify\n");
+#ifdef ADAPTER_PEC_RPM_EIP74_DEVICE0_ID
+    EIP74State.fInterruptEnabled = true;
+#endif
+
+    EIP74State.Notify_CBFunc = NULL;
+    if (CB_Func != NULL)
+    {
+        LOG_INFO("\t Invoking callback\n");
+        CB_Func();
+    }
+}
+#endif
+/*----------------------------------------------------------------------------
+ * GlobalControl74Lib_Init
+ *
+ * This function performs the initialization of the EIP-74 Deterministic
+ * Random Bit Generator.
+ *
+ * Note: the Device was already found and the IOArea is already initialized.
+ *
+ * Configuration_p (input)
+ *     Configuration parameters of the DRBG.
+ *
+ * Entropy_p (input)
+ *     Pointer to a string of exactly 48 bytes that serves as the entropy.
+ *     to initialize the DRBG.
+ *
+ * Return value
+ *     GLOBAL_CONTROL_EIP74_NO_ERROR : initialization performed successfully
+ *     GLOBAL_CONTROL_EIP74_ERROR_INTERNAL : initialization failed
+ */
+static GlobalControl74_Error_t
+GlobalControl74Lib_Init(
+        const GlobalControl74_Configuration_t * const Configuration_p,
+        const uint8_t * const Entropy_p)
+{
+    EIP74_Error_t Rc;
+    EIP74_Configuration_t Conf;
+    unsigned LoopCounter = ADAPTER_EIP74_RESET_MAX_RETRIES;
+    uint32_t Entropy[12];
+
+    Rc = EIP74_Reset(&EIP74State.IOArea);
+    do
+    {
+        if (Rc == EIP74_BUSY_RETRY_LATER)
+        {
+            LoopCounter--;
+            if (LoopCounter == 0)
+            {
+                LOG_CRIT("%s EIP74 reset timed out\n",__func__);
+                return GLOBAL_CONTROL_EIP74_ERROR_INTERNAL;
+            }
+            Rc = EIP74_Reset_IsDone(&EIP74State.IOArea);
+        }
+        else if (Rc != EIP74_NO_ERROR)
+        {
+            LOG_CRIT("%s EIP74 reset error\n",__func__);
+            return GLOBAL_CONTROL_EIP74_ERROR_INTERNAL;
+        }
+    } while (Rc != EIP74_NO_ERROR);
+
+    if (Configuration_p->GenerateBlockSize == 0)
+    {
+        Conf.GenerateBlockSize =  ADAPTER_EIP74_GEN_BLK_SIZE;
+    }
+    else
+    {
+        Conf.GenerateBlockSize = Configuration_p->GenerateBlockSize;
+    }
+
+    if (Configuration_p->ReseedThr == 0)
+    {
+        Conf.ReseedThr =  ADAPTER_EIP74_RESEED_THR;
+    }
+    else
+    {
+        Conf.ReseedThr = Configuration_p->ReseedThr;
+    }
+
+    if (Configuration_p->ReseedThrEarly == 0)
+    {
+        Conf.ReseedThrEarly =  ADAPTER_EIP74_RESEED_THR_EARLY;
+    }
+    else
+    {
+        Conf.ReseedThrEarly = Configuration_p->ReseedThrEarly;
+    }
+
+    Rc = EIP74_Configure(&EIP74State.IOArea, &Conf);
+    if (Rc != EIP74_NO_ERROR)
+    {
+        LOG_CRIT("%s EIP74 could not be configured\n",__func__);
+        return GLOBAL_CONTROL_EIP74_ERROR_INTERNAL;
+    }
+
+    GlobalControl74Lib_CopyKeyMat(Entropy, Entropy_p, 48);
+
+    Rc = EIP74_Instantiate(&EIP74State.IOArea, Entropy, Configuration_p->fStuckOut);
+
+    if (Rc != EIP74_NO_ERROR)
+    {
+        LOG_CRIT("%s EIP74 could not be instantiated\n",__func__);
+        return GLOBAL_CONTROL_EIP74_ERROR_INTERNAL;
+    }
+
+    return GLOBAL_CONTROL_EIP74_NO_ERROR;
+}
+
+
+/*----------------------------------------------------------------------------
+ * GlobalControl74_Capabilities_Get
+ */
+void
+GlobalControl74_Capabilities_Get(
+        GlobalControl74_Capabilities_t * const Capabilities_p)
+{
+    Device_Handle_t Device;
+    uint8_t Versions[3];
+    LOG_INFO("\n\t\t\t GlobalControl74_Capabilities_Get\n");
+
+    memcpy(Capabilities_p, &Global_CapabilitiesString,
+           sizeof(Global_CapabilitiesString));
+
+    Device = Device_Find(ADAPTER_EIP74_DEVICE_NAME);
+    if (Device == NULL)
+    {
+        LOG_CRIT("%s EIP74 Device not found\n",__func__);
+        return;
+    }
+
+    {
+        EIP74_Capabilities_t Capabilities;
+        EIP74_Error_t Rc;
+
+        if (RPM_DEVICE_IO_START_MACRO(ADAPTER_GLOBAL_RPM_EIP74_DEVICE_ID,
+                                RPM_FLAG_SYNC) != RPM_SUCCESS)
+            return;
+
+        Rc = EIP74_HWRevision_Get(Device, &Capabilities);
+
+        (void)RPM_DEVICE_IO_STOP_MACRO(ADAPTER_GLOBAL_RPM_EIP74_DEVICE_ID,
+                                       RPM_FLAG_ASYNC);
+
+        if (Rc != EIP74_NO_ERROR)
+        {
+            LOG_CRIT("%s EIP74_Capaboilities_Get() failed\n",__func__);
+            return;
+        }
+
+        Log_FormattedMessage(
+            "EIP74 options: Nof Clients=%u Nof AESCores=%u\n"
+            "\t\tAESSpeed=%u FIFODepth=%u\n",
+            Capabilities.HW_Options.ClientCount,
+            Capabilities.HW_Options.AESCoreCount,
+            Capabilities.HW_Options.AESSpeed,
+            Capabilities.HW_Options.FIFODepth);
+
+
+        Versions[0] = Capabilities.HW_Revision.MajHWRevision;
+        Versions[1] = Capabilities.HW_Revision.MinHWRevision;
+        Versions[2] = Capabilities.HW_Revision.HWPatchLevel;
+    }
+
+    {
+        char * p = Capabilities_p->szTextDescription;
+        int VerIndex = 0;
+        int i = 0;
+
+        while(p[i])
+        {
+            if (p[i] == '_' && VerIndex < 3)
+            {
+                if (Versions[VerIndex] > 9)
+                    p[i] = '?';
+                else
+                    p[i] = '0' + Versions[VerIndex];
+
+                VerIndex++;
+            }
+
+            i++;
+        }
+    }
+}
+
+
+/*----------------------------------------------------------------------------
+ * GlobalControl74_Init
+ */
+GlobalControl74_Error_t
+GlobalControl74_Init(
+        const GlobalControl74_Configuration_t * const Configuration_p,
+        const uint8_t * const Entropy_p)
+{
+    EIP74_Error_t Rc;
+    Device_Handle_t Device;
+
+    LOG_INFO("\n\t\t\t GlobalControl74_Init\n");
+
+    Device = Device_Find(ADAPTER_EIP74_DEVICE_NAME);
+    if (Device == NULL)
+    {
+        LOG_CRIT("%s EIP74 Device not found\n",__func__);
+        return GLOBAL_CONTROL_EIP74_ERROR_NOT_IMPLEMENTED;
+    }
+
+
+    Rc = EIP74_Init(&EIP74State.IOArea, Device);
+    if (Rc != EIP74_NO_ERROR)
+    {
+        LOG_CRIT("%s EIP74 could not be initialized\n",__func__);
+        return GLOBAL_CONTROL_EIP74_ERROR_NOT_IMPLEMENTED;
+    }
+
+    if (RPM_DEVICE_INIT_START_MACRO(ADAPTER_GLOBAL_RPM_EIP74_DEVICE_ID,
+                                    GlobalControl74Lib_Suspend,
+                                    GlobalControl74Lib_Resume) != RPM_SUCCESS)
+        return GLOBAL_CONTROL_EIP74_ERROR_INTERNAL;
+
+    if (GlobalControl74Lib_Init(Configuration_p,Entropy_p) !=
+        GLOBAL_CONTROL_EIP74_NO_ERROR)
+    {
+        (void)RPM_DEVICE_INIT_STOP_MACRO(ADAPTER_GLOBAL_RPM_EIP74_DEVICE_ID);
+
+        return GLOBAL_CONTROL_EIP74_ERROR_INTERNAL;
+    }
+
+
+#ifdef ADAPTER_PEC_RPM_EIP74_DEVICE0_ID
+    EIP74State.fInitialized = true;
+    EIP74State.CachedConfig = *Configuration_p;
+#endif
+    (void)RPM_DEVICE_INIT_STOP_MACRO(ADAPTER_GLOBAL_RPM_EIP74_DEVICE_ID);
+
+
+#ifdef ADAPTER_EIP74_INTERRUPTS_ENABLE
+    Adapter_Interrupt_SetHandler(ADAPTER_EIP74_ERR_IRQ,
+                                 GlobalControl74_InterruptHandlerNotify);
+    Adapter_Interrupt_SetHandler(ADAPTER_EIP74_RES_IRQ,
+                                 GlobalControl74_InterruptHandlerNotify);
+#endif
+
+    return GLOBAL_CONTROL_EIP74_NO_ERROR;
+}
+
+
+
+/*----------------------------------------------------------------------------
+ * GlobalControl74_UnInit
+ */
+GlobalControl74_Error_t
+GlobalControl74_UnInit(void)
+{
+    EIP74_Error_t Rc;
+    unsigned LoopCounter = ADAPTER_EIP74_RESET_MAX_RETRIES;
+
+    LOG_INFO("\n\t\t\t GlobalControl74_UnInit\n");
+
+#ifdef ADAPTER_EIP74_INTERRUPTS_ENABLE
+    Adapter_Interrupt_SetHandler(ADAPTER_EIP74_ERR_IRQ, NULL);
+    Adapter_Interrupt_SetHandler(ADAPTER_EIP74_RES_IRQ, NULL);
+    Adapter_Interrupt_Disable(ADAPTER_EIP74_ERR_IRQ, 0);
+    Adapter_Interrupt_Disable(ADAPTER_EIP74_RES_IRQ, 0);
+#endif
+    (void)RPM_DEVICE_UNINIT_START_MACRO(ADAPTER_GLOBAL_RPM_EIP74_DEVICE_ID, false);
+
+    Rc = EIP74_Reset(&EIP74State.IOArea);
+    do
+    {
+        if (Rc == EIP74_BUSY_RETRY_LATER)
+        {
+            LoopCounter--;
+            if (LoopCounter == 0)
+            {
+                LOG_CRIT("%s EIP74 reset timed out\n",__func__);
+                (void)RPM_DEVICE_UNINIT_STOP_MACRO(ADAPTER_GLOBAL_RPM_EIP74_DEVICE_ID);
+                return GLOBAL_CONTROL_EIP74_ERROR_INTERNAL;
+            }
+            Rc = EIP74_Reset_IsDone(&EIP74State.IOArea);
+        }
+        else if (Rc != EIP74_NO_ERROR)
+        {
+            LOG_CRIT("%s EIP74 reset error\n",__func__);
+            (void)RPM_DEVICE_UNINIT_STOP_MACRO(ADAPTER_GLOBAL_RPM_EIP74_DEVICE_ID);
+
+            return GLOBAL_CONTROL_EIP74_ERROR_INTERNAL;
+        }
+    } while (Rc != EIP74_NO_ERROR);
+    (void)RPM_DEVICE_UNINIT_STOP_MACRO(ADAPTER_GLOBAL_RPM_EIP74_DEVICE_ID);
+
+#ifdef ADAPTER_PEC_RPM_EIP74_DEVICE0_ID
+    EIP74State.fInitialized = false;
+#ifdef ADAPTER_EIP74_INTERRUPTS_ENABLE
+    EIP74State.fInterruptEnabled = false;
+#endif
+#endif
+
+    return GLOBAL_CONTROL_EIP74_NO_ERROR;
+}
+
+
+/*----------------------------------------------------------------------------
+ * GlobalControl74_Reseed
+ */
+GlobalControl74_Error_t
+GlobalControl74_Reseed(
+        const uint8_t * const Entropy_p)
+{
+    EIP74_Error_t Rc;
+    uint32_t Entropy[12];
+    LOG_INFO("\n\t\t\t GlobalControl74_Reseed\n");
+
+
+    GlobalControl74Lib_CopyKeyMat(Entropy, Entropy_p, 48);
+
+    if (RPM_DEVICE_IO_START_MACRO(ADAPTER_GLOBAL_RPM_EIP74_DEVICE_ID,
+                                  RPM_FLAG_SYNC) != RPM_SUCCESS)
+        return GLOBAL_CONTROL_EIP74_ERROR_INTERNAL;
+
+    Rc = EIP74_Reseed(&EIP74State.IOArea, Entropy);
+
+    (void)RPM_DEVICE_IO_STOP_MACRO(ADAPTER_GLOBAL_RPM_EIP74_DEVICE_ID,
+                                   RPM_FLAG_ASYNC);
+
+    if (Rc != EIP74_NO_ERROR)
+    {
+        LOG_CRIT("%s EIP74 could not be reseeded\n",__func__);
+        return GLOBAL_CONTROL_EIP74_ERROR_INTERNAL;
+    }
+
+    return GLOBAL_CONTROL_EIP74_NO_ERROR;
+}
+
+
+/*----------------------------------------------------------------------------
+ * GlobalControl74_Status_Get
+ */
+GlobalControl74_Error_t
+GlobalControl74_Status_Get(
+        GlobalControl74_Status_t * const Status_p)
+{
+    EIP74_Error_t Rc;
+    EIP74_Status_t Status;
+    LOG_INFO("\n\t\t\t GlobalControl74_Status_Get\n");
+
+    if (RPM_DEVICE_IO_START_MACRO(ADAPTER_GLOBAL_RPM_EIP74_DEVICE_ID,
+                                  RPM_FLAG_SYNC) != RPM_SUCCESS)
+        return GLOBAL_CONTROL_EIP74_ERROR_INTERNAL;
+
+    Rc = EIP74_Status_Get(&EIP74State.IOArea, &Status);
+
+    (void)RPM_DEVICE_IO_STOP_MACRO(ADAPTER_GLOBAL_RPM_EIP74_DEVICE_ID,
+                                   RPM_FLAG_ASYNC);
+
+    if (Rc != EIP74_NO_ERROR)
+    {
+        LOG_CRIT("%s EIP74 status could not be read\n",__func__);
+        return GLOBAL_CONTROL_EIP74_ERROR_INTERNAL;
+    }
+
+    Status_p->GenerateBlockCount = Status.GenerateBlockCount;
+    Status_p->fStuckOut = Status.fStuckOut;
+    Status_p->fNotInitialized = Status.fNotInitialized;
+    Status_p->fReseedError = Status.fReseedError;
+    Status_p->fReseedWarning = Status.fReseedWarning;
+    Status_p->fInstantiated = Status.fInstantiated;
+    Status_p->AvailableCount = Status.AvailableCount;
+
+    return GLOBAL_CONTROL_EIP74_NO_ERROR;
+}
+
+/*----------------------------------------------------------------------------
+ * GlobalControl74_Clear
+ */
+GlobalControl74_Error_t
+GlobalControl74_Clear(void)
+{
+    EIP74_Error_t Rc;
+    LOG_INFO("\n\t\t\t GlobalControl74_Clear\n");
+
+    if (RPM_DEVICE_IO_START_MACRO(ADAPTER_GLOBAL_RPM_EIP74_DEVICE_ID,
+                                  RPM_FLAG_SYNC) != RPM_SUCCESS)
+        return GLOBAL_CONTROL_EIP74_ERROR_INTERNAL;
+
+    Rc = EIP74_Clear(&EIP74State.IOArea);
+
+    (void)RPM_DEVICE_IO_STOP_MACRO(ADAPTER_GLOBAL_RPM_EIP74_DEVICE_ID,
+                                   RPM_FLAG_ASYNC);
+
+    if (Rc != EIP74_NO_ERROR)
+    {
+        LOG_CRIT("%s EIP74 could not be cleared\n",__func__);
+        return GLOBAL_CONTROL_EIP74_ERROR_INTERNAL;
+    }
+
+    return GLOBAL_CONTROL_EIP74_NO_ERROR;
+}
+
+
+#ifdef ADAPTER_EIP74_INTERRUPTS_ENABLE
+/*----------------------------------------------------------------------------
+ * GlobalControl74_Notify_Request
+ */
+GlobalControl74_Error_t
+GlobalControl74_Notify_Request(
+        GlobalControl74_NotifyFunction_t CBFunc_p)
+{
+    LOG_INFO("\n\t\t\t GlobalControl74_Notify_Request\n");
+    IDENTIFIER_NOT_USED(CBFunc_p);
+
+    EIP74State.Notify_CBFunc = CBFunc_p;
+    if (CBFunc_p != NULL)
+    {
+        Adapter_Interrupt_Enable(ADAPTER_EIP74_ERR_IRQ, 0);
+        Adapter_Interrupt_Enable(ADAPTER_EIP74_RES_IRQ, 0);
+#ifdef ADAPTER_PEC_RPM_EIP74_DEVICE0_ID
+        EIP74State.fInterruptEnabled = true;
+#endif
+    }
+
+    return GLOBAL_CONTROL_EIP74_NO_ERROR;
+}
+#endif
+
+
+/* end of file adapter_global_eip74.c */
diff --git a/package-21.02/kernel/crypto-eip/src/ddk/slad/adapter_global_eip97.c b/package-21.02/kernel/crypto-eip/src/ddk/slad/adapter_global_eip97.c
new file mode 100644
index 0000000..cb6ae1d
--- /dev/null
+++ b/package-21.02/kernel/crypto-eip/src/ddk/slad/adapter_global_eip97.c
@@ -0,0 +1,884 @@
+/* adapter_global_eip97.c
+ *
+ * Security-IP-97 Global Control Adapter
+ */
+
+/*****************************************************************************
+* Copyright (c) 2011-2021 by Rambus, Inc. and/or its subsidiaries.
+*
+* This program is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 2 of the License, or
+* any later version.
+*
+* This program is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with this program. If not, see <http://www.gnu.org/licenses/>.
+*****************************************************************************/
+
+/*----------------------------------------------------------------------------
+ * This module implements (provides) the following interface(s):
+ */
+#include "api_global_eip97.h"
+#include "adapter_global_internal.h"
+
+/*----------------------------------------------------------------------------
+ * This module uses (requires) the following interface(s):
+ */
+
+// Default Adapter configuration
+#include "c_adapter_global.h"
+
+#ifndef GLOBALCONTROL_BUILD
+#include "adapter_ring_eip202.h" // Ring EIP-202 interface to pass
+                                 // config params from Global Control
+#endif
+
+// Driver Framework Basic Definitions API
+#include "basic_defs.h"         // uint8_t, uint32_t, bool, IDENTIFIER_NOT_USED
+
+// Driver Framework C Library API
+#include "clib.h"               // memcpy, ZEROINIT
+
+// EIP-97 Driver Library Global Control API
+#include "eip97_global_event.h" // Event Management
+#include "eip97_global_init.h"  // Init/Uninit
+#include "eip97_global_prng.h"  // PRNG Control
+
+#include "device_types.h"       // Device_Handle_t
+#include "device_mgmt.h"        // Device_find
+
+// Logging API
+#include "log.h"                // Log_*, LOG_*
+
+#ifdef GLOBALCONTROL_BUILD
+#include "shdevxs_init.h"       // SHDevXS_Global_init()
+#endif
+
+// Runtime Power Management Device Macros API
+#include "rpm_device_macros.h"  // RPM_*
+
+
+/*----------------------------------------------------------------------------
+ * Definitions and macros
+ */
+
+typedef struct
+{
+    bool fCached;
+
+    GlobalControl97_Ring_PE_Map_t RingPEMap;
+
+} GlobalControl97_Ring_PE_Map_Cache_t;
+
+typedef struct
+{
+    bool fCached;
+
+    GlobalControl97_PRNG_Reseed_t   ReseedData;
+
+} GlobalControl97_PRNG_Cache_t;
+
+
+/*----------------------------------------------------------------------------
+ * Local variables
+ */
+static EIP97_Global_IOArea_t Global_IOArea;
+static bool Global_IsInitialized;
+static bool Global_PRNG_Present;
+
+static const  GlobalControl97_Capabilities_t Global_CapabilitiesString =
+{
+  "EIP-97 v_._p_  with EIP-202 v_._p_ and EIP-96 v_._p_, "
+  "#PE=__ #rings=__ central-prng=_"// szTextDescription
+};
+
+static unsigned int GlobalControl97_NofPEs;
+static unsigned int GlobalControl97_NofRings;
+static unsigned int GlobalControl97_NofLAInterfaces;
+static unsigned int GlobalControl97_NofInlineInterfaces;
+
+// Cached values for RPM resume callback
+static GlobalControl97_Ring_PE_Map_Cache_t GlobalControl97_RingPEMap [ADAPTER_GLOBAL_EIP97_NOF_PES];
+static GlobalControl97_PRNG_Cache_t GlobalControl97_Prng [ADAPTER_GLOBAL_EIP97_NOF_PES];
+
+
+/*----------------------------------------------------------------------------
+ * YesNo
+ */
+static const char *
+YesNo(
+        const bool b)
+{
+    if (b)
+        return "Yes";
+    else
+        return "No";
+}
+
+
+/*----------------------------------------------------------------------------
+ * GlobalControl97Lib_Resume
+ *
+ */
+static int
+GlobalControl97Lib_Resume(void * p)
+{
+    unsigned int i;
+    EIP97_Global_Error_t rc;
+    EIP97_Global_Capabilities_t Capabilities;
+
+    IDENTIFIER_NOT_USED(p);
+
+    LOG_INFO("\n\t\t\t\t EIP97_Global_Init \n");
+
+    rc = EIP97_Global_Init(&Global_IOArea,
+                           Device_Find(ADAPTER_GLOBAL_DEVICE_NAME));
+    if (rc != EIP97_GLOBAL_NO_ERROR)
+    {
+        LOG_CRIT("%s: EIP97_Global_Init() returned error %d\n", __func__, rc);
+        return -1; // error
+    }
+
+    rc = EIP97_Global_HWRevision_Get(&Global_IOArea, &Capabilities);
+    if (rc != EIP97_GLOBAL_NO_ERROR)
+    {
+        LOG_CRIT("%s: EIP97_Global_HWRevision_Get() returned error %d\n", __func__, rc);
+        return -1; // error
+    }
+    GlobalControl97_NofPEs = MIN(Capabilities.EIP202_Options.NofPes, ADAPTER_GLOBAL_EIP97_NOF_PES);
+    for (i = 0; i < GlobalControl97_NofPEs; i++)
+    {
+        if (GlobalControl97_RingPEMap[i].fCached)
+        {
+            LOG_INFO("\n\t\t\t\t EIP97_Global_Configure \n");
+
+            rc = EIP97_Global_Configure(&Global_IOArea,
+                                        i,
+                                        &GlobalControl97_RingPEMap[i].RingPEMap);
+            if (rc != EIP97_GLOBAL_NO_ERROR)
+            {
+                LOG_CRIT("%s: EIP97_Global_Configure() error %d for PE %d\n",
+                         __func__,
+                         rc,
+                         i);
+                return -2; // error
+            }
+        }
+
+        if (GlobalControl97_Prng[i].fCached && Global_PRNG_Present)
+        {
+            LOG_INFO("\n\t\t\t\t EIP97_Global_PRNG_Reseed \n");
+
+            rc = EIP97_Global_PRNG_Reseed(&Global_IOArea,
+                                          i,
+                                          &GlobalControl97_Prng[i].ReseedData);
+            if (rc != EIP97_GLOBAL_NO_ERROR)
+            {
+                LOG_CRIT("%s: EIP97_Global_PRNG_Reseed() error %d for PE %d\n",
+                         __func__,
+                         rc,
+                         i);
+                return -3; // error
+            }
+        }
+    } // for
+
+    return 0; // success
+}
+
+
+/*----------------------------------------------------------------------------
+ * GlobalControl97_Capabilities_Get
+ */
+GlobalControl97_Error_t
+GlobalControl97_Capabilities_Get(
+        GlobalControl97_Capabilities_t * const Capabilities_p)
+{
+    uint8_t Versions[14];
+
+    LOG_INFO("\n\t\t\t GlobalControl97_Capabilities_Get \n");
+
+    memcpy(Capabilities_p, &Global_CapabilitiesString,
+           sizeof(Global_CapabilitiesString));
+
+    {
+        EIP97_Global_Error_t rc;
+        EIP97_Global_Capabilities_t Capabilities;
+
+        ZEROINIT(Capabilities);
+
+        if (RPM_DEVICE_IO_START_MACRO(ADAPTER_GLOBAL_RPM_EIP97_DEVICE_ID,
+                                RPM_FLAG_SYNC) != RPM_SUCCESS)
+            return GLOBAL_CONTROL_ERROR_INTERNAL;
+
+        LOG_INFO("\n\t\t\t\t EIP97_Global_HWRevision_Get \n");
+
+        rc = EIP97_Global_HWRevision_Get(&Global_IOArea, &Capabilities);
+
+        (void)RPM_DEVICE_IO_STOP_MACRO(ADAPTER_GLOBAL_RPM_EIP97_DEVICE_ID,
+                                       RPM_FLAG_ASYNC);
+
+        if (rc != EIP97_GLOBAL_NO_ERROR)
+        {
+            LOG_CRIT("GlobalControl97_Capabilities_Get: returned error");
+            return GLOBAL_CONTROL_ERROR_INTERNAL;
+        }
+
+        // Show those capabilities not propagated to higher layer.
+        LOG_CRIT("GlobalControl97_Capabilities_Get\n");
+        LOG_CRIT("EIP202: PEs=%d rings=%d 64-bit=%s, fill level extension=%s\n"
+                 "CF size=%d RF size=%d DMA len = %d "
+                 "Align=%d HDW=%d HostIfc=%d\n",
+                 Capabilities.EIP202_Options.NofPes,
+                 Capabilities.EIP202_Options.NofRings,
+                 YesNo(Capabilities.EIP202_Options.fAddr64),
+                 YesNo(Capabilities.EIP202_Options.fExpPlf),
+                 Capabilities.EIP202_Options.CF_Size,
+                 Capabilities.EIP202_Options.RF_Size,
+                 Capabilities.EIP202_Options.DMA_Len,
+                 Capabilities.EIP202_Options.TgtAlign,
+                 Capabilities.EIP202_Options.HDW,
+                 Capabilities.EIP202_Options.HostIfc);
+        LOG_CRIT("EIP96 options:\n"
+                 "AES: %s with CFB/OFB: %s Fast: %s\n"
+                 "DES: %s with CFB/OFB: %s Fast: %s\n"
+                 "ARCFOUR level: %d\n"
+                 "AES-XTS: %s Wireless crypto: %s\n"
+                 "MD5: %s SHA1: %s Fast: %s SHA256: %s SHA512: %s\n"
+                 "(X)CBC-MAC: %s Fast: %s All key sizes: %s GHASH %s\n",
+                 YesNo(Capabilities.EIP96_Options.fAES),
+                 YesNo(Capabilities.EIP96_Options.fAESfb),
+                 YesNo(Capabilities.EIP96_Options.fAESspeed),
+                 YesNo(Capabilities.EIP96_Options.fDES),
+                 YesNo(Capabilities.EIP96_Options.fDESfb),
+                 YesNo(Capabilities.EIP96_Options.fDESspeed),
+                 Capabilities.EIP96_Options.ARC4,
+                 YesNo(Capabilities.EIP96_Options.fAES_XTS),
+                 YesNo(Capabilities.EIP96_Options.fWireless),
+                 YesNo(Capabilities.EIP96_Options.fMD5),
+                 YesNo(Capabilities.EIP96_Options.fSHA1),
+                 YesNo(Capabilities.EIP96_Options.fSHA1speed),
+                 YesNo(Capabilities.EIP96_Options.fSHA224_256),
+                 YesNo(Capabilities.EIP96_Options.fSHA384_512),
+                 YesNo(Capabilities.EIP96_Options.fXCBC_MAC),
+                 YesNo(Capabilities.EIP96_Options.fCBC_MACspeed),
+                 YesNo(Capabilities.EIP96_Options.fCBC_MACkeylens),
+                 YesNo(Capabilities.EIP96_Options.fGHASH));
+        LOG_CRIT("EIP97 options: PEs=%d, In Dbuf size=%d In Tbuf size=%d,"
+                 " Out Dbuf size=%d, Out Tbuf size=%d, Central PRNG: %s\n"
+                 "Token Generator: %s, Transform Record Cache: %s\n",
+                 Capabilities.EIP97_Options.NofPes,
+                 Capabilities.EIP97_Options.in_dbuf_size,
+                 Capabilities.EIP97_Options.in_tbuf_size,
+                 Capabilities.EIP97_Options.out_dbuf_size,
+                 Capabilities.EIP97_Options.out_tbuf_size,
+                 YesNo(Capabilities.EIP97_Options.central_prng),
+                 YesNo(Capabilities.EIP97_Options.tg),
+                 YesNo(Capabilities.EIP97_Options.trc));
+        LOG_CRIT("EIP206 options: PE type=%d InClassifier=%d OutClassifier=%d "
+                 "MAC chans=%d \n"
+                 "InDBuf=%dkB InTBuf=%dkB OutDBuf=%dkB OutTBuf=%dkB\n",
+                 Capabilities.EIP206_Options.PE_Type,
+                 Capabilities.EIP206_Options.InClassifier,
+                 Capabilities.EIP206_Options.OutClassifier,
+                 Capabilities.EIP206_Options.NofMAC_Channels,
+                 Capabilities.EIP206_Options.InDbufSizeKB,
+                 Capabilities.EIP206_Options.InTbufSizeKB,
+                 Capabilities.EIP206_Options.OutDbufSizeKB,
+                 Capabilities.EIP206_Options.OutTbufSizeKB);
+
+        Versions[0] = Capabilities.EIP97_Version.MajHWRevision;
+        Versions[1] = Capabilities.EIP97_Version.MinHWRevision;
+        Versions[2] = Capabilities.EIP97_Version.HWPatchLevel;
+
+        Versions[3] = Capabilities.EIP202_Version.MajHWRevision;
+        Versions[4] = Capabilities.EIP202_Version.MinHWRevision;
+        Versions[5] = Capabilities.EIP202_Version.HWPatchLevel;
+
+        Versions[6] = Capabilities.EIP96_Version.MajHWRevision;
+        Versions[7] = Capabilities.EIP96_Version.MinHWRevision;
+        Versions[8] = Capabilities.EIP96_Version.HWPatchLevel;
+
+        Versions[9]  = Capabilities.EIP202_Options.NofPes / 10;
+        Versions[10] = Capabilities.EIP202_Options.NofPes % 10;
+        Versions[11] = Capabilities.EIP202_Options.NofRings / 10;
+        Versions[12] = Capabilities.EIP202_Options.NofRings % 10;
+        Versions[13] = (uint8_t)Capabilities.EIP97_Options.central_prng;
+    }
+
+    {
+        char * p = Capabilities_p->szTextDescription;
+        int VerIndex = 0;
+        int i = 0;
+
+        while(p[i])
+        {
+            if (p[i] == '_')
+            {
+                if (Versions[VerIndex] > 9)
+                    p[i] = '?';
+                else
+                    p[i] = '0' + Versions[VerIndex];
+
+                VerIndex++;
+            }
+
+            i++;
+        }
+    }
+
+    return GLOBAL_CONTROL_NO_ERROR;
+}
+
+
+/*----------------------------------------------------------------------------
+ * GlobalControl97_Init
+ */
+GlobalControl97_Error_t
+GlobalControl97_Init(
+        const bool fHWResetDone)
+{
+    EIP97_Global_Error_t rc;
+    GlobalControl97_Error_t GC97_Rc = GLOBAL_CONTROL_ERROR_INTERNAL;
+    Device_Handle_t dev;
+    EIP97_Global_Capabilities_t Capabilities;
+
+    LOG_INFO("\n\t\t\t GlobalControl97_Init \n");
+
+    if (Global_IsInitialized)
+    {
+        LOG_CRIT("GlobalControl97_Init: called while already initialized\n");
+        return GLOBAL_CONTROL_ERROR_BAD_USE_ORDER;
+    }
+
+    dev = Device_Find(ADAPTER_GLOBAL_DEVICE_NAME);
+    if (dev == NULL)
+    {
+        LOG_CRIT("GlobalControl97_Init: Could not find device\n");
+        return GLOBAL_CONTROL_ERROR_INTERNAL;
+    }
+
+    ZEROINIT(GlobalControl97_RingPEMap);
+    ZEROINIT(GlobalControl97_Prng);
+
+    if (RPM_DEVICE_INIT_START_MACRO(ADAPTER_GLOBAL_RPM_EIP97_DEVICE_ID,
+                                    NULL, // Suspend callback not used
+                                    GlobalControl97Lib_Resume) != RPM_SUCCESS)
+        return GLOBAL_CONTROL_ERROR_INTERNAL;
+
+    if (!fHWResetDone)
+    {
+        LOG_INFO("\n\t\t\t\t EIP97_Global_Reset \n");
+
+        // Need to do a software reset first.
+        rc = EIP97_Global_Reset(&Global_IOArea, dev);
+        if (rc == EIP97_GLOBAL_BUSY_RETRY_LATER)
+        {
+            unsigned int tries = 0;
+            do {
+                LOG_INFO("\n\t\t\t\t EIP97_Global_Reset_IsDone \n");
+
+                rc = EIP97_Global_Reset_IsDone(&Global_IOArea);
+                if (rc != EIP97_GLOBAL_NO_ERROR &&
+                    rc != EIP97_GLOBAL_BUSY_RETRY_LATER)
+                {
+                    LOG_CRIT("GlobalControl97_Init:"
+                             " Error from EIP97_Global_Reset_IsDone\n");
+                    goto exit; // error
+                }
+                tries ++;
+                if (tries > ADAPTER_GLOBAL_RESET_MAX_RETRIES)
+                {
+                    LOG_CRIT("GlobalControl97_Init: Reset timeout\n");
+                    goto exit; // error
+                }
+            } while (rc == EIP97_GLOBAL_BUSY_RETRY_LATER);
+        }
+        else if (rc != EIP97_GLOBAL_NO_ERROR)
+        {
+            LOG_CRIT("GlobalControl97_Init: Error from EIP97_Global_Reset\n");
+            goto exit; // error
+        }
+    }
+
+    ZEROINIT(Capabilities);
+
+    rc = EIP97_Global_HWRevision_Get(&Global_IOArea, &Capabilities);
+    if (rc != EIP97_GLOBAL_NO_ERROR)
+    {
+        LOG_CRIT("GlobalControl97_Init: returned error");
+        goto exit; // error
+    }
+    Global_PRNG_Present = !Capabilities.EIP97_Options.central_prng;
+
+    if (GlobalControl97Lib_Resume(NULL) != 0)
+        goto exit; // error
+    else
+    {
+        Global_IsInitialized = true;
+
+        GlobalControl97_NofRings = Capabilities.EIP202_Options.NofRings;
+        GlobalControl97_NofLAInterfaces = Capabilities.EIP202_Options2.NofLA_Ifs;
+        GlobalControl97_NofInlineInterfaces = Capabilities.EIP202_Options2.NofIN_Ifs;
+
+#ifdef GLOBALCONTROL_BUILD
+        if (SHDevXS_Global_Init() != 0)
+        {
+            LOG_CRIT(
+                "GlobalControl97_Init: SHDevXS_Global_Init() returned error");
+            goto exit; // error
+        }
+#else
+        // Pass HW default configuration parameters obtained via
+        // the Global Control interface to the Ring Control
+        // for its automatic configuration
+        Adapter_Ring_EIP202_Configure(Capabilities.EIP202_Options.HDW,
+                                      Capabilities.EIP202_Options.CF_Size,
+                                      Capabilities.EIP202_Options.RF_Size);
+#endif
+
+        GC97_Rc = GLOBAL_CONTROL_NO_ERROR; // success
+    }
+
+exit:
+    (void)RPM_DEVICE_INIT_STOP_MACRO(ADAPTER_GLOBAL_RPM_EIP97_DEVICE_ID);
+
+    return GC97_Rc;
+}
+
+
+/*----------------------------------------------------------------------------
+ * GlobalControl97_UnInit
+ */
+GlobalControl97_Error_t
+GlobalControl97_UnInit(void)
+{
+    EIP97_Global_Error_t rc;
+    GlobalControl97_Error_t GC97_Rc = GLOBAL_CONTROL_ERROR_INTERNAL;
+    Device_Handle_t dev;
+
+    LOG_INFO("\n\t\t\t GlobalControl97_UnInit \n");
+
+    if (!Global_IsInitialized)
+    {
+        LOG_CRIT("GlobalControl97_UnInit: called while not initialized\n");
+        return GLOBAL_CONTROL_ERROR_BAD_USE_ORDER;
+    }
+
+    dev = Device_Find(ADAPTER_GLOBAL_DEVICE_NAME);
+    if (dev == NULL)
+    {
+        LOG_CRIT("GlobalControl97_UnInit: Could not find device\n");
+        return GLOBAL_CONTROL_ERROR_INTERNAL;
+    }
+
+    if (RPM_DEVICE_UNINIT_START_MACRO(ADAPTER_GLOBAL_RPM_EIP97_DEVICE_ID,
+                                      true) != RPM_SUCCESS)
+        return GLOBAL_CONTROL_ERROR_INTERNAL;
+
+    LOG_INFO("\n\t\t\t\t EIP97_Global_Reset \n");
+
+    rc = EIP97_Global_Reset(&Global_IOArea, dev);
+    if (rc == EIP97_GLOBAL_BUSY_RETRY_LATER)
+    {
+        unsigned int tries = 0;
+        do {
+            LOG_INFO("\n\t\t\t\t EIP97_Global_Reset_IsDone \n");
+
+            rc = EIP97_Global_Reset_IsDone(&Global_IOArea);
+            if (rc != EIP97_GLOBAL_NO_ERROR &&
+                rc != EIP97_GLOBAL_BUSY_RETRY_LATER)
+            {
+                LOG_CRIT("GlobalControl97_UnInit:"
+                         " Error from EIP97_Global_Reset_IsDone\n");
+                goto exit; // error
+            }
+                tries ++;
+                if (tries > ADAPTER_GLOBAL_RESET_MAX_RETRIES)
+                {
+                    LOG_CRIT("GlobalControl97_UnInit: Reset timeout\n");
+                    goto exit; // error
+                }
+        } while (rc == EIP97_GLOBAL_BUSY_RETRY_LATER);
+    }
+    else if (rc != EIP97_GLOBAL_NO_ERROR)
+    {
+        LOG_CRIT("GlobalControl97_Init: Error from EIP97_Global_Reset\n");
+        goto exit; // error
+    }
+
+#ifdef GLOBALCONTROL_BUILD
+    SHDevXS_Global_UnInit();
+#endif
+
+    Global_IsInitialized = false;
+
+    GC97_Rc = GLOBAL_CONTROL_NO_ERROR; // success
+
+exit:
+    (void)RPM_DEVICE_UNINIT_STOP_MACRO(ADAPTER_GLOBAL_RPM_EIP97_DEVICE_ID);
+
+    return GC97_Rc;
+}
+
+
+/*----------------------------------------------------------------------------
+ * GlobalControl97_Configure
+ */
+GlobalControl97_Error_t
+GlobalControl97_Configure(
+        const unsigned int PE_Number,
+        const GlobalControl97_Ring_PE_Map_t * const RingPEMap_p)
+{
+    EIP97_Global_Error_t rc;
+
+    LOG_INFO("\n\t\t\t GlobalControl97_Configure \n");
+
+    if (RPM_DEVICE_IO_START_MACRO(ADAPTER_GLOBAL_RPM_EIP97_DEVICE_ID,
+                            RPM_FLAG_SYNC) != RPM_SUCCESS)
+        return GLOBAL_CONTROL_ERROR_INTERNAL;
+
+    LOG_INFO("\n\t\t\t\t EIP97_Global_Configure \n");
+
+    rc = EIP97_Global_Configure(&Global_IOArea, PE_Number, RingPEMap_p);
+
+    (void)RPM_DEVICE_IO_STOP_MACRO(ADAPTER_GLOBAL_RPM_EIP97_DEVICE_ID,
+                                   RPM_FLAG_ASYNC);
+
+    if (rc == EIP97_GLOBAL_NO_ERROR)
+    {
+        // Fall back on EIP97_Global_Configure() for PE_Number bounds check
+        GlobalControl97_RingPEMap[PE_Number].fCached   = true;
+        GlobalControl97_RingPEMap[PE_Number].RingPEMap = *RingPEMap_p;
+        return GLOBAL_CONTROL_NO_ERROR;
+    }
+    else if (rc == EIP97_GLOBAL_ARGUMENT_ERROR)
+        return GLOBAL_CONTROL_ERROR_BAD_PARAMETER;
+    else
+        return GLOBAL_CONTROL_ERROR_INTERNAL;
+}
+
+
+/*----------------------------------------------------------------------------
+ * GlobalControl97_PRNG_Reseed
+ */
+GlobalControl97_Error_t
+GlobalControl97_PRNG_Reseed(
+        const unsigned int PE_Number,
+        const GlobalControl97_PRNG_Reseed_t * const ReseedData_p)
+{
+    EIP97_Global_Error_t rc;
+
+    LOG_INFO("\n\t\t\t GlobalControl97_PRNG_Reseed \n");
+
+    if (!Global_PRNG_Present)
+    {
+        LOG_CRIT("%s: PRNG device not present\n",__func__);
+        return GLOBAL_CONTROL_ERROR_NOT_IMPLEMENTED;
+    }
+
+    if (RPM_DEVICE_IO_START_MACRO(ADAPTER_GLOBAL_RPM_EIP97_DEVICE_ID,
+                            RPM_FLAG_SYNC) != RPM_SUCCESS)
+        return GLOBAL_CONTROL_ERROR_INTERNAL;
+
+    LOG_INFO("\n\t\t\t\t EIP97_Global_PRNG_Reseed \n");
+
+    rc = EIP97_Global_PRNG_Reseed(&Global_IOArea, PE_Number, ReseedData_p);
+
+    (void)RPM_DEVICE_IO_STOP_MACRO(ADAPTER_GLOBAL_RPM_EIP97_DEVICE_ID,
+                                   RPM_FLAG_ASYNC);
+
+    if (rc == EIP97_GLOBAL_NO_ERROR)
+    {
+        GlobalControl97_Prng[PE_Number].fCached     = true;
+        GlobalControl97_Prng[PE_Number].ReseedData  = *ReseedData_p;
+        return GLOBAL_CONTROL_NO_ERROR;
+    }
+    else if (rc == EIP97_GLOBAL_ARGUMENT_ERROR)
+        return GLOBAL_CONTROL_ERROR_BAD_PARAMETER;
+    else
+        return GLOBAL_CONTROL_ERROR_INTERNAL;
+
+}
+
+
+/*----------------------------------------------------------------------------
+ * GlobalControl97_DFE_Status_Get
+ */
+GlobalControl97_Error_t
+GlobalControl97_DFE_Status_Get(
+        const unsigned int PE_Number,
+        GlobalControl97_DFE_Status_t * const DFE_Status_p)
+{
+    EIP97_Global_Error_t rc;
+
+    LOG_INFO("\n\t\t\t GlobalControl97_DFE_Status_Get \n");
+
+    if (RPM_DEVICE_IO_START_MACRO(ADAPTER_GLOBAL_RPM_EIP97_DEVICE_ID,
+                            RPM_FLAG_SYNC) != RPM_SUCCESS)
+        return GLOBAL_CONTROL_ERROR_INTERNAL;
+
+    LOG_INFO("\n\t\t\t\t EIP97_Global_DFE_Status_Get \n");
+
+    rc = EIP97_Global_DFE_Status_Get(&Global_IOArea, PE_Number, DFE_Status_p);
+
+    (void)RPM_DEVICE_IO_STOP_MACRO(ADAPTER_GLOBAL_RPM_EIP97_DEVICE_ID,
+                                   RPM_FLAG_ASYNC);
+
+    if (rc == EIP97_GLOBAL_NO_ERROR)
+        return GLOBAL_CONTROL_NO_ERROR;
+    else if (rc == EIP97_GLOBAL_ARGUMENT_ERROR)
+        return GLOBAL_CONTROL_ERROR_BAD_PARAMETER;
+    else
+        return GLOBAL_CONTROL_ERROR_INTERNAL;
+}
+
+
+/*----------------------------------------------------------------------------
+ * GlobalControl97_DSE_Status_Get
+ */
+GlobalControl97_Error_t
+GlobalControl97_DSE_Status_Get(
+        const unsigned int PE_Number,
+        GlobalControl97_DSE_Status_t * const DSE_Status_p)
+{
+    EIP97_Global_Error_t rc;
+
+    LOG_INFO("\n\t\t\t GlobalControl97_DSE_Status_Get \n");
+
+    if (RPM_DEVICE_IO_START_MACRO(ADAPTER_GLOBAL_RPM_EIP97_DEVICE_ID,
+                            RPM_FLAG_SYNC) != RPM_SUCCESS)
+        return GLOBAL_CONTROL_ERROR_INTERNAL;
+
+    LOG_INFO("\n\t\t\t\t EIP97_Global_DSE_Status_Get \n");
+
+    rc = EIP97_Global_DSE_Status_Get(&Global_IOArea, PE_Number, DSE_Status_p);
+
+    (void)RPM_DEVICE_IO_STOP_MACRO(ADAPTER_GLOBAL_RPM_EIP97_DEVICE_ID, RPM_FLAG_ASYNC);
+
+    if (rc == EIP97_GLOBAL_NO_ERROR)
+        return GLOBAL_CONTROL_NO_ERROR;
+    else if (rc == EIP97_GLOBAL_ARGUMENT_ERROR)
+        return GLOBAL_CONTROL_ERROR_BAD_PARAMETER;
+    else
+        return GLOBAL_CONTROL_ERROR_INTERNAL;
+}
+
+
+/*----------------------------------------------------------------------------
+ * GlobalControl97_Token_Status_Get
+ */
+GlobalControl97_Error_t
+GlobalControl97_Token_Status_Get(
+        const unsigned int PE_Number,
+        GlobalControl97_Token_Status_t * const Token_Status_p)
+{
+    EIP97_Global_Error_t rc;
+
+    LOG_INFO("\n\t\t\t GlobalControl97_Token_Status_Get \n");
+
+    if (RPM_DEVICE_IO_START_MACRO(ADAPTER_GLOBAL_RPM_EIP97_DEVICE_ID,
+                            RPM_FLAG_SYNC) != RPM_SUCCESS)
+        return GLOBAL_CONTROL_ERROR_INTERNAL;
+
+    LOG_INFO("\n\t\t\t\t EIP97_Global_EIP96_Token_Status_Get \n");
+
+    rc = EIP97_Global_EIP96_Token_Status_Get(&Global_IOArea,
+                                             PE_Number,
+                                             Token_Status_p);
+
+    (void)RPM_DEVICE_IO_STOP_MACRO(ADAPTER_GLOBAL_RPM_EIP97_DEVICE_ID,
+                                   RPM_FLAG_ASYNC);
+
+    if (rc == EIP97_GLOBAL_NO_ERROR)
+        return GLOBAL_CONTROL_NO_ERROR;
+    else if (rc == EIP97_GLOBAL_ARGUMENT_ERROR)
+        return GLOBAL_CONTROL_ERROR_BAD_PARAMETER;
+    else
+        return GLOBAL_CONTROL_ERROR_INTERNAL;
+}
+
+
+/*----------------------------------------------------------------------------
+ * GlobalControl97_Context_Status_Get
+ */
+GlobalControl97_Error_t
+GlobalControl97_Context_Status_Get(
+        const unsigned int PE_Number,
+        GlobalControl97_Context_Status_t * const Context_Status_p)
+{
+    EIP97_Global_Error_t rc;
+
+    LOG_INFO("\n\t\t\t GlobalControl97_Context_Status_Get \n");
+
+    if (RPM_DEVICE_IO_START_MACRO(ADAPTER_GLOBAL_RPM_EIP97_DEVICE_ID,
+                            RPM_FLAG_SYNC) != RPM_SUCCESS)
+        return GLOBAL_CONTROL_ERROR_INTERNAL;
+
+    LOG_INFO("\n\t\t\t\t EIP97_Global_EIP96_Context_Status_Get \n");
+
+    rc = EIP97_Global_EIP96_Context_Status_Get(&Global_IOArea,
+                                               PE_Number,
+                                               Context_Status_p);
+
+    (void)RPM_DEVICE_IO_STOP_MACRO(ADAPTER_GLOBAL_RPM_EIP97_DEVICE_ID,
+                                   RPM_FLAG_ASYNC);
+
+    if (rc == EIP97_GLOBAL_NO_ERROR)
+        return GLOBAL_CONTROL_NO_ERROR;
+    else if (rc == EIP97_GLOBAL_ARGUMENT_ERROR)
+        return GLOBAL_CONTROL_ERROR_BAD_PARAMETER;
+    else
+        return GLOBAL_CONTROL_ERROR_INTERNAL;
+}
+
+
+/*----------------------------------------------------------------------------
+ * GlobalControl97_Interrupt_Status_Get
+ */
+GlobalControl97_Error_t
+GlobalControl97_Interrupt_Status_Get(
+        const unsigned int PE_Number,
+        GlobalControl97_Interrupt_Status_t * const Interrupt_Status_p)
+{
+    IDENTIFIER_NOT_USED(PE_Number);
+
+    LOG_INFO("\n\t\t\t GlobalControl97_Interrupt_Status_Get \n");
+
+    // Not implemented yet, must use EIP-96 AIC
+    ZEROINIT(*Interrupt_Status_p);
+
+    return GLOBAL_CONTROL_NO_ERROR;
+}
+
+
+/*----------------------------------------------------------------------------
+ * GlobalControl97_OutXfer_Status_Get
+ */
+GlobalControl97_Error_t
+GlobalControl97_OutXfer_Status_Get(
+        const unsigned int PE_Number,
+        GlobalControl97_Output_Transfer_Status_t * const OutXfer_Status_p)
+{
+    EIP97_Global_Error_t rc;
+
+    LOG_INFO("\n\t\t\t GlobalControl97_OutXfer_Status_Get \n");
+
+    if (RPM_DEVICE_IO_START_MACRO(ADAPTER_GLOBAL_RPM_EIP97_DEVICE_ID,
+                            RPM_FLAG_SYNC) != RPM_SUCCESS)
+        return GLOBAL_CONTROL_ERROR_INTERNAL;
+
+    LOG_INFO("\n\t\t\t\t EIP97_Global_EIP96_OutXfer_Status_Get \n");
+
+    rc = EIP97_Global_EIP96_OutXfer_Status_Get(&Global_IOArea,
+                                               PE_Number,
+                                               OutXfer_Status_p);
+
+    (void)RPM_DEVICE_IO_STOP_MACRO(ADAPTER_GLOBAL_RPM_EIP97_DEVICE_ID,
+                                   RPM_FLAG_ASYNC);
+
+    if (rc == EIP97_GLOBAL_NO_ERROR)
+        return GLOBAL_CONTROL_NO_ERROR;
+    else if (rc == EIP97_GLOBAL_ARGUMENT_ERROR)
+        return GLOBAL_CONTROL_ERROR_BAD_PARAMETER;
+    else
+        return GLOBAL_CONTROL_ERROR_INTERNAL;
+}
+
+
+/*----------------------------------------------------------------------------
+ * GlobalControl97_PRNG_Status_Get
+ */
+GlobalControl97_Error_t
+GlobalControl97_PRNG_Status_Get(
+        const unsigned int PE_Number,
+        GlobalControl97_PRNG_Status_t * const PRNG_Status_p)
+{
+    EIP97_Global_Error_t rc;
+
+    LOG_INFO("\n\t\t\t GlobalControl97_PRNG_Status_Get \n");
+
+    if (!Global_PRNG_Present)
+    {
+        return GLOBAL_CONTROL_ERROR_NOT_IMPLEMENTED;
+    }
+
+    if (RPM_DEVICE_IO_START_MACRO(ADAPTER_GLOBAL_RPM_EIP97_DEVICE_ID,
+                            RPM_FLAG_SYNC) != RPM_SUCCESS)
+        return GLOBAL_CONTROL_ERROR_INTERNAL;
+
+    LOG_INFO("\n\t\t\t\t EIP97_Global_EIP96_PRNG_Status_Get \n");
+
+    rc = EIP97_Global_EIP96_PRNG_Status_Get(&Global_IOArea,
+                                            PE_Number,
+                                            PRNG_Status_p);
+
+    (void)RPM_DEVICE_IO_STOP_MACRO(ADAPTER_GLOBAL_RPM_EIP97_DEVICE_ID,
+                                   RPM_FLAG_ASYNC);
+
+    if (rc == EIP97_GLOBAL_NO_ERROR)
+        return GLOBAL_CONTROL_NO_ERROR;
+    else if (rc == EIP97_GLOBAL_ARGUMENT_ERROR)
+        return GLOBAL_CONTROL_ERROR_BAD_PARAMETER;
+    else
+        return GLOBAL_CONTROL_ERROR_INTERNAL;
+}
+
+#ifdef ADAPTER_GLOBAL_DBG_STATISTICS
+/*----------------------------------------------------------------------------
+ * GlobalControl97_Debug_Statistics_Get
+ */
+GlobalControl97_Error_t
+GlobalControl97_Debug_Statistics_Get(
+        GlobalControl97_Debug_Statistics_t * const Debug_Statistics_p)
+{
+    EIP97_Global_Error_t rc;
+
+    LOG_INFO("\n\t\t\t GlobalControl97_DSE_Debug_Statistics_Get \n");
+
+    if (RPM_DEVICE_IO_START_MACRO(ADAPTER_GLOBAL_RPM_EIP97_DEVICE_ID,
+                            RPM_FLAG_SYNC) != RPM_SUCCESS)
+        return GLOBAL_CONTROL_ERROR_INTERNAL;
+
+    LOG_INFO("\n\t\t\t\t EIP97_Global_Deubg_Statistics_Get \n");
+
+    rc = EIP97_Global_Debug_Statistics_Get(&Global_IOArea, Debug_Statistics_p);
+
+    (void)RPM_DEVICE_IO_STOP_MACRO(ADAPTER_GLOBAL_RPM_EIP97_DEVICE_ID, RPM_FLAG_ASYNC);
+
+    if (rc == EIP97_GLOBAL_NO_ERROR)
+        return GLOBAL_CONTROL_NO_ERROR;
+    else if (rc == EIP97_GLOBAL_ARGUMENT_ERROR)
+        return GLOBAL_CONTROL_ERROR_BAD_PARAMETER;
+    else
+        return GLOBAL_CONTROL_ERROR_INTERNAL;
+}
+#endif
+
+/*----------------------------------------------------------------------------
+ * GlobalControl97_Interfaces_Get
+ */
+void
+GlobalControl97_Interfaces_Get(
+    unsigned int * const NofPEs_p,
+    unsigned int * const NofRings_p,
+    unsigned int * const NofLAInterfaces_p,
+    unsigned int * const NofInlineInterfaces_p)
+{
+    if (NofPEs_p)
+        *NofPEs_p = GlobalControl97_NofPEs;
+    if (NofRings_p)
+        *NofRings_p = GlobalControl97_NofRings;
+    if (NofLAInterfaces_p)
+        *NofLAInterfaces_p = GlobalControl97_NofLAInterfaces;
+    if (NofInlineInterfaces_p)
+        *NofInlineInterfaces_p = GlobalControl97_NofInlineInterfaces;
+}
+
+
+/* end of file adapter_global_eip97.c */
diff --git a/package-21.02/kernel/crypto-eip/src/ddk/slad/adapter_global_init.c b/package-21.02/kernel/crypto-eip/src/ddk/slad/adapter_global_init.c
new file mode 100644
index 0000000..35a6cac
--- /dev/null
+++ b/package-21.02/kernel/crypto-eip/src/ddk/slad/adapter_global_init.c
@@ -0,0 +1,417 @@
+/* adapter_global_init.c
+ *
+ * Global Control initialization module.
+ */
+
+/*****************************************************************************
+* Copyright (c) 2011-2022 by Rambus, Inc. and/or its subsidiaries.
+*
+* This program is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 2 of the License, or
+* any later version.
+*
+* This program is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with this program. If not, see <http://www.gnu.org/licenses/>.
+*****************************************************************************/
+
+/*----------------------------------------------------------------------------
+ * This module implements (provides) the following interface(s):
+ */
+#include "adapter_global_init.h"
+
+
+/*----------------------------------------------------------------------------
+ * This module uses (requires) the following interface(s):
+ */
+
+// Default Adapter configuration
+#include "c_adapter_global.h"   // ADAPTER_GLOBAL_PRNG_SEED
+
+// Global Control API: Packet I/O
+#include "api_global_eip97.h"
+
+// Driver Framework Basic Definitions API
+#include "basic_defs.h"         // uint8_t, uint32_t, bool
+
+// Driver Framework C Library API
+#include "clib.h"               // memcpy
+
+// EIP-97 Driver Library Global Control API
+#include "eip97_global_event.h" // Event Management
+#include "eip97_global_init.h"  // Init/Uninit
+#include "eip97_global_prng.h"  // PRNG Control
+
+#include "device_types.h"       // Device_Handle_t
+#include "device_mgmt.h"        // Device_find
+#include "log.h"                // Log API
+
+#include "adapter_global_internal.h"
+
+/*----------------------------------------------------------------------------
+ * Definitions and macros
+ */
+
+
+/*----------------------------------------------------------------------------
+ * Local variables
+ */
+static const uint32_t Global_PRNG_Key[8] = ADAPTER_GLOBAL_PRNG_SEED;
+
+/*----------------------------------------------------------------------------
+ * BoolToString()
+ *
+ * Convert boolean value to string.
+ */
+static const char *
+BoolToString(
+        const bool b)
+{
+    if (b)
+        return "true";
+    else
+        return "false";
+}
+
+/*----------------------------------------------------------------------------
+ * Adapter_Global_StatusReport()
+ *
+ * Obtain all available global status information from the EIP-97 driver
+ * and report it.
+ */
+static void
+Adapter_Global_StatusReport(void)
+{
+    GlobalControl97_Error_t rc;
+    unsigned int i;
+    unsigned int NofPEs;
+    GlobalControl97_Interfaces_Get(&NofPEs,NULL,NULL,NULL);
+
+    LOG_INFO("\n\t\t Adapter_Global_StatusReport \n");
+
+    LOG_CRIT("Global Status of the EIP-97\n");
+
+    for (i=0; i < NofPEs; i++)
+    {
+        LOG_CRIT("Packet Engine %d Status\n", i);
+        {
+            GlobalControl97_DFE_Status_t DFE_Status;
+
+            rc = GlobalControl97_DFE_Status_Get(i, &DFE_Status);
+
+            if (rc != GLOBAL_CONTROL_NO_ERROR)
+            {
+                continue;
+            }
+
+            LOG_CRIT("DFE Status: CD FIFO Words: %d, CDR ID: %d, DMA size: %d\n"
+                     "AtDMA busy: %s, DataDMA busy: %s, DMA err: %s\n",
+                     DFE_Status.CDFifoWord32Count,
+                     DFE_Status.CDR_ID,
+                     DFE_Status.DMASize,
+                     BoolToString(DFE_Status.fAtDMABusy),
+                     BoolToString(DFE_Status.fDataDMABusy),
+                     BoolToString(DFE_Status.fDMAError));
+        }
+
+        {
+            GlobalControl97_DSE_Status_t DSE_Status;
+
+            rc = GlobalControl97_DSE_Status_Get(i, &DSE_Status);
+
+            if (rc != GLOBAL_CONTROL_NO_ERROR)
+            {
+                continue;
+            }
+
+            LOG_CRIT("DSE Status: RD FIFO Words: %d, RDR ID: %d, DMA size: %d\n"
+                     "Data flush  busy: %s, DataDMA busy: %s, DMA err: %s\n",
+                     DSE_Status.RDFifoWord32Count,
+                     DSE_Status.RDR_ID,
+                     DSE_Status.DMASize,
+                     BoolToString(DSE_Status.fDataFlushBusy),
+                     BoolToString(DSE_Status.fDataDMABusy),
+                     BoolToString(DSE_Status.fDMAError));
+        }
+
+        {
+            GlobalControl97_Token_Status_t Token_Status;
+            rc = GlobalControl97_Token_Status_Get(i, &Token_Status);
+
+            if (rc != GLOBAL_CONTROL_NO_ERROR)
+            {
+                continue;
+            }
+
+            LOG_CRIT("Token Status: Active: %d, loc available: %s\n"
+                     "res available: %s, read active: %s, ccache active: %s\n"
+                     "cntx fetch: %s, res cntx: %s\n"
+                     "processing held: %s, busy: %s\n",
+                     Token_Status.ActiveTokenCount,
+                     BoolToString(Token_Status.fTokenLocationAvailable),
+                     BoolToString(Token_Status.fResultTokenAvailable),
+                     BoolToString(Token_Status.fTokenReadActive),
+                     BoolToString(Token_Status.fContextCacheActive),
+                     BoolToString(Token_Status.fContextFetch),
+                     BoolToString(Token_Status.fResultContext),
+                     BoolToString(Token_Status.fProcessingHeld),
+                     BoolToString(Token_Status.fBusy));
+        }
+
+        {
+            GlobalControl97_Context_Status_t Context_Status;
+
+            rc = GlobalControl97_Context_Status_Get(i, &Context_Status);
+
+            if (rc != GLOBAL_CONTROL_NO_ERROR)
+            {
+                continue;
+            }
+
+            LOG_CRIT("Context Status: Err mask: %04x, Available: %d\n"
+                     "Active cntx: %s, next cntx: %s, result cntx: %s"
+                     " Err recov: %s\n",
+                     Context_Status.Error,
+                     Context_Status.AvailableTokenCount,
+                     BoolToString(Context_Status.fActiveContext),
+                     BoolToString(Context_Status.fNextContext),
+                     BoolToString(Context_Status.fResultContext),
+                     BoolToString(Context_Status.fErrorRecovery));
+        }
+
+        {
+            GlobalControl97_Interrupt_Status_t Interrupt_Status;
+
+            rc = GlobalControl97_Interrupt_Status_Get(i, &Interrupt_Status);
+
+            if (rc != GLOBAL_CONTROL_NO_ERROR)
+            {
+                continue;
+            }
+
+            LOG_CRIT("Interrupt Status: input DMA err: %s, output DMA err %s \n"
+                     "pkt proc err: %s, pkt timeout: %s, f a t a l err: %s, "
+                     "PE int out: %s\n"
+                     "inp DMA enable: %s, outp DMA enable %s, "
+                     "pkt proc enable: %s\n"
+                     "pkt timeout enable: %s, f a t a l enable: %s,"
+                     "PE int out enable: %s\n",
+                     BoolToString(Interrupt_Status.fInputDMAError),
+                     BoolToString(Interrupt_Status.fOutputDMAError),
+                     BoolToString(Interrupt_Status.fPacketProcessingError),
+                     BoolToString(Interrupt_Status.fPacketTimeout),
+                     BoolToString(Interrupt_Status.fFatalError),
+                     BoolToString(Interrupt_Status.fPeInterruptOut),
+                     BoolToString(Interrupt_Status.fInputDMAErrorEnabled),
+                     BoolToString(Interrupt_Status.fOutputDMAErrorEnabled),
+                     BoolToString(Interrupt_Status.fPacketProcessingEnabled),
+                     BoolToString(Interrupt_Status.fPacketTimeoutEnabled),
+                     BoolToString(Interrupt_Status.fFatalErrorEnabled),
+                     BoolToString(Interrupt_Status.fPeInterruptOutEnabled));
+        }
+        {
+            GlobalControl97_Output_Transfer_Status_t OutXfer_Status;
+
+            rc = GlobalControl97_OutXfer_Status_Get(i, &OutXfer_Status);
+
+            if (rc != GLOBAL_CONTROL_NO_ERROR)
+            {
+                continue;
+            }
+
+            LOG_CRIT("Output Transfer Status: availabe: %d, "
+                     "min: %d, max: %d, size mask: %d\n",
+                     OutXfer_Status.AvailableWord32Count,
+                     OutXfer_Status.MinTransferWordCount,
+                     OutXfer_Status.MaxTransferWordCount,
+                     OutXfer_Status.TransferSizeMask);
+        }
+        {
+            GlobalControl97_PRNG_Status_t PRNG_Status;
+
+            rc = GlobalControl97_PRNG_Status_Get(i, &PRNG_Status);
+
+            if (rc == GLOBAL_CONTROL_ERROR_NOT_IMPLEMENTED)
+            {
+                LOG_CRIT("No PRNG present in EIP-96\n");
+            }
+            else if (rc == GLOBAL_CONTROL_NO_ERROR)
+            {
+                    LOG_CRIT("PRNG Status: busy: %s, res ready: %s\n",
+                             BoolToString(PRNG_Status.fBusy),
+                             BoolToString(PRNG_Status.fResultReady));
+            }
+        }
+    }
+#ifdef ADAPTER_GLOBAL_DBG_STATISTICS
+    {
+        GlobalControl97_Debug_Statistics_t Debug_Statistics;
+
+        rc = GlobalControl97_Debug_Statistics_Get(&Debug_Statistics);
+
+        if (rc != GLOBAL_CONTROL_NO_ERROR)
+        {
+           return;
+        }
+
+        LOG_CRIT("\nInterface DBG Statistics:\n");
+        for (i=0; i<16; i++)
+        {
+            if(Debug_Statistics.Ifc_Packets_In[i] != 0 ||
+               Debug_Statistics.Ifc_Packets_Out[i] != 0)
+            {
+                LOG_CRIT("\t\tInterface #%2u Input pkts=%10u Output pkts=%10u\n",
+                         i,
+                         (unsigned int)Debug_Statistics.Ifc_Packets_In[i],
+                         (unsigned int)Debug_Statistics.Ifc_Packets_Out[i]);
+            }
+        }
+        LOG_CRIT("\nPipe DBG Statistics:\n");
+        for (i=0; i <NofPEs; i++)
+        {
+            LOG_CRIT("\t\tPipe #%2u Total=%10u Data=%10u Cur=%3u Max=%3u\n",
+                     i,
+                     (unsigned int)Debug_Statistics.Pipe_Total_Packets[i],
+                     (unsigned int)Debug_Statistics.Pipe_Data_Count[i],
+                     (unsigned int)Debug_Statistics.Pipe_Current_Packets[i],
+                     (unsigned int)Debug_Statistics.Pipe_Max_Packets[i]);
+        }
+    }
+#endif
+}
+
+
+/*----------------------------------------------------------------------------
+ * Adapter_Global_Init()
+ *
+ */
+bool
+Adapter_Global_Init(void)
+{
+    unsigned int NofPEs, NofRings, NofLAInterfaces, NofInlineInterfaces;
+    GlobalControl97_Error_t rc;
+    unsigned int i;
+
+    LOG_INFO("\n\t\t Adapter_Global_Init \n");
+
+    // Initialize the device
+    rc = GlobalControl97_Init(false);
+    if (rc != GLOBAL_CONTROL_NO_ERROR)
+    {
+        LOG_CRIT("Adaptar_Global_Init: EIP97 initialization failed\n");
+        return false; // error
+    }
+
+    GlobalControl97_Interfaces_Get(&NofPEs,
+                                   &NofRings,
+                                   &NofLAInterfaces,
+                                   &NofInlineInterfaces);
+
+    // First read the device capabilities
+    {
+        GlobalControl97_Capabilities_t Capabilities;
+
+        rc = GlobalControl97_Capabilities_Get(&Capabilities);
+        if ( rc != GLOBAL_CONTROL_NO_ERROR)
+        {
+            LOG_CRIT("GlobalControl97_Capabilities_Get returned error\n");
+        }
+        else
+        {
+            LOG_CRIT("Global EIP-97 capabilities: %s\n",
+                     Capabilities.szTextDescription);
+        }
+    }
+
+    // Enable the rings for the packet engines
+    {
+        GlobalControl97_Ring_PE_Map_t RingPEMap;
+
+        ZEROINIT(RingPEMap);
+
+        // Enable rings
+        RingPEMap.RingPE_Mask = (1 << (NofRings + NofLAInterfaces + NofInlineInterfaces)) - 1;
+
+        // Set rings priority
+        RingPEMap.RingPrio_Mask = ADAPTER_GLOBAL_EIP97_PRIOMASK;
+
+        for (i=0; i < NofPEs; i++)
+        {
+            rc = GlobalControl97_Configure(i, &RingPEMap);
+            if (rc != GLOBAL_CONTROL_NO_ERROR)
+            {
+                LOG_CRIT("Ring configuration failed for PE %d\n", i);
+                GlobalControl97_UnInit();
+                return false; // error
+            }
+        }
+    }
+
+    {
+        GlobalControl97_PRNG_Status_t PRNG_Status;
+        // Check whether we have a PRNG.
+        rc = GlobalControl97_PRNG_Status_Get(0, &PRNG_Status);
+
+        if (rc != GLOBAL_CONTROL_NO_ERROR && rc != GLOBAL_CONTROL_ERROR_NOT_IMPLEMENTED)
+        {
+                return false;
+        }
+
+        if (rc != GLOBAL_CONTROL_ERROR_NOT_IMPLEMENTED)
+        {
+            for (i=0; i < NofPEs; i++)
+            {
+                GlobalControl97_PRNG_Reseed_t PRNG_Reseed;
+
+                PRNG_Reseed.SeedLo = Global_PRNG_Key[0];
+                PRNG_Reseed.SeedHi = Global_PRNG_Key[1];
+                PRNG_Reseed.Key0Lo = Global_PRNG_Key[2];
+                PRNG_Reseed.Key0Hi = Global_PRNG_Key[3];
+                PRNG_Reseed.Key1Lo = Global_PRNG_Key[4];
+                PRNG_Reseed.Key1Hi = Global_PRNG_Key[5];
+                PRNG_Reseed.LFSRLo = Global_PRNG_Key[6];
+                PRNG_Reseed.LFSRHi = Global_PRNG_Key[7];
+
+                rc = GlobalControl97_PRNG_Reseed(i, &PRNG_Reseed);
+
+                if (rc != GLOBAL_CONTROL_NO_ERROR)
+                {
+                    LOG_CRIT("Could not reseed PRNG of PE#%d\n",i);
+                    GlobalControl97_UnInit();
+                    return false; // error
+                }
+            }
+        }
+        else
+        {
+            LOG_CRIT("No PRNG in PEs, skip initialization\n");
+        }
+    }
+
+    Adapter_Global_StatusReport();
+
+    return true; // success
+}
+
+
+/*----------------------------------------------------------------------------
+ * Adapter_Global_UnInit()
+ *
+ */
+void
+Adapter_Global_UnInit(void)
+{
+    LOG_INFO("\n\t\t Adapter_Global_UnInit \n");
+
+    Adapter_Global_StatusReport();
+
+    GlobalControl97_UnInit();
+}
+
+
+/* end of file adapter_global_eip97.c */
diff --git a/package-21.02/kernel/crypto-eip/src/ddk/slad/adapter_init.c b/package-21.02/kernel/crypto-eip/src/ddk/slad/adapter_init.c
new file mode 100644
index 0000000..ef08853
--- /dev/null
+++ b/package-21.02/kernel/crypto-eip/src/ddk/slad/adapter_init.c
@@ -0,0 +1,413 @@
+/* adapter_init.c
+ *
+ * Adapter module responsible for adapter initialization tasks.
+ *
+ */
+
+/*****************************************************************************
+* Copyright (c) 2011-2022 by Rambus, Inc. and/or its subsidiaries.
+*
+* This program is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 2 of the License, or
+* any later version.
+*
+* This program is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with this program. If not, see <http://www.gnu.org/licenses/>.
+*****************************************************************************/
+
+/*----------------------------------------------------------------------------
+ * This module implements (provides) the following interface(s):
+ */
+
+#include "adapter_init.h"
+
+
+/*----------------------------------------------------------------------------
+ * This module uses (requires) the following interface(s):
+ */
+
+// Top-level Adapter configuration
+#include "cs_adapter.h"
+
+#ifdef ADAPTER_PEC_INTERRUPTS_ENABLE
+#include "adapter_interrupts.h" // Adapter_Interrupts_Init,
+                                // Adapter_Interrupts_UnInit
+#endif
+
+// Runtime Power Management Device Macros API
+#include "rpm_device_macros.h"  // RPM_*
+
+// Logging API
+#include "log.h"            // LOG_*
+
+// Driver Framework Device API
+#include "device_mgmt.h"    // Device_Initialize, Device_UnInitialize
+#include "device_rw.h"      // Device_Read32, Device_Write32
+
+// Driver Framework DMAResource API
+#include "dmares_mgmt.h"    // DMAResource_Init, DMAResource_UnInit
+
+// Driver Framework C Library API
+#include "clib.h"           // memcpy, ZEROINIT
+
+// Driver Framework Basic Definitions API
+#include "basic_defs.h"     // bool, true, false
+
+
+/*----------------------------------------------------------------------------
+ * Local variables
+ */
+
+static bool Adapter_IsInitialized = false;
+
+#ifdef ADAPTER_GLOBAL_BOARDCTRL_SUPPORT_ENABLE
+static Device_Handle_t Adapter_Device_BOARDCTRL;
+#endif
+
+static int Device_IRQ;
+
+/*----------------------------------------------------------------------------
+ * Forward declarations
+ */
+
+static int
+AdapterLib_EIP197_Resume(void * p);
+
+#ifdef ADAPTER_GLOBAL_RPM_EIP197_DEVICE_ID
+static int
+AdapterLib_EIP197_Suspend(void * p);
+#endif // ADAPTER_GLOBAL_RPM_EIP197_DEVICE_ID
+
+#ifdef ADAPTER_PEC_INTERRUPTS_ENABLE
+#ifdef ADAPTER_GLOBAL_RPM_EIP201_DEVICE_ID
+static int
+AdapterLib_EIP201_Resume(void * p);
+#endif
+#endif
+
+
+/*----------------------------------------------------------------------------
+ * AdapterLib_EIP197_Resume
+ *
+ */
+static int
+AdapterLib_EIP197_Resume(void * p)
+{
+    IDENTIFIER_NOT_USED(p);
+
+    // FPGA board specific functionality
+#ifdef ADAPTER_GLOBAL_BOARDCTRL_SUPPORT_ENABLE
+    {
+#ifdef ADAPTER_GLOBAL_FPGA_HW_RESET_ENABLE
+        LOG_INFO("%s: reset FPGA\n", __func__);
+        // Perform HW Reset for the EIP-197 FPGA board
+        Device_Write32(Adapter_Device_BOARDCTRL, 0x2000, 0);
+        Device_Write32(Adapter_Device_BOARDCTRL, 0x2000, 0xFFFFFFFF);
+        Device_Write32(Adapter_Device_BOARDCTRL, 0x2000, 0);
+#endif // ADAPTER_GLOBAL_FPGA_HW_RESET_ENABLE
+    }
+#endif // ADAPTER_GLOBAL_BOARDCTRL_SUPPORT_ENABLE
+
+    return 0; // success
+}
+
+
+#ifdef ADAPTER_GLOBAL_RPM_EIP197_DEVICE_ID
+/*----------------------------------------------------------------------------
+ * AdapterLib_EIP197_Suspend
+ *
+ */
+static int
+AdapterLib_EIP197_Suspend(void * p)
+{
+    IDENTIFIER_NOT_USED(p);
+
+    // FPGA board specific functionality
+#ifdef ADAPTER_GLOBAL_BOARDCTRL_SUPPORT_ENABLE
+    {
+#ifdef ADAPTER_GLOBAL_FPGA_HW_RESET_ENABLE
+        LOG_INFO("%s: reset FPGA\n", __func__);
+        // Perform HW Reset for the EIP-197 FPGA board
+        Device_Write32(Adapter_Device_BOARDCTRL, 0x2000, 0);
+        Device_Write32(Adapter_Device_BOARDCTRL, 0x2000, 0xFFFFFFFF);
+        Device_Write32(Adapter_Device_BOARDCTRL, 0x2000, 0);
+#endif // ADAPTER_GLOBAL_FPGA_HW_RESET_ENABLE
+    }
+#endif // ADAPTER_GLOBAL_BOARDCTRL_SUPPORT_ENABLE
+
+    return 0; // success
+}
+#endif // ADAPTER_GLOBAL_RPM_EIP197_DEVICE_ID
+
+
+#ifdef ADAPTER_PEC_INTERRUPTS_ENABLE
+#ifdef ADAPTER_GLOBAL_RPM_EIP201_DEVICE_ID
+/*----------------------------------------------------------------------------
+ * AdapterLib_EIP201_Resume
+ *
+ */
+static int
+AdapterLib_EIP201_Resume(void * p)
+{
+    IDENTIFIER_NOT_USED(p);
+
+    return Adapter_Interrupts_Resume();
+}
+#endif
+#endif
+
+
+/*----------------------------------------------------------------------------
+ * Adapter_Init
+ *
+ * Return Value
+ *     true   Success
+ *     false  Failure (fatal!)
+ */
+bool
+Adapter_Init(void)
+{
+    Device_IRQ = -1;
+
+    if (Adapter_IsInitialized != false)
+    {
+        LOG_WARN("Adapter_Init: Already initialized\n");
+        return true;
+    }
+
+    // trigger first-time initialization of the adapter
+    if (Device_Initialize(&Device_IRQ) < 0)
+        return false;
+
+#ifdef ADAPTER_GLOBAL_BOARDCTRL_SUPPORT_ENABLE
+    Adapter_Device_BOARDCTRL = Device_Find("BOARD_CTRL");
+    if (Adapter_Device_BOARDCTRL == NULL)
+    {
+        LOG_CRIT("Adapter_Init: Failed to locate BOARD_CTRL\n");
+        Device_UnInitialize();
+        return false;
+    }
+#endif // ADAPTER_GLOBAL_BOARDCTRL_SUPPORT_ENABLE
+
+    if (!DMAResource_Init())
+    {
+        Device_UnInitialize();
+        return false;
+    }
+
+    if (RPM_DEVICE_INIT_START_MACRO(ADAPTER_GLOBAL_RPM_EIP197_DEVICE_ID,
+                                    AdapterLib_EIP197_Suspend,
+                                    AdapterLib_EIP197_Resume)
+                                                   != RPM_SUCCESS)
+    {
+        DMAResource_UnInit();
+        Device_UnInitialize();
+        return false;
+    }
+
+    AdapterLib_EIP197_Resume(NULL);
+
+    (void)RPM_DEVICE_INIT_STOP_MACRO(ADAPTER_GLOBAL_RPM_EIP197_DEVICE_ID);
+
+#ifdef ADAPTER_PEC_INTERRUPTS_ENABLE
+    {
+        int res;
+
+        if (RPM_DEVICE_INIT_START_MACRO(ADAPTER_GLOBAL_RPM_EIP201_DEVICE_ID,
+                                        NULL, // Suspend callback not used
+                                        AdapterLib_EIP201_Resume)
+                                                         != RPM_SUCCESS)
+        {
+            DMAResource_UnInit();
+            Device_UnInitialize();
+            return false;
+        }
+
+        res = Adapter_Interrupts_Init(Device_IRQ);
+
+        (void)RPM_DEVICE_INIT_STOP_MACRO(ADAPTER_GLOBAL_RPM_EIP201_DEVICE_ID);
+
+        if (res < 0)
+        {
+            LOG_CRIT("Adapter_Init: Adapter_Interrupts_Init failed\n");
+            DMAResource_UnInit();
+            Device_UnInitialize();
+            return false;
+        }
+    }
+#endif
+
+    Adapter_IsInitialized = true;
+
+    return true;    // success
+}
+
+
+/*----------------------------------------------------------------------------
+ * Adapter_UnInit
+ */
+void
+Adapter_UnInit(void)
+{
+    if (!Adapter_IsInitialized)
+    {
+        LOG_WARN("Adapter_UnInit: Adapter is not initialized\n");
+        return;
+    }
+
+    Adapter_IsInitialized = false;
+
+    DMAResource_UnInit();
+
+#ifdef ADAPTER_PEC_INTERRUPTS_ENABLE
+    if (RPM_DEVICE_UNINIT_START_MACRO(ADAPTER_GLOBAL_RPM_EIP201_DEVICE_ID,
+                                      true) == RPM_SUCCESS)
+    {
+        Adapter_Interrupts_UnInit(Device_IRQ);
+        (void)RPM_DEVICE_UNINIT_STOP_MACRO(ADAPTER_GLOBAL_RPM_EIP201_DEVICE_ID);
+    }
+#endif
+
+    (void)RPM_DEVICE_UNINIT_START_MACRO(ADAPTER_GLOBAL_RPM_EIP197_DEVICE_ID, false);
+    (void)RPM_DEVICE_UNINIT_STOP_MACRO(ADAPTER_GLOBAL_RPM_EIP197_DEVICE_ID);
+
+    Device_UnInitialize();
+}
+
+
+/*----------------------------------------------------------------------------
+ * Adapter_Report_Build_Params
+ */
+void
+Adapter_Report_Build_Params(void)
+{
+    // This function is dependent on config file cs_adapter.h.
+    // Please update this when Config file for Adapter is changed.
+    Log_FormattedMessage("Adapter build configuration of %s:\n",
+        ADAPTER_VERSION_STRING);
+
+#define REPORT_SET(_X) \
+    Log_FormattedMessage("\t" #_X "\n")
+
+#define REPORT_STR(_X) \
+    Log_FormattedMessage("\t" #_X ": %s\n", _X)
+
+#define REPORT_INT(_X) \
+    Log_FormattedMessage("\t" #_X ": %d\n", _X)
+
+#define REPORT_HEX32(_X) \
+    Log_FormattedMessage("\t" #_X ": 0x%08X\n", _X)
+
+#define REPORT_EQ(_X, _Y) \
+    Log_FormattedMessage("\t" #_X " == " #_Y "\n")
+
+#define REPORT_EXPL(_X, _Y) \
+    Log_FormattedMessage("\t" #_X _Y "\n")
+
+    // Adapter PEC
+#ifdef ADAPTER_PEC_DBG
+    REPORT_SET(ADAPTER_PEC_DBG);
+#endif
+
+#ifdef ADAPTER_PEC_STRICT_ARGS
+    REPORT_SET(ADAPTER_PEC_STRICT_ARGS);
+#endif
+
+#ifdef ADAPTER_PEC_ENABLE_SCATTERGATHER
+    REPORT_SET(ADAPTER_PEC_ENABLE_SCATTERGATHER);
+#endif
+
+#ifdef ADAPTER_PEC_SEPARATE_RINGS
+    REPORT_SET(ADAPTER_PEC_SEPARATE_RINGS);
+#else
+    REPORT_EXPL(ADAPTER_PEC_SEPARATE_RINGS, " is NOT set => Overlapping");
+#endif
+
+#ifdef ADAPTER_PEC_ARMRING_ENABLE_SWAP
+    REPORT_SET(ADAPTER_PEC_ARMRING_ENABLE_SWAP);
+#endif
+
+    REPORT_INT(ADAPTER_PEC_DEVICE_COUNT);
+    REPORT_INT(ADAPTER_PEC_MAX_PACKETS);
+    REPORT_INT(ADAPTER_MAX_PECLOGICDESCR);
+    REPORT_INT(ADAPTER_PEC_MAX_SAS);
+    REPORT_INT(ADAPTER_DESCRIPTORDONETIMEOUT);
+    REPORT_INT(ADAPTER_DESCRIPTORDONECOUNT);
+
+#ifdef ADAPTER_REMOVE_BOUNCEBUFFERS
+    REPORT_EXPL(ADAPTER_REMOVE_BOUNCEBUFFERS, " is SET => Bounce DISABLED");
+#else
+    REPORT_EXPL(ADAPTER_REMOVE_BOUNCEBUFFERS, " is NOT set => Bounce ENABLED");
+#endif
+
+#ifdef ADAPTER_EIP202_INTERRUPTS_ENABLE
+    REPORT_EXPL(ADAPTER_EIP202_INTERRUPTS_ENABLE,
+            " is SET => Interrupts ENABLED");
+#else
+    REPORT_EXPL(ADAPTER_EIP202_INTERRUPTS_ENABLE,
+            " is NOT set => Interrupts DISABLED");
+#endif
+
+#ifdef ADAPTER_PCL_ENABLE
+    REPORT_SET(ADAPTER_PCL_ENABLE);
+    REPORT_INT(ADAPTER_PCL_FLOW_HASH_ENTRIES_COUNT);
+#endif
+
+#ifdef ADAPTER_64BIT_HOST
+    REPORT_EXPL(ADAPTER_64BIT_HOST,
+                " is SET => addresses are 64-bit");
+#else
+    REPORT_EXPL(ADAPTER_64BIT_HOST,
+                " is NOT set => addresses are 32-bit");
+#endif
+
+#ifdef ADAPTER_64BIT_DEVICE
+    REPORT_EXPL(ADAPTER_64BIT_DEVICE,
+                " is SET => full 64-bit DMA addresses usable");
+#else
+    REPORT_EXPL(ADAPTER_64BIT_DEVICE,
+                " is NOT set => DMA addresses must be below 4GB");
+#endif
+
+#ifdef ADAPTER_DMARESOURCE_BANKS_ENABLE
+    REPORT_SET(ADAPTER_DMARESOURCE_BANKS_ENABLE);
+#endif
+
+    // Adapter Global Classification Control
+#ifdef ADAPTER_CS_TIMER_PRESCALER
+    REPORT_INT(ADAPTER_CS_TIMER_PRESCALER);
+#endif
+
+#ifdef ADAPTER_GLOBAL_BOARDCTRL_SUPPORT_ENABLE
+    REPORT_SET(ADAPTER_GLOBAL_BOARDCTRL_SUPPORT_ENABLE);
+#endif
+
+    // Log
+    Log_FormattedMessage("Logging:\n");
+
+#if (LOG_SEVERITY_MAX == LOG_SEVERITY_INFO)
+    REPORT_EQ(LOG_SEVERITY_MAX, LOG_SEVERITY_INFO);
+#elif (LOG_SEVERITY_MAX == LOG_SEVERITY_WARNING)
+    REPORT_EQ(LOG_SEVERITY_MAX, LOG_SEVERITY_W_A_R_N_I_N_G);
+#elif (LOG_SEVERITY_MAX == LOG_SEVERITY_CRITICAL)
+    REPORT_EQ(LOG_SEVERITY_MAX, LOG_SEVERITY_CRITICAL);
+#else
+    REPORT_EXPL(LOG_SEVERITY_MAX, " - Unknown (not info/warn/crit)");
+#endif
+
+    // Adapter other
+    Log_FormattedMessage("Other:\n");
+    REPORT_STR(ADAPTER_DRIVER_NAME);
+    REPORT_STR(ADAPTER_LICENSE);
+    REPORT_HEX32(ADAPTER_INTERRUPTS_TRACEFILTER);
+    REPORT_STR(RPM_DEVICE_CAPABILITIES_STR_MACRO);
+}
+
+
+/* end of file adapter_init.c */
diff --git a/package-21.02/kernel/crypto-eip/src/ddk/slad/adapter_init_pec.c b/package-21.02/kernel/crypto-eip/src/ddk/slad/adapter_init_pec.c
new file mode 100644
index 0000000..4bcb88e
--- /dev/null
+++ b/package-21.02/kernel/crypto-eip/src/ddk/slad/adapter_init_pec.c
@@ -0,0 +1,265 @@
+/* adapter_init_pec.c
+ *
+ * Adapter module responsible for Adapter PEC initialization tasks.
+ *
+ */
+
+/*****************************************************************************
+* Copyright (c) 2012-2022 by Rambus, Inc. and/or its subsidiaries.
+*
+* This program is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 2 of the License, or
+* any later version.
+*
+* This program is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with this program. If not, see <http://www.gnu.org/licenses/>.
+*****************************************************************************/
+
+/*----------------------------------------------------------------------------
+ * This module implements (provides) the following interface(s):
+ */
+
+#include "adapter_init.h"
+
+
+/*----------------------------------------------------------------------------
+ * This module uses (requires) the following interface(s):
+ */
+
+// Top-level Adapter configuration
+#include "cs_adapter.h"
+
+#ifdef ADAPTER_PEC_INTERRUPTS_ENABLE
+#include "adapter_interrupts.h" // Adapter_Interrupts_Init,
+                                // Adapter_Interrupts_UnInit
+#endif
+
+// Logging API
+#include "log.h"            // LOG_*
+
+// Driver Framework Device API
+#include "device_mgmt.h"    // Device_Initialize, Device_UnInitialize
+#include "device_rw.h"      // Device_Read32, Device_Write32
+
+// Driver Framework DMAResource API
+#include "dmares_mgmt.h"    // DMAResource_Init, DMAResource_UnInit
+
+// Driver Framework C Library API
+#include "clib.h"           // memcpy, ZEROINIT
+
+// Driver Framework Basic Definitions API
+#include "basic_defs.h"     // bool, true, false
+
+
+/*----------------------------------------------------------------------------
+ * Local variables
+ */
+
+static bool Adapter_IsInitialized = false;
+static int Device_IRQ;
+
+
+/*----------------------------------------------------------------------------
+ * Forward declarations
+ */
+
+
+/*----------------------------------------------------------------------------
+ * Adapter_Init
+ *
+ * Return Value
+ *     true   Success
+ *     false  Failure (fatal!)
+ */
+bool
+Adapter_Init(void)
+{
+    Device_IRQ = -1;
+
+    if (Adapter_IsInitialized != false)
+    {
+        LOG_WARN("Adapter_Init: Already initialized\n");
+        return true;
+    }
+
+    // trigger first-time initialization of the adapter
+    if (Device_Initialize(&Device_IRQ) < 0)
+        return false;
+
+    if (!DMAResource_Init())
+    {
+        Device_UnInitialize();
+        return false;
+    }
+
+#ifdef ADAPTER_PEC_INTERRUPTS_ENABLE
+    if (Adapter_Interrupts_Init(Device_IRQ) < 0)
+    {
+        LOG_CRIT("Adapter_Init: Adapter_Interrupts_Init failed\n");
+        DMAResource_UnInit();
+        Device_UnInitialize();
+        return false;
+    }
+#endif
+
+    Adapter_IsInitialized = true;
+
+    return true;    // success
+}
+
+
+/*----------------------------------------------------------------------------
+ * Adapter_UnInit
+ */
+void
+Adapter_UnInit(void)
+{
+    if (!Adapter_IsInitialized)
+    {
+        LOG_WARN("Adapter_UnInit: Adapter is not initialized\n");
+        return;
+    }
+
+    Adapter_IsInitialized = false;
+
+    DMAResource_UnInit();
+
+#ifdef ADAPTER_PEC_INTERRUPTS_ENABLE
+    Adapter_Interrupts_UnInit(Device_IRQ);
+#endif
+
+    Device_UnInitialize();
+}
+
+
+/*----------------------------------------------------------------------------
+ * Adapter_Report_Build_Params
+ */
+void
+Adapter_Report_Build_Params(void)
+{
+    // This function is dependent on config file cs_adapter.h.
+    // Please update this when Config file for Adapter is changed.
+    Log_FormattedMessage("Adapter build configuration of %s:\n",
+        ADAPTER_VERSION_STRING);
+
+#define REPORT_SET(_X) \
+    Log_FormattedMessage("\t" #_X "\n")
+
+#define REPORT_STR(_X) \
+    Log_FormattedMessage("\t" #_X ": %s\n", _X)
+
+#define REPORT_INT(_X) \
+    Log_FormattedMessage("\t" #_X ": %d\n", _X)
+
+#define REPORT_HEX32(_X) \
+    Log_FormattedMessage("\t" #_X ": 0x%08X\n", _X)
+
+#define REPORT_EQ(_X, _Y) \
+    Log_FormattedMessage("\t" #_X " == " #_Y "\n")
+
+#define REPORT_EXPL(_X, _Y) \
+    Log_FormattedMessage("\t" #_X _Y "\n")
+
+    // Adapter PEC
+#ifdef ADAPTER_PEC_DBG
+    REPORT_SET(ADAPTER_PEC_DBG);
+#endif
+
+#ifdef ADAPTER_PEC_STRICT_ARGS
+    REPORT_SET(ADAPTER_PEC_STRICT_ARGS);
+#endif
+
+#ifdef ADAPTER_PEC_ENABLE_SCATTERGATHER
+    REPORT_SET(ADAPTER_PEC_ENABLE_SCATTERGATHER);
+#endif
+
+#ifdef ADAPTER_PEC_SEPARATE_RINGS
+    REPORT_SET(ADAPTER_PEC_SEPARATE_RINGS);
+#else
+    REPORT_EXPL(ADAPTER_PEC_SEPARATE_RINGS, " is NOT set => Overlapping");
+#endif
+
+#ifdef ADAPTER_PEC_ARMRING_ENABLE_SWAP
+    REPORT_SET(ADAPTER_PEC_ARMRING_ENABLE_SWAP);
+#endif
+
+    REPORT_INT(ADAPTER_PEC_DEVICE_COUNT);
+    REPORT_INT(ADAPTER_PEC_MAX_PACKETS);
+    REPORT_INT(ADAPTER_MAX_PECLOGICDESCR);
+    REPORT_INT(ADAPTER_PEC_MAX_SAS);
+    REPORT_INT(ADAPTER_DESCRIPTORDONETIMEOUT);
+    REPORT_INT(ADAPTER_DESCRIPTORDONECOUNT);
+
+#ifdef ADAPTER_REMOVE_BOUNCEBUFFERS
+    REPORT_EXPL(ADAPTER_REMOVE_BOUNCEBUFFERS, " is SET => Bounce DISABLED");
+#else
+    REPORT_EXPL(ADAPTER_REMOVE_BOUNCEBUFFERS, " is NOT set => Bounce ENABLED");
+#endif
+
+#ifdef ADAPTER_EIP202_INTERRUPTS_ENABLE
+    REPORT_EXPL(ADAPTER_EIP202_INTERRUPTS_ENABLE,
+            " is SET => Interrupts ENABLED");
+#else
+    REPORT_EXPL(ADAPTER_EIP202_INTERRUPTS_ENABLE,
+            " is NOT set => Interrupts DISABLED");
+#endif
+
+#ifdef ADAPTER_PCL_ENABLE
+    REPORT_SET(ADAPTER_PCL_ENABLE);
+    REPORT_INT(ADAPTER_PCL_FLOW_HASH_ENTRIES_COUNT);
+#endif
+
+#ifdef ADAPTER_64BIT_HOST
+    REPORT_EXPL(ADAPTER_64BIT_HOST,
+                " is SET => addresses are 64-bit");
+#else
+    REPORT_EXPL(ADAPTER_64BIT_HOST,
+                " is NOT set => addresses are 32-bit");
+#endif
+
+#ifdef ADAPTER_64BIT_DEVICE
+    REPORT_EXPL(ADAPTER_64BIT_DEVICE,
+                " is SET => full 64-bit DMA addresses usable");
+#else
+    REPORT_EXPL(ADAPTER_64BIT_DEVICE,
+                " is NOT set => DMA addresses must be below 4GB");
+#endif
+
+#ifdef ADAPTER_DMARESOURCE_BANKS_ENABLE
+    REPORT_SET(ADAPTER_DMARESOURCE_BANKS_ENABLE);
+#endif
+
+    // Adapter Global Classification Control
+#ifdef ADAPTER_CS_TIMER_PRESCALER
+    REPORT_INT(ADAPTER_CS_TIMER_PRESCALER);
+#endif
+
+    // Log
+    Log_FormattedMessage("Logging:\n");
+
+#if (LOG_SEVERITY_MAX == LOG_SEVERITY_INFO)
+    REPORT_EQ(LOG_SEVERITY_MAX, LOG_SEVERITY_INFO);
+#elif (LOG_SEVERITY_MAX == LOG_SEVERITY_WARNING)
+    REPORT_EQ(LOG_SEVERITY_MAX, LOG_SEVERITY_W_A_R_N_I_N_G);
+#elif (LOG_SEVERITY_MAX == LOG_SEVERITY_CRITICAL)
+    REPORT_EQ(LOG_SEVERITY_MAX, LOG_SEVERITY_CRITICAL);
+#else
+    REPORT_EXPL(LOG_SEVERITY_MAX, " - Unknown (not info/warn/crit)");
+#endif
+
+    // Adapter other
+    Log_FormattedMessage("Other:\n");
+    REPORT_STR(ADAPTER_DRIVER_NAME);
+    REPORT_STR(ADAPTER_LICENSE);
+    REPORT_HEX32(ADAPTER_INTERRUPTS_TRACEFILTER);
+}
+
+
+/* end of file adapter_init_pec.c */
diff --git a/package-21.02/kernel/crypto-eip/src/ddk/slad/adapter_int_shdevxs.c b/package-21.02/kernel/crypto-eip/src/ddk/slad/adapter_int_shdevxs.c
new file mode 100644
index 0000000..d68072b
--- /dev/null
+++ b/package-21.02/kernel/crypto-eip/src/ddk/slad/adapter_int_shdevxs.c
@@ -0,0 +1,129 @@
+/* adapter_int_shdevxs.c
+ *
+ * Adapter Shared Device Access module responsible for interrupts.
+ * Implementation depends on the Kernel Support Driver.
+ *
+ */
+
+/*****************************************************************************
+* Copyright (c) 2012-2022 by Rambus, Inc. and/or its subsidiaries.
+*
+* This program is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 2 of the License, or
+* any later version.
+*
+* This program is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with this program. If not, see <http://www.gnu.org/licenses/>.
+*****************************************************************************/
+
+
+/*----------------------------------------------------------------------------
+ * This module implements (provides) the following interface(s):
+ */
+
+#include "adapter_interrupts.h"
+
+
+/*----------------------------------------------------------------------------
+ * This module uses (requires) the following interface(s):
+ */
+
+// Driver Framework Basic Definitions API
+#include "basic_defs.h"            // bool, IDENTIFIER_NOT_USED
+
+// Kernel support driver
+#include "shdevxs_irq.h"
+
+
+/*----------------------------------------------------------------------------
+ * Definitions and macros
+ */
+
+
+/*----------------------------------------------------------------------------
+ * Local variables
+ */
+
+
+/*----------------------------------------------------------------------------
+ * Adapter_Interrupt_Enable
+ */
+int
+Adapter_Interrupt_Enable(
+        const int nIRQ,
+        const unsigned int Flags)
+{
+    return SHDevXS_IRQ_Enable(nIRQ, Flags);
+}
+
+
+/*----------------------------------------------------------------------------
+ * Adapter_Interrupt_Disable
+ *
+ */
+int
+Adapter_Interrupt_Disable(
+        const int nIRQ,
+        const unsigned int Flags)
+{
+    return SHDevXS_IRQ_Disable(nIRQ, Flags);
+}
+
+
+/*----------------------------------------------------------------------------
+ * Adapter_Interrupt_SetHandler
+ */
+int
+Adapter_Interrupt_SetHandler(
+        const int nIRQ,
+        Adapter_InterruptHandler_t HandlerFunction)
+{
+    return SHDevXS_IRQ_SetHandler(nIRQ, HandlerFunction);
+}
+
+
+/*----------------------------------------------------------------------------
+ * Adapter_Interrupts_Init
+ */
+int
+Adapter_Interrupts_Init(
+        const int nIRQ)
+{
+    int res = SHDevXS_IRQ_Init();
+
+    IDENTIFIER_NOT_USED(nIRQ);
+
+    return res;
+}
+
+
+/*----------------------------------------------------------------------------
+ * Adapter_Interrupts_UnInit
+ */
+int
+Adapter_Interrupts_UnInit(
+        const int nIRQ)
+{
+    IDENTIFIER_NOT_USED(nIRQ);
+    return SHDevXS_IRQ_UnInit();
+}
+
+
+/*----------------------------------------------------------------------------
+ * Adapter_Interrupts_Resume
+ */
+int
+Adapter_Interrupts_Resume(void)
+{
+    // Resume AIC devices is done in SHDevXS IRQ module
+    return 0; // success
+}
+
+
+/* end of file adapter_int_shdevxs.c */
diff --git a/package-21.02/kernel/crypto-eip/src/ddk/slad/adapter_lock_internal.c b/package-21.02/kernel/crypto-eip/src/ddk/slad/adapter_lock_internal.c
new file mode 100644
index 0000000..4b216af
--- /dev/null
+++ b/package-21.02/kernel/crypto-eip/src/ddk/slad/adapter_lock_internal.c
@@ -0,0 +1,142 @@
+/* adapter_lock_internal.c
+ *
+ * Adapter concurrency (locking) management
+ * Generic implementation
+ *
+ */
+
+/*****************************************************************************
+* Copyright (c) 2013-2020 by Rambus, Inc. and/or its subsidiaries.
+*
+* This program is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 2 of the License, or
+* any later version.
+*
+* This program is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with this program. If not, see <http://www.gnu.org/licenses/>.
+*****************************************************************************/
+
+/*----------------------------------------------------------------------------
+ * This module implements (provides) the following interface(s):
+ */
+
+// Adapter locking API
+#include "adapter_lock.h"
+
+
+/*----------------------------------------------------------------------------
+ * This module uses (requires) the following interface(s):
+ */
+
+// Driver Framework Basic Definitions API
+#include "basic_defs.h"         // bool
+
+// Adapter Lock Internal API
+#include "adapter_lock_internal.h"
+
+#define TEST_SIZEOF(type, size) \
+    extern int must_bigger[1 - 2*((int)(sizeof(type) > size))]
+
+// Check the size of the data structures
+TEST_SIZEOF(Adapter_Lock_CS_Internal_t, sizeof(Adapter_Lock_CS_t));
+
+
+/*----------------------------------------------------------------------------
+ * Adapter_Lock_NULL
+ *
+ */
+const Adapter_Lock_t Adapter_Lock_NULL = NULL;
+
+
+/*----------------------------------------------------------------------------
+ * Adapter_Lock_CS_Set
+ */
+void
+Adapter_Lock_CS_Set(
+        Adapter_Lock_CS_t * const CS_p,
+        Adapter_Lock_t Lock)
+{
+    Adapter_Lock_CS_Internal_t * CS_Internal_p =
+                                 (Adapter_Lock_CS_Internal_t*)CS_p;
+
+    if (CS_Internal_p)
+    {
+        // Lock cannot be set while the critical section is entered
+        if (CS_Internal_p->fLocked == false)
+            CS_Internal_p->Lock_p = Lock;
+    }
+}
+
+
+/*----------------------------------------------------------------------------
+ * Adapter_Lock_CS_Get
+ */
+Adapter_Lock_t
+Adapter_Lock_CS_Get(
+        Adapter_Lock_CS_t * const CS_p)
+{
+    Adapter_Lock_CS_Internal_t * CS_Internal_p =
+                                 (Adapter_Lock_CS_Internal_t*)CS_p;
+
+    if (CS_Internal_p)
+        return CS_Internal_p->Lock_p;
+    else
+        return Adapter_Lock_NULL;
+}
+
+
+/*----------------------------------------------------------------------------
+ * Adapter_Lock_CS_Enter
+ */
+bool
+Adapter_Lock_CS_Enter(
+        Adapter_Lock_CS_t * const CS_p)
+{
+    unsigned long Flags;
+    Adapter_Lock_CS_Internal_t * CS_Internal_p =
+                                (Adapter_Lock_CS_Internal_t*)CS_p;
+
+    if (CS_Internal_p == NULL)
+        return false;
+
+    // Enter critical section
+    Adapter_Lock_Acquire(CS_Internal_p->Lock_p, &Flags);
+
+    // Check if critical section is already entered
+    if (CS_Internal_p->fLocked)
+    {
+        Adapter_Lock_Release(CS_Internal_p->Lock_p, &Flags);
+        return false; // CS already entered
+    }
+    else
+        CS_Internal_p->fLocked = true; // success
+
+    // Leave critical section
+    Adapter_Lock_Release(CS_Internal_p->Lock_p, &Flags);
+
+    return true;
+}
+
+
+/*----------------------------------------------------------------------------
+ * Adapter_Lock_CS_Leave
+ */
+void
+Adapter_Lock_CS_Leave(
+        Adapter_Lock_CS_t * const CS_p)
+{
+    Adapter_Lock_CS_Internal_t * CS_Internal_p =
+                                (Adapter_Lock_CS_Internal_t*)CS_p;
+
+    if (CS_Internal_p)
+        CS_Internal_p->fLocked = false;
+}
+
+
+/* end of file adapter_lock_internal.c */
diff --git a/package-21.02/kernel/crypto-eip/src/ddk/slad/adapter_memxs.c b/package-21.02/kernel/crypto-eip/src/ddk/slad/adapter_memxs.c
new file mode 100644
index 0000000..0ec6593
--- /dev/null
+++ b/package-21.02/kernel/crypto-eip/src/ddk/slad/adapter_memxs.c
@@ -0,0 +1,242 @@
+/* adapter_memxs.c
+ *
+ * Low-level Memory Access API implementation.
+ */
+
+/*****************************************************************************
+* Copyright (c) 2012-2020 by Rambus, Inc. and/or its subsidiaries.
+*
+* This program is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 2 of the License, or
+* any later version.
+*
+* This program is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with this program. If not, see <http://www.gnu.org/licenses/>.
+*****************************************************************************/
+
+/*----------------------------------------------------------------------------
+ * This module implements (provides) the following interface(s):
+ */
+
+// MemXS API
+#include "api_memxs.h"
+
+
+/*----------------------------------------------------------------------------
+ * This module uses (requires) the following interface(s):
+ */
+
+// Default configuration
+#include "c_adapter_memxs.h"
+
+// Driver Framework Basic Definitions API
+#include "basic_defs.h"
+
+// Driver Framework Device API
+#include "device_types.h"       // Device_Handle_t
+#include "device_rw.h"         // Device_Read/Write
+#include "device_mgmt.h"
+
+// Driver Framework C Run-Time Library API
+#include "clib.h"               // memcmp
+
+
+/*----------------------------------------------------------------------------
+ * Definitions and macros
+ */
+
+/*----------------------------------------------------------------------------
+ * MemXS_DeviceAdmin_t
+ *
+ * MemXS device record
+ */
+typedef struct
+{
+    const char *        DevName;
+
+    unsigned int        FirstOfs;
+
+    unsigned int        LastOfs;
+
+    Device_Handle_t     MemXS_Device;
+
+} MemXS_DeviceAdmin_t;
+
+
+/*----------------------------------------------------------------------------
+ * Local variables
+ */
+
+// Here is the dependency on the Driver Framework configuration
+// via the MemXS configuration
+#ifndef HWPAL_DEVICES
+#error "Expected HWPAL_DEVICES defined by cs_memxs.h"
+#endif
+
+// Here is the dependency on the Driver Framework configuration
+// via the MemXS configuration
+#undef HWPAL_DEVICE_ADD
+#define HWPAL_DEVICE_ADD(_name, _devnr, _firstofs, _lastofs, _flags) \
+           { _name, _firstofs, _lastofs, NULL }
+
+static MemXS_DeviceAdmin_t MemXS_Devices[] =
+{
+    HWPAL_DEVICES
+};
+
+static const unsigned int MemXS_Device_Count =
+        (sizeof(MemXS_Devices) / sizeof(MemXS_DeviceAdmin_t));
+
+
+/*----------------------------------------------------------------------------
+ * MemXS_NULLHandle
+ *
+ */
+const MemXS_Handle_t MemXS_NULLHandle = { 0 };
+
+
+/*----------------------------------------------------------------------------
+ * MemXS_Init
+ */
+bool
+MemXS_Init (void)
+{
+    unsigned int i;
+
+    for(i = 0; i < MemXS_Device_Count; i++)
+    {
+        MemXS_Devices[i].MemXS_Device = NULL;
+
+        MemXS_Devices[i].MemXS_Device =
+                Device_Find (MemXS_Devices[i].DevName);
+
+        if (MemXS_Devices[i].MemXS_Device == NULL)
+        {
+            return false;
+        }
+    } // for
+
+    return true;
+}
+
+
+/*-----------------------------------------------------------------------------
+ * MemXS_Handle_IsSame
+ */
+bool
+MemXS_Handle_IsSame(
+        const MemXS_Handle_t * const Handle1_p,
+        const MemXS_Handle_t * const Handle2_p)
+{
+    return Handle1_p->p == Handle2_p->p;
+}
+
+
+/*-----------------------------------------------------------------------------
+ * MemXS_Device_Count_Get
+ */
+MemXS_Status_t
+MemXS_Device_Count_Get(
+        unsigned int * const DeviceCount_p)
+{
+    if (DeviceCount_p == NULL)
+        return MEMXS_INVALID_PARAMETER;
+
+    *DeviceCount_p = MemXS_Device_Count;
+
+    return MEMXS_STATUS_OK;
+}
+
+
+/*-----------------------------------------------------------------------------
+ * MemXS_Device_Info_Get
+ */
+MemXS_Status_t
+MemXS_Device_Info_Get(
+        const unsigned int DeviceIndex,
+        MemXS_DevInfo_t * const DeviceInfo_p)
+{
+    if (DeviceInfo_p == NULL)
+        return MEMXS_INVALID_PARAMETER;
+
+    if (DeviceIndex > MemXS_Device_Count)
+        return MEMXS_INVALID_PARAMETER;
+
+    DeviceInfo_p->Index    = DeviceIndex;
+    DeviceInfo_p->Handle.p = MemXS_Devices[DeviceIndex].MemXS_Device;
+    DeviceInfo_p->Name_p   = MemXS_Devices[DeviceIndex].DevName;
+    DeviceInfo_p->FirstOfs = MemXS_Devices[DeviceIndex].FirstOfs;
+    DeviceInfo_p->LastOfs  = MemXS_Devices[DeviceIndex].LastOfs;
+
+    return MEMXS_STATUS_OK;
+}
+
+
+/*----------------------------------------------------------------------------
+ * MemXS_Read32
+ */
+uint32_t
+MemXS_Read32(
+        const MemXS_Handle_t Handle,
+        const unsigned int ByteOffset)
+{
+    Device_Handle_t Device = (Device_Handle_t)Handle.p;
+
+    return Device_Read32(Device, ByteOffset);
+}
+
+
+/*----------------------------------------------------------------------------
+ * MemXS_Write32
+ */
+void
+MemXS_Write32(
+        const MemXS_Handle_t Handle,
+        const unsigned int ByteOffset,
+        const uint32_t Value)
+{
+    Device_Handle_t Device = (Device_Handle_t)Handle.p;
+
+    Device_Write32(Device, ByteOffset, Value);
+}
+
+
+/*----------------------------------------------------------------------------
+ * MemXS_Read32Array
+ */
+void
+MemXS_Read32Array(
+        const MemXS_Handle_t Handle,
+        const unsigned int ByteOffset,
+        uint32_t * MemoryDst_p,
+        const int Count)
+{
+    Device_Handle_t Device = (Device_Handle_t)Handle.p;
+
+    Device_Read32Array(Device, ByteOffset, MemoryDst_p, Count);
+}
+
+
+/*----------------------------------------------------------------------------
+ * MemXS_Write32Array
+ */
+void
+MemXS_Write32Array(
+        const MemXS_Handle_t Handle,
+        const unsigned int ByteOffset,
+        const uint32_t * MemorySrc_p,
+        const int Count)
+{
+    Device_Handle_t Device = (Device_Handle_t)Handle.p;
+
+    Device_Write32Array(Device, ByteOffset, MemorySrc_p, Count);
+}
+
+
+/* end of file adapter_memxs.c */
diff --git a/package-21.02/kernel/crypto-eip/src/ddk/slad/adapter_pcl_dtl.c b/package-21.02/kernel/crypto-eip/src/ddk/slad/adapter_pcl_dtl.c
new file mode 100644
index 0000000..249950a
--- /dev/null
+++ b/package-21.02/kernel/crypto-eip/src/ddk/slad/adapter_pcl_dtl.c
@@ -0,0 +1,1051 @@
+/* adapter_pcl_dtl.c
+ *
+ * Packet Classification (PCL) DTL API implementation.
+ */
+
+/*****************************************************************************
+* Copyright (c) 2012-2020 by Rambus, Inc. and/or its subsidiaries.
+*
+* This program is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 2 of the License, or
+* any later version.
+*
+* This program is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with this program. If not, see <http://www.gnu.org/licenses/>.
+******************************************************************************/
+
+/*----------------------------------------------------------------------------
+ * This module implements (provides) the following interface(s):
+ */
+
+// PCL API
+#include "api_pcl.h"                // PCL_*
+
+// PCL DTL API
+#include "api_pcl_dtl.h"            // PCL_DTL_*
+
+
+/*----------------------------------------------------------------------------
+ * This module uses (requires) the following interface(s):
+ */
+
+// Default Adapter configuration
+#include "c_adapter_pcl.h"
+
+// DMABuf API
+#include "api_dmabuf.h"         // DMABuf_*
+
+// Adapter DMABuf internal API
+#include "adapter_dmabuf.h"
+
+// Convert address to pair of 32-bit words.
+#include "adapter_addrpair.h"
+
+// Buffer allocation (non-DMA) API
+#include "adapter_alloc.h"
+
+// Adapter PCL Internal API
+#include "adapter_pcl.h"
+
+// Adapter Locking internal API
+#include "adapter_lock.h"       // Adapter_Lock_*
+
+// EIP-207 Driver Library Flow Control Generic API
+#include "eip207_flow_generic.h"
+
+// EIP-207 Driver Library Flow Control DTL API
+#include "eip207_flow_dtl.h"
+
+// Driver Framework Device API
+#include "device_types.h"       // Device_Handle_t
+#include "device_mgmt.h"        // Device_find
+
+// Driver Framework DMAResource API
+#include "dmares_types.h"       // DMAResource_Handle_t
+#include "dmares_mgmt.h"        // DMAResource management functions
+#include "dmares_rw.h"          // DMAResource buffer access.
+#include "dmares_addr.h"        // DMAResource addr translation functions.
+#include "dmares_buf.h"         // DMAResource buffer allocations
+
+// List API
+#include "list.h"               // List_*
+
+// Runtime Power Management Device Macros API
+#include "rpm_device_macros.h"  // RPM_*
+
+// Logging API
+#include "log.h"
+
+// Driver Framework C Run-Time Library API
+#include "clib.h"               // memcpy, memset
+
+// Driver Framework Basic Definitions API
+#include "basic_defs.h"         // bool, uint32_t
+
+
+/*----------------------------------------------------------------------------
+ * Definitions and macros
+ */
+
+// this implementation requires DMA resource banks
+#ifndef ADAPTER_PCL_DMARESOURCE_BANKS_ENABLE
+#error "Adapter DTL: ADAPTER_PCL_DMARESOURCE_BANKS_ENABLE not defined"
+#endif
+
+// Bit to indicate whether transformr record is large.
+#define ADAPTER_PCL_TR_ISLARGE              BIT_4
+
+
+/*----------------------------------------------------------------------------
+ * Global constants
+ */
+
+
+/*----------------------------------------------------------------------------
+ * PCL_DTL_NULLHandle
+ *
+ */
+const PCL_DTL_Hash_Handle_t PCL_DTL_NULLHandle = { NULL };
+
+
+/*----------------------------------------------------------------------------
+ * Local variables
+ */
+
+
+/*----------------------------------------------------------------------------
+ * Local prototypes
+ */
+
+
+/*-----------------------------------------------------------------------------
+ * PCL API functions implementation
+ *
+ */
+
+/*-----------------------------------------------------------------------------
+ * PCL_Flow_Remove
+ */
+PCL_Status_t
+PCL_Flow_Remove(
+        const unsigned int InterfaceId,
+        const unsigned int FlowHashTableId,
+        const PCL_FlowHandle_t FlowHandle)
+{
+    PCL_Status_t PCL_Rc = PCL_STATUS_OK;
+    EIP207_Flow_Error_t EIP207_Rc;
+    EIP207_Flow_IOArea_t * ioarea_p;
+    List_Element_t * Element_p = (List_Element_t*)FlowHandle;
+    EIP207_Flow_FR_Dscr_t * FlowDescriptor_p;
+    AdapterPCL_Device_Instance_Data_t * Dev_p;
+
+    LOG_INFO("\n\t PCL_Flow_Remove \n");
+
+    // validate input parameters
+    if (InterfaceId >= ADAPTER_PCL_MAX_FLUE_DEVICES ||
+        FlowHashTableId >= ADAPTER_CS_MAX_NOF_FLOW_HASH_TABLES_TO_USE ||
+        Element_p == NULL)
+    {
+        return PCL_INVALID_PARAMETER;
+    }
+
+    FlowDescriptor_p = (EIP207_Flow_FR_Dscr_t *)Element_p->DataObject_p;
+
+    if (FlowDescriptor_p == NULL)
+    {
+        LOG_CRIT("PCL_Flow_Remove: failed, invalid flow handle\n");
+        return PCL_INVALID_PARAMETER;
+    }
+
+    // get interface ioarea
+    Dev_p = AdapterPCL_Device_Get(InterfaceId);
+    ioarea_p = Dev_p->EIP207_IOArea_p;
+
+    if (Adapter_Lock_CS_Get(&Dev_p->AdapterPCL_DevCS) == Adapter_Lock_NULL)
+    {
+        LOG_CRIT("PCL_Flow_Add: no device lock, not initialized?\n");
+        return PCL_ERROR;
+    }
+
+    if (!Adapter_Lock_CS_Enter(&Dev_p->AdapterPCL_DevCS))
+        return PCL_STATUS_BUSY;
+
+    if (RPM_DEVICE_IO_START_MACRO(ADAPTER_PCL_RPM_EIP207_DEVICE_ID,
+                                  RPM_FLAG_SYNC) != RPM_SUCCESS)
+    {
+        Adapter_Lock_CS_Leave(&Dev_p->AdapterPCL_DevCS);
+        return PCL_ERROR;
+    }
+
+    LOG_INFO("\n\t\t EIP207_Flow_DTL_FR_Remove \n");
+
+    EIP207_Rc = EIP207_Flow_DTL_FR_Remove(ioarea_p,
+                                          FlowHashTableId,
+                                          FlowDescriptor_p);
+    if (EIP207_Rc != EIP207_FLOW_NO_ERROR)
+    {
+        LOG_CRIT("PCL_Flow_Remove: failed to remove FR, err=%d\n", EIP207_Rc);
+        PCL_Rc = PCL_ERROR;
+    }
+
+    (void)RPM_DEVICE_IO_STOP_MACRO(ADAPTER_PCL_RPM_EIP207_DEVICE_ID,
+                                   RPM_FLAG_ASYNC);
+
+    Adapter_Lock_CS_Leave(&Dev_p->AdapterPCL_DevCS);
+
+    return PCL_Rc;
+}
+
+
+/*-----------------------------------------------------------------------------
+ * PCL_Transform_Register
+ */
+PCL_Status_t
+PCL_Transform_Register(
+        const DMABuf_Handle_t TransformHandle)
+{
+    unsigned int TR_WordCount;
+    DMAResource_Handle_t DMAHandle =
+                Adapter_DMABuf_Handle2DMAResourceHandle(TransformHandle);
+    DMAResource_Record_t * const Rec_p =
+                                DMAResource_Handle2RecordPtr(DMAHandle);
+
+    LOG_INFO("\n\t PCL_Transform_Register \n");
+
+    // validate parameter
+    if (Rec_p == NULL)
+        return PCL_INVALID_PARAMETER;
+
+    {
+#ifndef ADAPTER_PCL_USE_LARGE_TRANSFORM_DISABLE
+        uint32_t *TR_p = (uint32_t*)Adapter_DMAResource_HostAddr(DMAHandle);
+
+        Rec_p->fIsLargeTransform = false;
+
+        // Check whether the transform record is large.
+        // Register that in the DMA resource record.
+        if ((*TR_p & ADAPTER_PCL_TR_ISLARGE) != 0)
+        {
+            Rec_p->fIsLargeTransform = true;
+
+            TR_WordCount = EIP207_Flow_DTL_TR_Large_WordCount_Get();
+            *TR_p = *TR_p & ~ADAPTER_PCL_TR_ISLARGE;
+            // Clear that bit in the transform record.
+        }
+        else
+#endif // !ADAPTER_PCL_USE_LARGE_TRANSFORM_DISABLE
+        {
+            TR_WordCount = EIP207_Flow_TR_WordCount_Get();
+        }
+    }
+
+#ifdef ADAPTER_PEC_ARMRING_ENABLE_SWAP
+    DMAResource_SwapEndianness_Set(DMAHandle, true);
+#endif
+
+#ifdef ADAPTER_PCL_DMARESOURCE_BANKS_ENABLE
+    if (Rec_p->Props.Bank != ADAPTER_PCL_BANK_TRANSFORM)
+    {
+        LOG_CRIT("PCL Adapter: Invalid bank for Transform\n");
+        return PCL_ERROR;
+    }
+#endif
+
+    if (Rec_p->Props.Size < (sizeof(uint32_t) * TR_WordCount))
+    {
+        LOG_CRIT("PCL_Transform_Register: supplied buffer too small\n");
+        return PCL_ERROR;
+    }
+
+    DMAResource_Write32Array(
+            DMAHandle,
+            0,
+            TR_WordCount,
+            Adapter_DMAResource_HostAddr(DMAHandle));
+
+    DMAResource_PreDMA(DMAHandle, 0, sizeof(uint32_t) * TR_WordCount);
+
+    return PCL_STATUS_OK;
+}
+
+
+/*-----------------------------------------------------------------------------
+ * PCL_Transform_UnRegister
+ */
+PCL_Status_t
+PCL_Transform_UnRegister(
+        const DMABuf_Handle_t TransformHandle)
+{
+    IDENTIFIER_NOT_USED(TransformHandle.p);
+
+    LOG_INFO("\n\t PCL_Transform_UnRegister \n");
+
+    // Kept for backwards-compatibility, nothing to do here
+
+    return PCL_STATUS_OK;
+}
+
+/*-----------------------------------------------------------------------------
+ * PCL_Transform_Get_ReadOnly
+ */
+PCL_Status_t
+PCL_Transform_Get_ReadOnly(
+        const DMABuf_Handle_t TransformHandle,
+        PCL_TransformParams_t * const TransformParams_p)
+{
+    EIP207_Flow_TR_Dscr_t TransformDescriptor;
+    EIP207_Flow_TR_OutputData_t TransformData;
+    EIP207_Flow_Error_t res;
+    EIP207_Flow_IOArea_t * ioarea_p;
+    AdapterPCL_Device_Instance_Data_t * Dev_p;
+    DMAResource_Record_t * Rec_p = NULL;
+
+    LOG_INFO("\n\t PCL_Transform_Get_ReadOnly \n");
+
+    if( AdapterPCL_DMABuf_To_TRDscr(
+            TransformHandle, &TransformDescriptor, &Rec_p) != PCL_STATUS_OK)
+        return PCL_ERROR;
+
+    // get interface ioarea
+    Dev_p = AdapterPCL_Device_Get(0);
+    ioarea_p = Dev_p->EIP207_IOArea_p;
+    if (ioarea_p == NULL)
+    {
+        LOG_CRIT("PCL_Transform_Get_ReadOnly: failed, not initialized\n");
+        return PCL_ERROR;
+    }
+
+    {
+#ifndef ADAPTER_PCL_USE_LARGE_TRANSFORM_DISABLE
+        if (Rec_p->fIsLargeTransform)
+        {
+            res = EIP207_Flow_DTL_TR_Large_Read(
+                ioarea_p,
+                0,
+                &TransformDescriptor,
+                &TransformData);
+        }
+        else
+#else
+        IDENTIFIER_NOT_USED(Rec_p);
+#endif // !ADAPTER_PCL_USE_LARGE_TRANSFORM_DISABLE
+        {
+            res = EIP207_Flow_TR_Read(
+                ioarea_p,
+                0,
+                &TransformDescriptor,
+                &TransformData);
+        }
+        if (res != EIP207_FLOW_NO_ERROR)
+        {
+            LOG_CRIT("PCL_Transform_Get_ReadOnly: "
+                    "Failed to remove transform record\n");
+            return PCL_ERROR;
+        }
+    }
+
+    TransformParams_p->SequenceNumber   = TransformData.SequenceNumber;
+    TransformParams_p->PacketsCounterLo = TransformData.PacketsCounter;
+    TransformParams_p->PacketsCounterHi = 0;
+    TransformParams_p->OctetsCounterLo  = TransformData.OctetsCounterLo;
+    TransformParams_p->OctetsCounterHi  = TransformData.OctetsCounterHi;
+
+    return PCL_STATUS_OK;
+}
+
+
+/*-----------------------------------------------------------------------------
+ * PCL DTL API functions implementation
+ *
+ */
+
+
+/*-----------------------------------------------------------------------------
+ * PCL_DTL_Transform_Add
+ */
+PCL_Status_t
+PCL_DTL_Transform_Add(
+        const unsigned int InterfaceId,
+        const unsigned int FlowHashTableId,
+        const PCL_DTL_TransformParams_t * const TransformParams,
+        const DMABuf_Handle_t XformDMAHandle,
+        PCL_DTL_Hash_Handle_t * const HashHandle_p)
+{
+    PCL_Status_t PCL_Rc = PCL_ERROR;
+    PCL_Status_t PCL_Rc2;
+    EIP207_Flow_Error_t EIP207_Rc;
+    EIP207_Flow_IOArea_t * ioarea_p;
+    EIP207_Flow_TR_Dscr_t * TR_Dscr_p;
+    EIP207_Flow_TR_InputData_t TR_inputdata;
+    AdapterPCL_Device_Instance_Data_t * Dev_p;
+    void * HashList_p = NULL;
+    List_Status_t List_Rc;
+    DMAResource_Record_t * Rec_p = NULL;
+    List_Element_t * Element_p = NULL;
+
+    LOG_INFO("\n\t %s \n", __func__);
+
+    // Validate input parameters
+    if (InterfaceId >= ADAPTER_PCL_MAX_FLUE_DEVICES ||
+        FlowHashTableId >= ADAPTER_CS_MAX_NOF_FLOW_HASH_TABLES_TO_USE)
+        return PCL_INVALID_PARAMETER;
+
+    // Get interface ioarea
+    Dev_p = AdapterPCL_Device_Get(InterfaceId);
+    ioarea_p = Dev_p->EIP207_IOArea_p;
+
+    if (Dev_p->List_p == NULL)
+    {
+        LOG_CRIT("%s: failed, not initialized\n", __func__);
+        return PCL_ERROR;
+    }
+
+    if (Adapter_Lock_CS_Get(&Dev_p->AdapterPCL_DevCS) == Adapter_Lock_NULL)
+    {
+        LOG_CRIT("%s: failed, no device lock, not initialized?\n", __func__);
+        return PCL_ERROR;
+    }
+
+    if (!Adapter_Lock_CS_Enter(&Dev_p->AdapterPCL_DevCS))
+        return PCL_STATUS_BUSY;
+
+    // Try to add new hash value to Flow Hash Table
+    {
+        unsigned int ListID;
+
+        PCL_Rc2 = AdapterPCL_ListID_Get(InterfaceId, &ListID);
+        if (PCL_Rc2 != PCL_STATUS_OK)
+        {
+            LOG_CRIT("%s: failed to get free list\n", __func__);
+            goto error_exit;
+        }
+
+        List_Rc = List_RemoveFromTail(ListID, NULL, &Element_p);
+        if (List_Rc != LIST_STATUS_OK)
+        {
+            LOG_CRIT(
+                "%s: failed to get free element from list\n", __func__);
+            goto error_exit;
+        }
+
+        // Note: Element_p and TR_Dscr_p must be valid by implementation!
+        TR_Dscr_p = (EIP207_Flow_TR_Dscr_t*)Element_p->DataObject_p;
+
+        // Set list element with the transform record descriptor data
+        PCL_Rc2 = AdapterPCL_DMABuf_To_TRDscr(XformDMAHandle, TR_Dscr_p, &Rec_p);
+        if (PCL_Rc2 != PCL_STATUS_OK)
+        {
+            LOG_CRIT("%s: failed, invalid transform\n", __func__);
+            PCL_Rc = PCL_INVALID_PARAMETER;
+            goto error_exit;
+        }
+
+        // Convert transform parameters into EIP-207 transform parameters
+        ZEROINIT(TR_inputdata);
+        TR_inputdata.HashID.Word32[0] = TransformParams->HashID[0];
+        TR_inputdata.HashID.Word32[1] = TransformParams->HashID[1];
+        TR_inputdata.HashID.Word32[2] = TransformParams->HashID[2];
+        TR_inputdata.HashID.Word32[3] = TransformParams->HashID[3];
+
+#ifndef ADAPTER_PCL_USE_LARGE_TRANSFORM_DISABLE
+        TR_inputdata.fLarge = Rec_p->fIsLargeTransform;
+#else
+        TR_inputdata.fLarge = false;
+#endif
+
+        LOG_INFO("\n\t\t EIP207_Flow_DTL_TR_Add \n");
+
+        // Add new hash value for this transform record to Flow Hash Table
+        EIP207_Rc = EIP207_Flow_DTL_TR_Add(ioarea_p,
+                                           FlowHashTableId,
+                                           TR_Dscr_p,
+                                           &TR_inputdata);
+        if (EIP207_Rc == EIP207_FLOW_OUT_OF_MEMORY_ERROR)
+        {
+            LOG_CRIT("%s: failed to install transform, "
+                     "out of memory\n", __func__);
+            PCL_Rc = PCL_OUT_OF_MEMORY_ERROR;
+        }
+        else if (EIP207_Rc == EIP207_FLOW_NO_ERROR)
+        {
+            PCL_Rc = PCL_STATUS_OK;
+        }
+        else
+        {
+            LOG_CRIT("%s: failed to install transform, "
+                     "EIP207_Flow_DTL_TR_Add() error %d\n",
+                     __func__,
+                     EIP207_Rc);
+        }
+
+        if (PCL_Rc != PCL_STATUS_OK)
+        {
+            LOG_CRIT("%s: failed to add hash value for transform record\n",
+                     __func__);
+
+            // Return not added element to free list
+            List_Rc = List_AddToHead(ListID, NULL, Element_p);
+            if (List_Rc != LIST_STATUS_OK)
+            {
+                LOG_CRIT("%s: failed to update free list\n", __func__);
+            }
+
+            PCL_Rc = PCL_INVALID_PARAMETER;
+            goto error_exit;
+        }
+    } // Done adding new hash value to Flow Hash Table
+
+    if (Rec_p->Context_p)
+    {
+        // Get list element
+        List_Element_t * TmpElement_p = Rec_p->Context_p;
+
+        // Get hash list that contains all transform record descriptors
+        HashList_p = TmpElement_p->DataObject_p;
+    }
+
+    if(HashList_p == NULL)
+    {
+        // Create hash list for transform record
+
+        List_Element_t * TmpElement_p = NULL;
+
+        // Get a free list from pool of lists
+        List_Rc = List_RemoveFromTail(LIST_DUMMY_LIST_ID,
+                                      Dev_p->List_p,
+                                      &TmpElement_p);
+        if (List_Rc != LIST_STATUS_OK)
+        {
+            LOG_CRIT("%s: failed to get free element from pool list\n",
+                     __func__);
+            goto error_exit;
+        }
+
+        // Note: TmpElement_p must be valid by implementation!
+        HashList_p = TmpElement_p->DataObject_p;
+
+        // Initialize list instance
+        if (List_Init(LIST_DUMMY_LIST_ID, HashList_p) != LIST_STATUS_OK)
+        {
+            LOG_CRIT("%s: list initialization failed\n", __func__);
+            goto error_exit;
+        }
+
+        // Store list element in the transform record descriptor
+        Rec_p->Context_p = TmpElement_p;
+    } // Created hash list for transform record
+
+    // Add new hash value to list of hash values for this transform record
+    List_Rc = List_AddToHead(LIST_DUMMY_LIST_ID, HashList_p, Element_p);
+    if (List_Rc != LIST_STATUS_OK)
+    {
+        LOG_CRIT("%s: failed to update hash list for transform record\n",
+                 __func__);
+    }
+
+    HashHandle_p->p = Element_p;
+
+error_exit:
+
+    Adapter_Lock_CS_Leave(&Dev_p->AdapterPCL_DevCS);
+    return PCL_Rc;
+}
+
+
+/*-----------------------------------------------------------------------------
+ * PCL_DTL_Transform_Remove
+ */
+PCL_Status_t
+PCL_DTL_Transform_Remove(
+        const unsigned int InterfaceId,
+        const unsigned int FlowHashTableId,
+        const DMABuf_Handle_t XformDMAHandle)
+{
+    PCL_Status_t PCL_Rc = PCL_ERROR;
+    PCL_Status_t PCL_Rc2;
+    AdapterPCL_Device_Instance_Data_t * Dev_p;
+    EIP207_Flow_Error_t EIP207_Rc;
+    EIP207_Flow_IOArea_t * ioarea_p;
+    EIP207_Flow_TR_Dscr_t * TR_Dscr_p;
+    List_Status_t List_Rc;
+    List_Element_t * Element_p;
+    List_Element_t * ListElement_p;
+    unsigned int ListID;
+    void * HashList_p;
+
+    DMAResource_Handle_t DMAHandle =
+        Adapter_DMABuf_Handle2DMAResourceHandle(XformDMAHandle);
+
+    DMAResource_Record_t * Rec_p = DMAResource_Handle2RecordPtr(DMAHandle);
+
+    LOG_INFO("\n\t %s \n", __func__);
+
+    // Validate input parameters
+    if (InterfaceId >= ADAPTER_PCL_MAX_FLUE_DEVICES ||
+        FlowHashTableId >= ADAPTER_CS_MAX_NOF_FLOW_HASH_TABLES_TO_USE ||
+        Rec_p == NULL)
+        return PCL_INVALID_PARAMETER;
+
+    // Get interface ioarea
+    Dev_p = AdapterPCL_Device_Get(InterfaceId);
+    ioarea_p = Dev_p->EIP207_IOArea_p;
+
+    if (Dev_p->List_p == NULL)
+    {
+        LOG_CRIT("%s: failed, not initialized\n", __func__);
+        return PCL_ERROR;
+    }
+
+    if (Adapter_Lock_CS_Get(&Dev_p->AdapterPCL_DevCS) == Adapter_Lock_NULL)
+    {
+        LOG_CRIT("%s: no device lock, not initialized?\n", __func__);
+        return PCL_ERROR;
+    }
+
+    if (!Adapter_Lock_CS_Enter(&Dev_p->AdapterPCL_DevCS))
+        return PCL_STATUS_BUSY;
+
+    PCL_Rc2 = AdapterPCL_ListID_Get(InterfaceId, &ListID);
+    if (PCL_Rc2 != PCL_STATUS_OK)
+    {
+        LOG_CRIT("%s: failed to get free list\n", __func__);
+        goto error_exit;
+    }
+
+    // Get list element
+    ListElement_p = Rec_p->Context_p;
+    if (ListElement_p == NULL || ListElement_p->DataObject_p == NULL)
+    {
+        PCL_Rc = PCL_INVALID_PARAMETER;
+        goto error_exit;
+    }
+
+    // Get hash list that contains all transform record descriptors
+    // for this transform
+    HashList_p = ListElement_p->DataObject_p;
+
+    while (HashList_p)
+    {
+        // Get the element from hash list that references record descriptor
+        List_Rc = List_RemoveFromTail(LIST_DUMMY_LIST_ID,
+                                      HashList_p,
+                                      &Element_p);
+        if (List_Rc != LIST_STATUS_OK || Element_p == NULL)
+        {
+            LOG_CRIT(
+                "%s: failed to get element from hash list\n", __func__);
+            goto error_exit;
+        }
+
+        // Retrieve transform record descriptor
+        TR_Dscr_p = Element_p->DataObject_p;
+        if (TR_Dscr_p == NULL)
+        {
+            LOG_CRIT("%s: failed, invalid transform handle\n", __func__);
+            PCL_Rc = PCL_INVALID_PARAMETER;
+            goto error_exit;
+        }
+
+        if (RPM_DEVICE_IO_START_MACRO(ADAPTER_PCL_RPM_EIP207_DEVICE_ID + InterfaceId,
+                                      RPM_FLAG_SYNC) != RPM_SUCCESS)
+        {
+            PCL_Rc = PCL_ERROR;
+            goto error_exit;
+        }
+
+        LOG_INFO("\n\t\t EIP207_Flow_DTL_TR_Remove \n");
+
+        EIP207_Rc = EIP207_Flow_DTL_TR_Remove(ioarea_p,
+                                              FlowHashTableId,
+                                              TR_Dscr_p);
+
+        (void)RPM_DEVICE_IO_STOP_MACRO(ADAPTER_PCL_RPM_EIP207_DEVICE_ID + InterfaceId,
+                                       RPM_FLAG_ASYNC);
+
+        if (EIP207_Rc != EIP207_FLOW_NO_ERROR)
+        {
+            LOG_CRIT("%s: failed to remove TR, "
+                     "EIP207_Flow_DTL_TR_Remove() error %d\n",
+                    __func__,
+                    EIP207_Rc);
+            // Return element to hash list
+            List_AddToHead(LIST_DUMMY_LIST_ID, HashList_p, Element_p);
+            goto error_exit;
+        }
+
+        {
+            unsigned int Count;
+
+            // Return the element to the free list
+            List_Rc = List_AddToHead(ListID, NULL, Element_p);
+            if (List_Rc != LIST_STATUS_OK)
+            {
+                LOG_CRIT(
+                    "%s: failed to get free element from list\n", __func__);
+                goto error_exit;
+            }
+
+            // Check if transform record has any hash values still referencing it
+            List_GetListElementCount(LIST_DUMMY_LIST_ID, HashList_p, &Count);
+            if (Count == 0)
+            {
+                // Return the element to the free list
+                List_Rc = List_AddToHead(LIST_DUMMY_LIST_ID,
+                                         Dev_p->List_p,
+                                         ListElement_p);
+                if (List_Rc != LIST_STATUS_OK)
+                {
+                    LOG_CRIT("%s: failed to return element to pool list\n",
+                              __func__);
+                    goto error_exit;
+                }
+
+                Rec_p->Context_p = HashList_p = NULL;
+            }
+        }
+    } // while
+
+    PCL_Rc = PCL_STATUS_OK;
+
+error_exit:
+    Adapter_Lock_CS_Leave(&Dev_p->AdapterPCL_DevCS);
+    return PCL_Rc;
+}
+
+
+/*-----------------------------------------------------------------------------
+ * PCL_DTL_Hash_Remove
+ */
+PCL_Status_t
+PCL_DTL_Hash_Remove(
+        const unsigned int InterfaceId,
+        const unsigned int FlowHashTableId,
+        PCL_DTL_Hash_Handle_t * const HashHandle_p)
+{
+    PCL_Status_t PCL_Rc = PCL_ERROR;
+    PCL_Status_t PCL_Rc2;
+    EIP207_Flow_Error_t EIP207_Rc;
+    EIP207_Flow_IOArea_t * ioarea_p;
+    EIP207_Flow_TR_Dscr_t * TR_Dscr_p;
+    List_Element_t * Element_p;
+    AdapterPCL_Device_Instance_Data_t * Dev_p;
+    DMAResource_Record_t * Rec_p;
+
+    LOG_INFO("\n\t %s \n", __func__);
+
+    // Validate input parameters
+    if (InterfaceId >= ADAPTER_PCL_MAX_FLUE_DEVICES ||
+        FlowHashTableId >= ADAPTER_CS_MAX_NOF_FLOW_HASH_TABLES_TO_USE)
+        return PCL_INVALID_PARAMETER;
+
+    // Get interface ioarea
+    Dev_p = AdapterPCL_Device_Get(InterfaceId);
+    ioarea_p = Dev_p->EIP207_IOArea_p;
+
+    if (Dev_p->List_p == NULL)
+    {
+        LOG_CRIT("%s: failed, not initialized\n", __func__);
+        return PCL_ERROR;
+    }
+
+    if (Adapter_Lock_CS_Get(&Dev_p->AdapterPCL_DevCS) == Adapter_Lock_NULL)
+    {
+        LOG_CRIT("%s: no device lock, not initialized?\n", __func__);
+        return PCL_ERROR;
+    }
+
+    if (!Adapter_Lock_CS_Enter(&Dev_p->AdapterPCL_DevCS))
+        return PCL_STATUS_BUSY;
+
+    // Retrieve transform record descriptor
+    Element_p = HashHandle_p->p;
+    if (Element_p == NULL)
+    {
+        LOG_CRIT("%s: failed, invalid hash handle\n", __func__);
+        PCL_Rc = PCL_INVALID_PARAMETER;
+        goto error_exit;
+    }
+
+    TR_Dscr_p = Element_p->DataObject_p;
+    if (TR_Dscr_p == NULL)
+    {
+        LOG_CRIT("%s: failed, invalid hash handle for transform descriptor\n",
+                 __func__);
+        PCL_Rc = PCL_INVALID_PARAMETER;
+        goto error_exit;
+    }
+
+    Rec_p = DMAResource_Handle2RecordPtr(TR_Dscr_p->DMA_Handle);
+    if (Rec_p == NULL || Rec_p->Context_p == NULL)
+    {
+        LOG_CRIT("%s: failed, invalid hash handle for DMA resource\n",
+                 __func__);
+        PCL_Rc = PCL_INVALID_PARAMETER;
+        goto error_exit;
+    }
+
+    if (RPM_DEVICE_IO_START_MACRO(ADAPTER_PCL_RPM_EIP207_DEVICE_ID + InterfaceId,
+                                  RPM_FLAG_SYNC) != RPM_SUCCESS)
+    {
+        PCL_Rc = PCL_ERROR;
+        goto error_exit;
+    }
+
+    LOG_INFO("\n\t\t EIP207_Flow_DTL_TR_Remove \n");
+
+    EIP207_Rc = EIP207_Flow_DTL_TR_Remove(ioarea_p, FlowHashTableId, TR_Dscr_p);
+
+    (void)RPM_DEVICE_IO_STOP_MACRO(ADAPTER_PCL_RPM_EIP207_DEVICE_ID + InterfaceId,
+                                   RPM_FLAG_ASYNC);
+
+    if (EIP207_Rc != EIP207_FLOW_NO_ERROR)
+    {
+        LOG_CRIT("%s: failed to remove TR, "
+                 "EIP207_Flow_DTL_TR_Remove() error %d\n",
+                __func__,
+                EIP207_Rc);
+        goto error_exit;
+    }
+
+    {
+        unsigned int ListID, Count;
+        List_Status_t List_Rc;
+        List_Element_t * ListElement_p = Rec_p->Context_p;
+        void * HashList_p = ListElement_p->DataObject_p;
+
+        // Remove the hash value from the transform record list
+        List_Rc = List_RemoveAnywhere(LIST_DUMMY_LIST_ID,
+                                      HashList_p,
+                                      Element_p);
+        if (List_Rc != LIST_STATUS_OK)
+        {
+            LOG_CRIT("%s: failed to remove hash from record list\n", __func__);
+        }
+
+        PCL_Rc2 = AdapterPCL_ListID_Get(InterfaceId, &ListID);
+        if (PCL_Rc2 != PCL_STATUS_OK)
+        {
+            LOG_CRIT("%s: failed to get free list\n", __func__);
+            goto error_exit;
+        }
+
+        // Return the element to the free list
+        List_Rc = List_AddToHead(ListID, NULL, Element_p);
+        if (List_Rc != LIST_STATUS_OK)
+        {
+            LOG_CRIT(
+                "%s: failed to get free element from list\n", __func__);
+            goto error_exit;
+        }
+
+        // Check if transform record has any hash values still referencing it
+        List_GetListElementCount(LIST_DUMMY_LIST_ID, HashList_p, &Count);
+        if (Count == 0)
+        {
+            // Return the element to the free list
+            List_Rc = List_AddToHead(LIST_DUMMY_LIST_ID,
+                                     Dev_p->List_p,
+                                     ListElement_p);
+            if (List_Rc != LIST_STATUS_OK)
+            {
+                LOG_CRIT("%s: failed to return element to pool list\n",
+                          __func__);
+                goto error_exit;
+            }
+
+            Rec_p->Context_p = NULL;
+        }
+    }
+
+    // Invalidate hash handle
+    HashHandle_p->p = NULL;
+
+    PCL_Rc = PCL_STATUS_OK;
+
+error_exit:
+    Adapter_Lock_CS_Leave(&Dev_p->AdapterPCL_DevCS);
+    return PCL_Rc;
+}
+
+
+/*-----------------------------------------------------------------------------
+ * PCL_DTL_Init
+ */
+PCL_Status_t
+PCL_DTL_Init(
+        const unsigned int InterfaceId)
+{
+    PCL_Status_t PCL_Rc = PCL_ERROR;
+    AdapterPCL_Device_Instance_Data_t * Dev_p;
+
+    LOG_INFO("\n\t %s \n", __func__);
+
+    // Validate input parameters.
+    if (InterfaceId >= ADAPTER_PCL_MAX_FLUE_DEVICES)
+        return PCL_INVALID_PARAMETER;
+
+    // Get interface ioarea
+    Dev_p = AdapterPCL_Device_Get(InterfaceId);
+
+    if (Dev_p->List_p != NULL)
+    {
+        LOG_CRIT("%s: failed, already initialized\n", __func__);
+        return PCL_ERROR;
+    }
+
+    if (Adapter_Lock_CS_Get(&Dev_p->AdapterPCL_DevCS) == Adapter_Lock_NULL)
+    {
+        LOG_CRIT("%s: failed, no device lock, not initialized?\n", __func__);
+        return PCL_ERROR;
+    }
+
+    if (!Adapter_Lock_CS_Enter(&Dev_p->AdapterPCL_DevCS))
+        return PCL_STATUS_BUSY;
+
+    // Create pool of lists for record descriptors
+    {
+        unsigned int i;
+        void * List_p;
+        List_Element_t * ListElementPool_p;
+        List_Element_t * Element_p;
+        unsigned char * ListPool_p;
+        unsigned int ListInstanceByteCount = List_GetInstanceByteCount();
+
+        // Allocate PCL DTL list instance that will chain other lists
+        List_p = Adapter_Alloc(ListInstanceByteCount);
+        if (List_p == NULL)
+        {
+            LOG_CRIT("%s: list pool allocation failed\n", __func__);
+            goto error_exit;
+        }
+        memset(List_p, 0, ListInstanceByteCount);
+
+        // Initialize PCL DTL list instance
+        if (List_Init(LIST_DUMMY_LIST_ID,
+                      List_p) != LIST_STATUS_OK)
+        {
+            LOG_CRIT("%s: list pool initialization failed\n", __func__);
+            goto error_exit;
+        }
+
+        // Allocate a pool of list elements
+        ListElementPool_p = Adapter_Alloc(sizeof(List_Element_t) *
+                                            ADAPTER_PCL_FLOW_RECORD_COUNT);
+        if (ListElementPool_p == NULL)
+        {
+            LOG_CRIT("%s: pool elements allocation failed\n", __func__);
+            Adapter_Free(List_p);
+            goto error_exit;
+        }
+
+        // Allocate a pool of lists,
+        // one list for one transform record
+        ListPool_p = Adapter_Alloc(ListInstanceByteCount *
+                                           ADAPTER_PCL_FLOW_RECORD_COUNT);
+        if (ListPool_p == NULL)
+        {
+            LOG_CRIT("%s:  pool lists allocation failed\n", __func__);
+            Adapter_Free(List_p);
+            Adapter_Free(ListElementPool_p);
+            goto error_exit;
+        }
+        memset(ListPool_p,
+               0,
+               ListInstanceByteCount * ADAPTER_PCL_FLOW_RECORD_COUNT);
+        Dev_p->ListPool_p = ListPool_p;
+
+        // Populate the pool list with the elements (lists)
+        Element_p = ListElementPool_p;
+        Element_p->DataObject_p = ListPool_p;
+        for (i = 0; i < ADAPTER_PCL_FLOW_RECORD_COUNT; i++)
+        {
+            if (List_AddToHead(LIST_DUMMY_LIST_ID,
+                               List_p,
+                               Element_p) == LIST_STATUS_OK)
+            {
+                if (i + 1 < ADAPTER_PCL_FLOW_RECORD_COUNT)
+                {
+                    Element_p++;
+                    ListPool_p += ListInstanceByteCount;
+                    Element_p->DataObject_p = ListPool_p;
+                }
+            }
+            else
+            {
+                LOG_CRIT("%s: pool list population failed\n", __func__);
+                Dev_p->ListPool_p = NULL;
+                Adapter_Free(List_p);
+                Adapter_Free(ListElementPool_p);
+                Adapter_Free(ListPool_p);
+                goto error_exit;
+            }
+        } // for
+
+        Dev_p->List_p            = List_p;
+        Dev_p->ListElementPool_p = ListElementPool_p;
+
+        PCL_Rc = PCL_STATUS_OK;
+    }  // Created pool of lists for record descriptors
+
+error_exit:
+
+    Adapter_Lock_CS_Leave(&Dev_p->AdapterPCL_DevCS);
+    return PCL_Rc;
+}
+
+
+/*-----------------------------------------------------------------------------
+ * PCL_DTL_UnInit
+ */
+PCL_Status_t
+PCL_DTL_UnInit(
+        const unsigned int InterfaceId)
+{
+    AdapterPCL_Device_Instance_Data_t * Dev_p;
+
+    LOG_INFO("\n\t %s \n", __func__);
+
+    // Validate input parameters.
+    if (InterfaceId >= ADAPTER_PCL_MAX_FLUE_DEVICES)
+        return PCL_INVALID_PARAMETER;
+
+    // Get interface ioarea
+    Dev_p = AdapterPCL_Device_Get(InterfaceId);
+    if (Dev_p->List_p == NULL)
+    {
+        LOG_CRIT("%s: failed, not initialized\n", __func__);
+        return PCL_ERROR;
+    }
+
+    if (Adapter_Lock_CS_Get(&Dev_p->AdapterPCL_DevCS) == Adapter_Lock_NULL)
+    {
+        LOG_CRIT("%s: failed, no device lock, not initialized?\n", __func__);
+        return PCL_ERROR;
+    }
+
+    if (!Adapter_Lock_CS_Enter(&Dev_p->AdapterPCL_DevCS))
+        return PCL_STATUS_BUSY;
+
+    // pool list data structures
+    Adapter_Free(Dev_p->ListElementPool_p);
+    Adapter_Free(Dev_p->ListPool_p);
+    List_Uninit(LIST_DUMMY_LIST_ID, Dev_p->List_p);
+    Adapter_Free(Dev_p->List_p);
+
+    Dev_p->List_p               = NULL;
+    Dev_p->ListElementPool_p    = NULL;
+    Dev_p->ListPool_p           = NULL;
+
+    Adapter_Lock_CS_Leave(&Dev_p->AdapterPCL_DevCS);
+
+    return PCL_STATUS_OK;
+}
+
+
+/* end of file adapter_pcl_dtl.c */
diff --git a/package-21.02/kernel/crypto-eip/src/ddk/slad/adapter_pcl_generic.c b/package-21.02/kernel/crypto-eip/src/ddk/slad/adapter_pcl_generic.c
new file mode 100644
index 0000000..280d03d
--- /dev/null
+++ b/package-21.02/kernel/crypto-eip/src/ddk/slad/adapter_pcl_generic.c
@@ -0,0 +1,1397 @@
+/* adapter_pcl_generic.c
+ *
+ * Packet Classification (PCL) Generic API implementation.
+ *
+ * Notes:
+ * - this implementation does not use SHDEVXS
+ */
+
+/*****************************************************************************
+* Copyright (c) 2011-2020 by Rambus, Inc. and/or its subsidiaries.
+*
+* This program is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 2 of the License, or
+* any later version.
+*
+* This program is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with this program. If not, see <http://www.gnu.org/licenses/>.
+******************************************************************************/
+
+/*----------------------------------------------------------------------------
+ * This module implements (provides) the following interface(s):
+ */
+
+// PCL API
+#include "api_pcl.h"            // PCL_DTL_*
+
+// Adapter PCL Internal API
+#include "adapter_pcl.h"        // AdapterPCL_*
+
+
+/*----------------------------------------------------------------------------
+ * This module uses (requires) the following interface(s):
+ */
+
+// Default Adapter configuration
+#include "c_adapter_pcl.h"
+
+// DMABuf API
+#include "api_dmabuf.h"         // DMABuf_*
+
+// Adapter DMABuf internal API
+#include "adapter_dmabuf.h"
+
+// Convert address to pair of 32-bit words.
+#include "adapter_addrpair.h"
+
+// Buffer allocation (non-DMA) API
+#include "adapter_alloc.h"
+
+// sleeping API/
+#include "adapter_sleep.h"
+
+// Adapter Locking internal API
+#include "adapter_lock.h"       // Adapter_Lock_*
+
+// Runtime Power Management Device Macros API
+#include "rpm_device_macros.h"  // RPM_*
+
+// Logging API
+#include "log.h"
+
+// Driver Framework Device API
+#include "device_types.h"       // Device_Handle_t
+#include "device_mgmt.h"        // Device_find
+
+// Driver Framework DMAResource API
+#include "dmares_types.h"       // DMAResource_Handle_t
+#include "dmares_mgmt.h"        // DMAResource management functions
+#include "dmares_rw.h"          // DMAResource buffer access.
+#include "dmares_addr.h"        // DMAResource addr translation functions.
+#include "dmares_buf.h"         // DMAResource buffer allocations
+
+// List API
+#include "list.h"               // List_*
+
+// Driver Framework C Run-Time Library API
+#include "clib.h"               // memcpy, memset
+
+// Driver Framework Basic Definitions API
+#include "basic_defs.h"         // bool, uint32_t
+
+// EIP-207 Driver Library
+#include "eip207_flow_generic.h"
+
+
+/*----------------------------------------------------------------------------
+ * Definitions and macros
+ */
+
+#if ADAPTER_PCL_MAX_DEVICE_DIGITS > 2
+#error "ADAPTER_PCL_MAX_DEVICE_DIGITS > 2 unsupported"
+#endif
+
+// Maximum number of 32-bit words in a 4Gb bank - representable as uint32_t
+#define ADAPTER_PCL_MAX_BANK_WORDS ((uint32_t)((1ULL<<32) / sizeof(uint32_t)))
+
+
+/*----------------------------------------------------------------------------
+ * Local variables
+ */
+
+static AdapterPCL_Device_Instance_Data_t Dev_Instance [ADAPTER_PCL_MAX_FLUE_DEVICES];
+
+// DMA buffer allocation alignment, in bytes
+static int AdapterPCL_DMA_Alignment_ByteCount =
+                                ADAPTER_DMABUF_ALIGNMENT_INVALID;
+
+// Global lock and critical section for PCL API
+static ADAPTER_LOCK_DEFINE(AdapterPCL_Lock);
+static Adapter_Lock_CS_t AdapterPCL_CS;
+
+// Cached values for RPM device resume operation
+static EIP207_Flow_Address_t EIP207_FlowBaseAddr;
+static EIP207_Flow_Address_t EIP207_TransformBaseAddr;
+static EIP207_Flow_Address_t EIP207_FlowAddr;
+static EIP207_Flow_HT_t EIP207_HT_Params;
+
+
+/*----------------------------------------------------------------------------
+ * Function definitions
+ */
+
+
+/*----------------------------------------------------------------------------
+  AdapterPCLLib_HashTable_Entries_Num_To_Size
+
+  Convert numerical value of number of hashtable entries, to corresponding enum
+
+  number (input)
+    value indicating number of hashtable entries (eg. 32)
+
+  Return:
+      EIP207_Flow_HashTable_Entry_Count_t value representing 'number'
+      or
+      EIP207_FLOW_HASH_TABLE_ENTRIES_MAX+1 indicating error
+
+   Note: implemented using macros to ensure numeric values in step with enums
+ */
+static EIP207_Flow_HashTable_Entry_Count_t
+AdapterPCLLib_HashTable_Entries_Num_To_Size(
+        int number)
+{
+#define HASHTABLE_SIZE_CASE(num) \
+    case (num): return EIP207_FLOW_HASH_TABLE_ENTRIES_##num
+
+    switch (number)
+    {
+        HASHTABLE_SIZE_CASE(32);
+        HASHTABLE_SIZE_CASE(64);
+        HASHTABLE_SIZE_CASE(128);
+        HASHTABLE_SIZE_CASE(256);
+        HASHTABLE_SIZE_CASE(512);
+        HASHTABLE_SIZE_CASE(1024);
+        HASHTABLE_SIZE_CASE(2048);
+        HASHTABLE_SIZE_CASE(4096);
+        HASHTABLE_SIZE_CASE(8192);
+        HASHTABLE_SIZE_CASE(16384);
+        HASHTABLE_SIZE_CASE(32768);
+        HASHTABLE_SIZE_CASE(65536);
+        HASHTABLE_SIZE_CASE(131072);
+        HASHTABLE_SIZE_CASE(262144);
+        HASHTABLE_SIZE_CASE(524288);
+        HASHTABLE_SIZE_CASE(1048576);
+
+        default:
+            return EIP207_FLOW_HASH_TABLE_ENTRIES_MAX + 1;  //invalid value
+    }
+#undef HASHTABLE_SIZE_CASE
+}
+
+
+/*----------------------------------------------------------------------------
+ * AdapterPCLLib_Device_Find
+ *
+ * Returns device handle corresponding to device interface id (index)
+ * Appends characters corresponding to id number to the device base name.
+ * The base name ADAPTER_PCL_FLUE_DEFAULT_DEVICE_NAME may optionally end in zero '0'.
+ * @note Will handle interface index 0-99
+ */
+static Device_Handle_t
+AdapterPCLLib_Device_Find(unsigned int InterfaceId)
+{
+    char device_name_digit;
+    // base name
+    char device_name[]= ADAPTER_PCL_FLUE_DEFAULT_DEVICE_NAME "\0\0\0\0";
+
+    // string's last char
+    int device_name_digit_index = strlen(device_name) - 1;
+
+    // parameter validation
+    if (InterfaceId > 1 ||  // implementation max
+            InterfaceId >= ADAPTER_PCL_MAX_FLUE_DEVICES ||    // config max
+            InterfaceId > 99   // algorithm max
+            )
+    {
+        return NULL;
+    }
+
+    // use final digit (0) if it's present, otherwise skip to end of base name
+    device_name_digit = device_name[device_name_digit_index];
+    if (device_name_digit != '0')
+    {
+        ++device_name_digit_index;
+    }
+
+    if (InterfaceId >= 10)   // two digit identifier, write tens digit
+    {
+        device_name[device_name_digit_index] = (InterfaceId / 10) + '0';
+        ++device_name_digit_index;
+        InterfaceId %= 10;
+    }
+
+    // write units digit
+    device_name[device_name_digit_index] = InterfaceId + '0';
+
+    // look up actual device
+    return Device_Find(device_name);
+}
+
+
+/*-----------------------------------------------------------------------------
+ * AdapterPCL_Int_To_Ptr
+ */
+static inline void *
+AdapterPCL_Int_To_Ptr(
+        const unsigned int Value)
+{
+    union Number
+    {
+        void * p;
+        uintptr_t Value;
+    } N;
+
+    N.Value = (uintptr_t)Value;
+
+    return N.p;
+}
+
+
+#ifdef ADAPTER_PCL_RPM_EIP207_DEVICE_ID
+/*-----------------------------------------------------------------------------
+ * AdapterPCL_Resume
+ */
+static int
+AdapterPCL_Resume(void * p)
+{
+    EIP207_Flow_Error_t res;
+    AdapterPCL_Device_Instance_Data_t * Dev_p;
+    int InterfaceId = *(int *)p;
+
+    // only one hash table in this implementation
+    const unsigned int hashtable_id = 0;
+
+    LOG_INFO("\n\t %s \n", __func__);
+
+    if (InterfaceId < 0 || InterfaceId < ADAPTER_PCL_RPM_EIP207_DEVICE_ID)
+        return -1; // error
+
+    InterfaceId -= ADAPTER_PCL_RPM_EIP207_DEVICE_ID;
+
+    // select current device global instance data, on validated InterfaceId
+    Dev_p = &Dev_Instance[InterfaceId];
+
+#ifdef ADAPTER_PCL_DMARESOURCE_BANKS_ENABLE
+    LOG_INFO("\n\t\t EIP207_Flow_RC_BaseAddr_Set \n");
+
+    // Restore base addresses for flow and transform records
+    res = EIP207_Flow_RC_BaseAddr_Set(Dev_p->EIP207_IOArea_p,
+                                      hashtable_id,
+                                      &EIP207_FlowBaseAddr,
+                                      &EIP207_TransformBaseAddr);
+    if (res != EIP207_FLOW_NO_ERROR)
+    {
+        LOG_CRIT("%s: set records base address failed, error %d\n",
+                 __func__,
+                 res);
+        return -3;
+    }
+#endif // ADAPTER_PCL_DMARESOURCE_BANKS_ENABLE
+
+    LOG_INFO("\n\t\t EIP207_Flow_HashTable_Install \n");
+
+    // Restore FLUE hashtable
+    res =  EIP207_Flow_HashTable_Install(Dev_p->EIP207_IOArea_p,
+                                         hashtable_id,
+                                         &EIP207_HT_Params,
+                                         ADAPTER_PCL_ENABLE_FLUE_CACHE,
+                                         false);
+    if (res != EIP207_FLOW_NO_ERROR)
+    {
+        LOG_CRIT("%s: EIP207_Flow_HashTable_Install() failed, error %d\n",
+                 __func__,
+                 res);
+        return -4;
+    }
+
+    return 0;
+}
+#endif
+
+
+/*-----------------------------------------------------------------------------
+ * Adapter PCL Internal API functions implementation
+ */
+
+/*----------------------------------------------------------------------------
+ * AdapterPCL_DMABuf_To_TRDscr
+ */
+PCL_Status_t
+AdapterPCL_DMABuf_To_TRDscr(
+        const DMABuf_Handle_t TransformHandle,
+        EIP207_Flow_TR_Dscr_t * const TR_Dscr_p,
+        DMAResource_Record_t ** Rec_pp)
+{
+    DMAResource_Handle_t DMAHandle =
+        Adapter_DMABuf_Handle2DMAResourceHandle(TransformHandle);
+
+    DMAResource_AddrPair_t PhysAddr;
+    DMAResource_Record_t * Rec_p;
+
+    Rec_p = DMAResource_Handle2RecordPtr(DMAHandle);
+
+    if (Rec_p == NULL)
+        return PCL_ERROR;
+
+#ifdef ADAPTER_PCL_DMARESOURCE_BANKS_ENABLE
+    if (Rec_p->Props.Bank != ADAPTER_PCL_BANK_TRANSFORM)
+    {
+        LOG_CRIT("PCL Adapter: Invalid bank for Transform\n");
+        return PCL_ERROR;
+    }
+#endif
+
+    if (DMAResource_Translate(DMAHandle, DMARES_DOMAIN_BUS, &PhysAddr) < 0)
+    {
+        LOG_CRIT("PCL_Transform: Failed to obtain physical address.\n");
+        return PCL_ERROR;
+    }
+
+    Adapter_AddrToWordPair(PhysAddr.Address_p, 0,
+                           &TR_Dscr_p->DMA_Addr.Addr,
+                           &TR_Dscr_p->DMA_Addr.UpperAddr);
+
+    TR_Dscr_p->DMA_Handle = DMAHandle;
+
+    *Rec_pp = Rec_p;
+
+    return PCL_STATUS_OK;
+}
+
+
+/*-----------------------------------------------------------------------------
+ * AdapterPCL_Device_Get
+ */
+AdapterPCL_Device_Instance_Data_t *
+AdapterPCL_Device_Get(
+        const unsigned int InterfaceId)
+{
+    return &Dev_Instance[InterfaceId];
+}
+
+
+/*-----------------------------------------------------------------------------
+ * AdapterPCL_ListID_Get
+ */
+PCL_Status_t
+AdapterPCL_ListID_Get(
+        const unsigned int InterfaceId,
+        unsigned int * const ListID_p)
+{
+    // validate parameter
+    if (ListID_p == NULL)
+        return PCL_INVALID_PARAMETER;
+
+    *ListID_p = Dev_Instance[InterfaceId].FreeListID;
+    return PCL_STATUS_OK;
+}
+
+
+/*-----------------------------------------------------------------------------
+ * Adapter PCL API functions implementation
+ */
+
+/*----------------------------------------------------------------------------
+ * PCL_Init
+ */
+PCL_Status_t
+PCL_Init(
+        const unsigned int InterfaceId,
+        const unsigned int NofFlowHashTables)
+{
+    EIP207_Flow_Error_t res;
+    Device_Handle_t EIP207_Device;
+    AdapterPCL_Device_Instance_Data_t * Dev_p;
+
+    unsigned int ioarea_size_bytes;
+    unsigned int descr_total_size_bytes;
+    unsigned int hashtable_entry_size_words, hashtable_total_size_words;
+
+    List_Element_t * ElementPool_p = NULL;
+    unsigned char * RecDscrPool_p = NULL;
+    EIP207_Flow_IOArea_t * ioarea_p = NULL;
+    void * descr_area_ptr = NULL;
+
+    // includes overflow records
+    const unsigned int total_hasharea_element_count =
+                            (ADAPTER_PCL_FLOW_HASH_OVERFLOW_COUNT +
+                                    ADAPTER_PCL_FLOW_HASH_ENTRIES_COUNT);
+
+    DMAResource_Handle_t hashtable_dma_handle = NULL;
+
+    // only one hash table in this implementation
+    const unsigned int hashtable_id = 0;
+
+    LOG_INFO("\n\t PCL_Init \n");
+
+    // check number of hash tables against implementation & config limits
+    if (NofFlowHashTables == 0 ||   // validity
+        NofFlowHashTables > 1 || // implementation limit
+        NofFlowHashTables > ADAPTER_CS_MAX_NOF_FLOW_HASH_TABLES_TO_USE)
+    {
+        LOG_CRIT("PCL_Init: Invalid number (%d) of hash tables\n",
+                 NofFlowHashTables);
+        return PCL_INVALID_PARAMETER;
+    }
+
+    Adapter_Lock_CS_Set(&AdapterPCL_CS, &AdapterPCL_Lock);
+
+    if (!Adapter_Lock_CS_Enter(&AdapterPCL_CS))
+        return PCL_STATUS_BUSY;
+
+    // select current device global instance data, on validated InterfaceId
+    Dev_p = &Dev_Instance[InterfaceId];
+
+    // state consistency check
+    if (Dev_p->PCL_IsInitialized)
+    {
+        LOG_CRIT("PCL_Init: Already initialized\n");
+        Adapter_Lock_CS_Leave(&AdapterPCL_CS);
+        return PCL_ERROR;
+    }
+
+    // Initialize instance variables to 0/NULL defaults
+    ZEROINIT(*Dev_p);
+
+    // Allocate device lock
+    Dev_p->AdapterPCL_DevLock = Adapter_Lock_Alloc();
+    if (Dev_p->AdapterPCL_DevLock == Adapter_Lock_NULL)
+    {
+        LOG_CRIT("PCL_Init: PutLock allocation failed\n");
+        Adapter_Lock_CS_Leave(&AdapterPCL_CS);
+        return PCL_OUT_OF_MEMORY_ERROR;
+    }
+    Adapter_Lock_CS_Set(&Dev_p->AdapterPCL_DevCS,
+                         Dev_p->AdapterPCL_DevLock);
+
+    // identify device, check InterfaceId
+    EIP207_Device = AdapterPCLLib_Device_Find(InterfaceId);
+    if (EIP207_Device == NULL)
+    {
+        LOG_CRIT("PCL_Init: Cannot find EIP-207 device, id=%d\n", InterfaceId);
+        goto error_exit;
+    }
+
+    // Get DMA buffer allocation alignment
+    AdapterPCL_DMA_Alignment_ByteCount = Adapter_DMAResource_Alignment_Get();
+    if (AdapterPCL_DMA_Alignment_ByteCount == ADAPTER_DMABUF_ALIGNMENT_INVALID)
+    {
+#if ADAPTER_PCL_DMA_ALIGNMENT_BYTE_COUNT == 0
+        LOG_CRIT("PCL_Init: Failed to get DMA alignment\n");
+        goto error_exit;
+#else
+        AdapterPCL_DMA_Alignment_ByteCount =
+                                ADAPTER_PCL_DMA_ALIGNMENT_BYTE_COUNT;
+#endif
+    }
+
+    // allocate IOArea non-DMA memory
+    ioarea_size_bytes = EIP207_Flow_IOArea_ByteCount_Get();
+    ioarea_p = Adapter_Alloc(ioarea_size_bytes);
+
+    if (ioarea_p == NULL)
+    {
+        LOG_CRIT("PCL_Init: Cannot allocate IOArea\n");
+        goto error_exit;
+    }
+
+    // store value for global use
+    Dev_p->EIP207_IOArea_p = ioarea_p;
+
+    if (RPM_DEVICE_INIT_START_MACRO(ADAPTER_PCL_RPM_EIP207_DEVICE_ID + InterfaceId,
+                                    0, // No suspend callback is used
+                                    AdapterPCL_Resume) != RPM_SUCCESS)
+        goto error_exit;
+
+    LOG_INFO("\n\t\t EIP207_Flow_Init \n");
+
+    // hand IOArea memory to driver
+    res = EIP207_Flow_Init(Dev_p->EIP207_IOArea_p,
+                           EIP207_Device);
+    if (res != EIP207_FLOW_NO_ERROR)
+    {
+        LOG_CRIT("PCL_Init: EIP207_Flow_Init() failed\n");
+        goto fail;  // exit which frees allocated resources
+    }
+
+#ifdef ADAPTER_PCL_DMARESOURCE_BANKS_ENABLE
+    {
+        unsigned int RecordWordCount;
+
+        RecordWordCount = EIP207_Flow_TR_WordCount_Get();
+
+        if (RecordWordCount * sizeof(uint32_t) >
+                ADAPTER_TRANSFORM_RECORD_BYTE_COUNT)
+        {
+            LOG_CRIT("PCL_Init: Bad Record size in transform bank, "
+                     "is %d, at least %d required\n",
+                     (int)(ADAPTER_TRANSFORM_RECORD_BYTE_COUNT *
+                               sizeof(uint32_t)),
+                     RecordWordCount);
+            goto fail;  // exit which frees allocated resources
+        }
+
+        RecordWordCount = EIP207_Flow_FR_WordCount_Get();
+
+        if (RecordWordCount * sizeof(uint32_t) >
+                           ADAPTER_PCL_FLOW_RECORD_BYTE_COUNT)
+        {
+            LOG_CRIT("PCL_Init: Bad Record size in flow bank, "
+                     "is %d, at least %d required\n",
+                     (int)(ADAPTER_PCL_FLOW_RECORD_BYTE_COUNT *
+                               sizeof(uint32_t)),
+                     RecordWordCount);
+            goto fail;  // exit which frees allocated resources
+        }
+    }
+
+    { // Set the SA pool base address.
+        int dmares;
+        DMAResource_Handle_t DMAHandle;
+        DMAResource_Properties_t DMAProperties;
+        DMAResource_AddrPair_t DMAAddr;
+
+        ZEROINIT(EIP207_FlowBaseAddr);
+        ZEROINIT(EIP207_TransformBaseAddr);
+
+        // Perform a full-bank allocation in transform bank to obtain the bank base
+        // address.
+        {
+            DMAProperties.Alignment = AdapterPCL_DMA_Alignment_ByteCount;
+            DMAProperties.Bank      = ADAPTER_PCL_BANK_TRANSFORM;
+            DMAProperties.fCached   = false;
+            DMAProperties.Size      = ADAPTER_TRANSFORM_RECORD_COUNT *
+                                          ADAPTER_TRANSFORM_RECORD_BYTE_COUNT;
+            dmares = DMAResource_Alloc(DMAProperties,
+                                       &DMAAddr,
+                                       &DMAHandle);
+            if (dmares != 0)
+            {
+                LOG_CRIT(
+                        "PCL_Init: allocate transforms base address failed\n");
+                goto fail;  // exit which frees allocated resources
+            }
+
+            // Derive the physical address from the DMA resource.
+            if (DMAResource_Translate(DMAHandle,
+                                      DMARES_DOMAIN_BUS,
+                                      &DMAAddr)             < 0)
+            {
+                DMAResource_Release(DMAHandle);
+                LOG_CRIT(
+                      "PCL_Init: translate transforms base address failed\n");
+                goto fail;  // exit which frees allocated resources
+            }
+
+            Adapter_AddrToWordPair(DMAAddr.Address_p,
+                                   0,
+                                   &EIP207_TransformBaseAddr.Addr,
+                                   &EIP207_TransformBaseAddr.UpperAddr);
+
+            // Release the DMA resource
+            DMAResource_Release(DMAHandle);
+        }
+
+        // Perform a size 0 allocation in flow bank to obtain the bank base
+        // address.
+        DMAProperties.Alignment = AdapterPCL_DMA_Alignment_ByteCount;
+        DMAProperties.Bank      = ADAPTER_PCL_BANK_FLOW;
+        DMAProperties.fCached   = false;
+        DMAProperties.Size      = ADAPTER_PCL_FLOW_RECORD_COUNT *
+                                          ADAPTER_PCL_FLOW_RECORD_BYTE_COUNT;
+        dmares = DMAResource_Alloc(DMAProperties,
+                                   &DMAAddr,
+                                   &DMAHandle);
+        if (dmares != 0)
+        {
+            LOG_CRIT("PCL_Init: allocate flow base address failed\n");
+            goto fail;  // exit which frees allocated resources
+        }
+
+        // Derive the physical address from the DMA resource.
+        if (DMAResource_Translate(DMAHandle, DMARES_DOMAIN_BUS, &DMAAddr) < 0)
+        {
+            DMAResource_Release(DMAHandle);
+            LOG_CRIT("PCL_Init: translate flow base address failed\n");
+            goto fail;  // exit which frees allocated resources
+        }
+
+        Adapter_AddrToWordPair(DMAAddr.Address_p, 0,
+                               &EIP207_FlowBaseAddr.Addr,
+                               &EIP207_FlowBaseAddr.UpperAddr);
+
+        // Release the DMA resource - handle to zero-size request.
+        DMAResource_Release(DMAHandle);
+
+        LOG_INFO("\n\t\t EIP207_Flow_RC_BaseAddr_Set \n");
+
+        // set base addresses for flow and transform records
+        res = EIP207_Flow_RC_BaseAddr_Set(
+                ioarea_p,
+                hashtable_id,
+                &EIP207_FlowBaseAddr,
+                &EIP207_TransformBaseAddr);
+        if (res != EIP207_FLOW_NO_ERROR)
+        {
+            LOG_CRIT("PCL_Init: set records base address failed\n");
+            goto fail;  // exit which frees allocated resources
+        }
+
+    }
+#endif // ADAPTER_PCL_DMARESOURCE_BANKS_ENABLE
+
+    // Install Hashtable:
+    // - calculate amount of required descriptor memory & allocate it
+    // - calculate amount of required DMA-safe hashtable+overflow memory &
+    //   allocate it
+    // - fill in struct for HT install, call install function
+
+    // descriptor memory
+    descr_total_size_bytes = EIP207_Flow_HTE_Dscr_ByteCount_Get() *
+                                               total_hasharea_element_count;
+
+    descr_area_ptr = Adapter_Alloc(descr_total_size_bytes);
+    if (descr_area_ptr == NULL)
+    {
+        LOG_CRIT("PCL_Init: Cannot allocate descriptor area\n");
+        goto fail;  // exit which frees allocated resources
+    }
+
+    // store value for global use
+    Dev_p->EIP207_Descriptor_Area_p = descr_area_ptr;
+
+    // get required memory size for hash table
+    // = (hash table size + overflow entries)*bucket size
+    hashtable_entry_size_words = EIP207_Flow_HT_Entry_WordCount_Get();
+    hashtable_total_size_words =
+            hashtable_entry_size_words * total_hasharea_element_count;
+
+    // check total size of hashtable region (lookup + overflow)
+    // would not exceed a 32-bit addressable bank of 4GB
+    if (hashtable_total_size_words >= ADAPTER_PCL_MAX_BANK_WORDS)
+    {
+        LOG_CRIT("PCL_Init: Too many hashtable lookup elements for bank\n");
+        goto fail;  // exit which frees allocated resources
+    }
+
+    // get DMA-safe memory for hashtable in appropriate bank
+    {
+        DMAResource_Properties_t TableProperties;
+        DMAResource_AddrPair_t TableHostAddr;
+        DMAResource_AddrPair_t PhysAddr;
+        int dmares;
+
+        // required DMA buffer properties
+        TableProperties.Alignment = AdapterPCL_DMA_Alignment_ByteCount;
+        // Hash table DMA bank
+        TableProperties.Bank      = ADAPTER_PCL_BANK_FLOWTABLE;
+        TableProperties.fCached   = false;
+        // Check if this does not exceed 4 GB, do it somewhere above
+        // size in bytes
+        TableProperties.Size      = hashtable_total_size_words *
+                                                        sizeof(uint32_t);
+
+        // Perform a full-bank allocation in flow table bank to obtain
+        // the bank base address.
+        dmares = DMAResource_Alloc(TableProperties,
+                                   &TableHostAddr,
+                                   &hashtable_dma_handle);
+
+#ifdef ADAPTER_PCL_ENABLE_SWAP
+        DMAResource_SwapEndianness_Set(hashtable_dma_handle, true);
+#endif
+        if (dmares != 0)
+        {
+            LOG_CRIT("PCL_Init: Failed to allocate flow hash table\n");
+            goto fail;  // exit which frees allocated resources
+        }
+
+        // get physical address from handle
+        if (DMAResource_Translate(hashtable_dma_handle,
+                                  DMARES_DOMAIN_BUS,
+                                  &PhysAddr) < 0)
+        {
+            LOG_CRIT("PCL_Init: Failed to obtain physical address.\n");
+            goto fail;  // exit which frees allocated resources
+        }
+
+        ZEROINIT(EIP207_FlowAddr);
+
+        // physical address as upper and lower (EIP207_Flow_Address_t)
+        Adapter_AddrToWordPair(PhysAddr.Address_p, 0,
+                               &EIP207_FlowAddr.Addr,
+                               &EIP207_FlowAddr.UpperAddr);
+
+        // fill in FLUE hashtable descriptor fields
+        ZEROINIT(EIP207_HT_Params);
+
+        // handle
+        EIP207_HT_Params.HT_DMA_Handle    = hashtable_dma_handle;
+
+        // translated addr
+        EIP207_HT_Params.HT_DMA_Address_p = &EIP207_FlowAddr;
+
+        // Convert numerical value to enum
+        EIP207_HT_Params.HT_TableSize     =
+                            AdapterPCLLib_HashTable_Entries_Num_To_Size(
+                                         ADAPTER_PCL_FLOW_HASH_ENTRIES_COUNT);
+        EIP207_HT_Params.DT_p             = descr_area_ptr;
+
+        // hash table plus overflow
+        EIP207_HT_Params.DT_EntryCount    = total_hasharea_element_count;
+    }
+
+    LOG_INFO("\n\t\t EIP207_Flow_HashTable_Install \n");
+
+    // install FLUE hashtable
+    res =  EIP207_Flow_HashTable_Install(ioarea_p,
+                                         hashtable_id,
+                                         &EIP207_HT_Params,
+                                         ADAPTER_PCL_ENABLE_FLUE_CACHE,
+                                         true);
+    if (res != EIP207_FLOW_NO_ERROR)
+    {
+        LOG_CRIT("PCL_Init: EIP207_Flow_HashTable_Install failed\n");
+        goto fail;  // exit which frees allocated resources
+    }
+
+    // Initialize the free list of record descriptors
+    {
+        unsigned int i;
+        List_Element_t * Element_p;
+        unsigned char * RecDscr_p;
+        unsigned int RecordByteCount = MAX(EIP207_Flow_FR_Dscr_ByteCount_Get(),
+            EIP207_Flow_TR_Dscr_ByteCount_Get());
+
+        // Set the free list ID
+        Dev_p->FreeListID = ADAPTER_PCL_LIST_ID_OFFSET + InterfaceId;
+
+        // Allocate a pool of list elements
+        ElementPool_p = Adapter_Alloc(sizeof(List_Element_t) *
+                                        total_hasharea_element_count);
+        if (ElementPool_p == NULL)
+        {
+            LOG_CRIT("PCL_Init: free list allocation failed\n");
+            goto fail;
+        }
+
+        if (List_Init(Dev_p->FreeListID, NULL) != LIST_STATUS_OK)
+        {
+            LOG_CRIT("PCL_Init: free list initialization failed\n");
+            goto fail;
+        }
+
+        // Allocate a pool of record descriptors
+        RecDscrPool_p = Adapter_Alloc( RecordByteCount *
+                                            total_hasharea_element_count);
+        if (RecDscrPool_p == NULL)
+        {
+            LOG_CRIT("PCL_Init: record descriptor allocation failed\n");
+            goto fail;
+        }
+
+        // Populate the free list with the elements (record descriptors)
+        Element_p = ElementPool_p;
+        Element_p->DataObject_p = RecDscr_p = RecDscrPool_p;
+        for(i = 0; i < total_hasharea_element_count; i++)
+        {
+            if (List_AddToHead(Dev_p->FreeListID,
+                               NULL,
+                               Element_p) == LIST_STATUS_OK)
+            {
+                if (i < total_hasharea_element_count - 1)
+                {
+                    Element_p++;
+                    RecDscr_p += RecordByteCount;
+                    Element_p->DataObject_p = RecDscr_p;
+                }
+            }
+            else
+            {
+                LOG_CRIT("PCL_Init: free list population failed\n");
+                goto fail;
+            }
+        }
+
+        Dev_p->RecDscrPool_p = RecDscrPool_p;
+        Dev_p->ElementPool_p = ElementPool_p;
+    }  // Record descriptors free list initialized
+
+    // set remaining instance variables, on success
+    Dev_p->EIP207_Hashtable_DMA_Handle = hashtable_dma_handle;
+    Dev_p->PCL_IsInitialized = true;
+
+    (void)RPM_DEVICE_INIT_STOP_MACRO(ADAPTER_PCL_RPM_EIP207_DEVICE_ID + InterfaceId);
+
+    Adapter_Lock_CS_Leave(&AdapterPCL_CS);
+
+    return PCL_STATUS_OK;
+
+fail:
+    (void)RPM_DEVICE_INIT_STOP_MACRO(ADAPTER_PCL_RPM_EIP207_DEVICE_ID + InterfaceId);
+
+    // free List data structures
+    Adapter_Free(ElementPool_p);
+    Adapter_Free(RecDscrPool_p);
+    List_Uninit(Dev_p->FreeListID, NULL);
+
+    // free memory areas and DMA-safe memory
+    Adapter_Free(Dev_p->EIP207_IOArea_p);
+    Adapter_Free(Dev_p->EIP207_Descriptor_Area_p);
+    if (hashtable_dma_handle != NULL)
+        DMAResource_Release(hashtable_dma_handle);
+
+error_exit:
+    Adapter_Lock_CS_Leave(&AdapterPCL_CS);
+
+    return PCL_ERROR;
+}
+
+
+/*----------------------------------------------------------------------------
+ * PCL_UnInit
+ */
+PCL_Status_t
+PCL_UnInit(
+        const unsigned int InterfaceId)
+{
+    AdapterPCL_Device_Instance_Data_t * Dev_p;
+
+    LOG_INFO("\n\t PCL_UnInit \n");
+
+    if (InterfaceId >= ADAPTER_PCL_MAX_FLUE_DEVICES)
+    {
+        return PCL_INVALID_PARAMETER;
+    }
+
+    Adapter_Lock_CS_Set(&AdapterPCL_CS, &AdapterPCL_Lock);
+
+    if (!Adapter_Lock_CS_Enter(&AdapterPCL_CS))
+        return PCL_STATUS_BUSY;
+
+    // select current device instance data, on validated InterfaceId
+    Dev_p = &Dev_Instance[InterfaceId];
+
+    if (!Dev_p->PCL_IsInitialized)
+    {
+        LOG_CRIT("PCL_UnInit: Not initialized\n");
+        Adapter_Lock_CS_Leave(&AdapterPCL_CS);
+        return PCL_ERROR;
+    }
+
+    if (!Adapter_Lock_CS_Enter(&Dev_p->AdapterPCL_DevCS))
+    {
+        Adapter_Lock_CS_Leave(&Dev_p->AdapterPCL_DevCS);
+        Adapter_Lock_CS_Leave(&AdapterPCL_CS);
+        return PCL_STATUS_BUSY;
+    }
+
+    if (RPM_DEVICE_UNINIT_START_MACRO(ADAPTER_PCL_RPM_EIP207_DEVICE_ID + InterfaceId,
+                                      false) != RPM_SUCCESS)
+    {
+        Adapter_Lock_CS_Leave(&Dev_p->AdapterPCL_DevCS);
+        Adapter_Lock_CS_Leave(&AdapterPCL_CS);
+        return PCL_ERROR;
+    }
+
+    // free List data structures
+    Adapter_Free(Dev_p->ElementPool_p);
+    Adapter_Free(Dev_p->RecDscrPool_p);
+    List_Uninit(Dev_p->FreeListID, NULL);
+
+    // pool list data structures
+    Adapter_Free(Dev_p->ListElementPool_p);
+    Adapter_Free(Dev_p->ListPool_p);
+    if (Dev_p->List_p)
+    {
+        List_Uninit(LIST_DUMMY_LIST_ID, Dev_p->List_p);
+        Dev_p->List_p = NULL;
+    }
+
+    // free memory areas and DMA-safe memory
+    Adapter_Free(Dev_p->EIP207_IOArea_p);
+    Adapter_Free(Dev_p->EIP207_Descriptor_Area_p);
+    DMAResource_Release(Dev_p->EIP207_Hashtable_DMA_Handle);
+
+    // reset globals
+    Dev_p->EIP207_IOArea_p              = NULL;
+    Dev_p->EIP207_Hashtable_DMA_Handle  = NULL;
+    Dev_p->EIP207_Descriptor_Area_p     = NULL;
+    Dev_p->RecDscrPool_p                = NULL;
+    Dev_p->ElementPool_p                = NULL;
+
+    Dev_p->PCL_IsInitialized = false;
+
+    AdapterPCL_DMA_Alignment_ByteCount = ADAPTER_DMABUF_ALIGNMENT_INVALID;
+
+    Adapter_Lock_CS_Leave(&Dev_p->AdapterPCL_DevCS);
+
+    // Free device lock
+    Adapter_Lock_Free(Adapter_Lock_CS_Get(&Dev_p->AdapterPCL_DevCS));
+    Adapter_Lock_CS_Set(&Dev_p->AdapterPCL_DevCS, Adapter_Lock_NULL);
+
+    (void)RPM_DEVICE_UNINIT_STOP_MACRO(ADAPTER_PCL_RPM_EIP207_DEVICE_ID + InterfaceId);
+
+    Adapter_Lock_CS_Leave(&AdapterPCL_CS);
+
+    return PCL_STATUS_OK;
+}
+
+
+/*-----------------------------------------------------------------------------
+ * PCL_Flow_DMABuf_Handle_Get
+ */
+PCL_Status_t
+PCL_Flow_DMABuf_Handle_Get(
+        const PCL_FlowHandle_t FlowHandle,
+        DMABuf_Handle_t * const DMAHandle_p)
+{
+    DMAResource_Handle_t DMARes_Handle;
+    EIP207_Flow_FR_Dscr_t * FlowDescriptor_p;
+    List_Element_t * Element_p = (List_Element_t*)FlowHandle;
+
+    LOG_INFO("\n\t PCL_Flow_DMABuf_Handle_Get \n");
+
+    if (DMAHandle_p == NULL ||
+        Element_p == NULL)
+    {
+        LOG_CRIT("PCL_Flow_DMABuf_Handle_Get: failed, invalid DMABuf handle or Flow Handle\n");
+        return PCL_INVALID_PARAMETER;
+    }
+
+    FlowDescriptor_p = (EIP207_Flow_FR_Dscr_t *)Element_p->DataObject_p;
+
+    if (FlowDescriptor_p == NULL)
+    {
+        LOG_CRIT("PCL_Flow_DMABuf_Handle_Get: failed, invalid flow handle\n");
+        return PCL_INVALID_PARAMETER;
+    }
+
+    DMARes_Handle = FlowDescriptor_p->DMA_Handle;
+
+    *DMAHandle_p = Adapter_DMAResource_Handle2DMABufHandle(DMARes_Handle);
+
+    return PCL_STATUS_OK;
+}
+
+
+/*----------------------------------------------------------------------------
+ * PCL_Flow_Hash
+ */
+PCL_Status_t
+PCL_Flow_Hash(
+        const PCL_SelectorParams_t * const SelectorParams,
+        uint32_t * FlowID_Word32ArrayOf4)
+{
+    EIP207_Flow_SelectorParams_t EIP207_SelectorParams;
+    EIP207_Flow_ID_t FlowID;
+    EIP207_Flow_Error_t res;
+    const unsigned int hashtable_id = 0;    // implementation limit
+
+    LOG_INFO("\n\t PCL_Flow_Hash \n");
+
+    if (SelectorParams == NULL || FlowID_Word32ArrayOf4 == NULL)
+        return PCL_ERROR;
+
+    ZEROINIT(EIP207_SelectorParams);
+    ZEROINIT(FlowID);
+
+    EIP207_SelectorParams.Flags   = SelectorParams->flags;
+    EIP207_SelectorParams.SrcIp_p = SelectorParams->SrcIp;
+    EIP207_SelectorParams.DstIp_p = SelectorParams->DstIp;
+    EIP207_SelectorParams.IpProto = SelectorParams->IpProto;
+    EIP207_SelectorParams.SrcPort = SelectorParams->SrcPort;
+    EIP207_SelectorParams.DstPort = SelectorParams->DstPort;
+    EIP207_SelectorParams.SPI     = SelectorParams->spi;
+    EIP207_SelectorParams.Epoch  = SelectorParams->epoch;
+
+    if (RPM_DEVICE_IO_START_MACRO(ADAPTER_PCL_RPM_EIP207_DEVICE_ID,
+                                  RPM_FLAG_SYNC) != RPM_SUCCESS)
+        return PCL_ERROR;
+
+    LOG_INFO("\n\t\t EIP207_Flow_ID_Compute \n");
+
+    res = EIP207_Flow_ID_Compute(
+            Dev_Instance[hashtable_id].EIP207_IOArea_p,
+            hashtable_id,
+            &EIP207_SelectorParams,
+            &FlowID);
+
+    // Note: only one EIP-207 hash table is supported!
+    (void)RPM_DEVICE_IO_STOP_MACRO(ADAPTER_PCL_RPM_EIP207_DEVICE_ID,
+                                   RPM_FLAG_ASYNC);
+
+    if (res != EIP207_FLOW_NO_ERROR)
+    {
+        LOG_CRIT("PCL_Flow_Hash: operation failed\n");
+        return PCL_ERROR;
+    }
+
+    FlowID_Word32ArrayOf4[0] = FlowID.Word32[0];
+    FlowID_Word32ArrayOf4[1] = FlowID.Word32[1];
+    FlowID_Word32ArrayOf4[2] = FlowID.Word32[2];
+    FlowID_Word32ArrayOf4[3] = FlowID.Word32[3];
+
+    return PCL_STATUS_OK;
+}
+
+
+/*-----------------------------------------------------------------------------
+ * PCL_Flow_Alloc
+ */
+PCL_Status_t
+PCL_Flow_Alloc(
+        const unsigned int InterfaceId,
+        const unsigned int FlowHashTableId,
+        PCL_FlowHandle_t * const FlowHandle_p)
+{
+    PCL_Status_t PCL_Rc = PCL_ERROR;
+    DMAResource_Handle_t DMAHandle;
+    DMAResource_Properties_t DMAProperties;
+    DMAResource_AddrPair_t HostAddr;
+    DMAResource_AddrPair_t PhysAddr;
+    int dmares;
+    EIP207_Flow_FR_Dscr_t * FlowDescriptor_p;
+    unsigned int FR_WordCount;
+    List_Element_t * Element_p;
+    AdapterPCL_Device_Instance_Data_t * Dev_p;
+
+    LOG_INFO("\n\t PCL_Flow_Alloc \n");
+
+    IDENTIFIER_NOT_USED(FlowHashTableId);
+
+    // validate interface id
+    if (InterfaceId >= ADAPTER_PCL_MAX_FLUE_DEVICES)
+        return PCL_INVALID_PARAMETER;
+
+    Dev_p = &Dev_Instance[InterfaceId];
+
+    if (Adapter_Lock_CS_Get(&Dev_p->AdapterPCL_DevCS) == Adapter_Lock_NULL)
+    {
+        LOG_CRIT("PCL_Flow_Alloc: no device lock, not initialized?\n");
+        return PCL_ERROR;
+    }
+
+    if (!Adapter_Lock_CS_Enter(&Dev_p->AdapterPCL_DevCS))
+        return PCL_STATUS_BUSY;
+
+    // select current device instance data, on validated InterfaceId
+    if (!Dev_p->PCL_IsInitialized)
+    {
+        LOG_CRIT("PCL_Flow_Alloc: Not initialized\n");
+        goto error_exit;
+    }
+
+    *FlowHandle_p = NULL;
+
+    LOG_INFO("\n\t\t EIP207_Flow_FR_WordCount_Get \n");
+
+    // Get the required size of the DMA buffer for the flow record.
+    FR_WordCount = EIP207_Flow_FR_WordCount_Get();
+
+    // Allocate a buffer for the flow record (DMA).
+    DMAProperties.Alignment = AdapterPCL_DMA_Alignment_ByteCount;
+    DMAProperties.Bank      = ADAPTER_PCL_BANK_FLOW;
+    DMAProperties.fCached   = false;
+    DMAProperties.Size      = 4 * FR_WordCount;
+
+    dmares = DMAResource_Alloc(DMAProperties, &HostAddr, &DMAHandle);
+    if (dmares != 0)
+    {
+        LOG_CRIT("PCL_Flow_Alloc: could not allocate buffer\n");
+        goto error_exit;
+    }
+
+#ifdef ADAPTER_PCL_ENABLE_SWAP
+    DMAResource_SwapEndianness_Set(DMAHandle, true);
+#endif
+
+    // Get a record descriptor from the free list
+    {
+        List_Status_t List_Rc =
+                List_RemoveFromTail(Dev_p->FreeListID,
+                                    NULL,
+                                    &Element_p);
+        if (List_Rc != LIST_STATUS_OK)
+        {
+            LOG_CRIT("PCL_Flow_Alloc: failed to allocate record\n");
+            goto error_exit;
+        }
+
+        // Get the flow record descriptor place-holder from the list element
+        FlowDescriptor_p = (EIP207_Flow_FR_Dscr_t*)Element_p->DataObject_p;
+        if (FlowDescriptor_p == NULL)
+        {
+            LOG_CRIT("PCL_Flow_Alloc: failed to get record descriptor\n");
+            goto error_exit;
+        }
+    }
+
+    // Fill in the descriptor.
+    FlowDescriptor_p->DMA_Handle = DMAHandle;
+
+    if (DMAResource_Translate(DMAHandle, DMARES_DOMAIN_BUS, &PhysAddr) < 0)
+    {
+        LOG_CRIT("PCL_FlowAlloc: Failed to obtain physical address.\n");
+        DMAResource_Release(DMAHandle);
+        goto error_exit;
+    }
+
+    Adapter_AddrToWordPair(PhysAddr.Address_p, 0,
+                           &FlowDescriptor_p->DMA_Addr.Addr,
+                           &FlowDescriptor_p->DMA_Addr.UpperAddr);
+
+    *FlowHandle_p = (PCL_FlowHandle_t)Element_p;
+
+    PCL_Rc = PCL_STATUS_OK;
+
+error_exit:
+    Adapter_Lock_CS_Leave(&Dev_p->AdapterPCL_DevCS);
+
+    return PCL_Rc;
+}
+
+
+/*-----------------------------------------------------------------------------
+ * PCL_Flow_Add
+ */
+PCL_Status_t
+PCL_Flow_Add(
+        const unsigned int InterfaceId,
+        const unsigned int FlowHashTableId,
+        const PCL_FlowParams_t * const FlowParams,
+        const PCL_FlowHandle_t FlowHandle)
+{
+    PCL_Status_t PCL_Rc = PCL_ERROR;
+    DMAResource_Handle_t DMAHandle;
+    DMAResource_AddrPair_t PhysAddr;
+    EIP207_Flow_Error_t res;
+    EIP207_Flow_FR_InputData_t FlowData;
+    EIP207_Flow_FR_Dscr_t * FlowDescriptor_p;
+    List_Element_t * Element_p = (List_Element_t*)FlowHandle;
+    AdapterPCL_Device_Instance_Data_t * Dev_p;
+
+    LOG_INFO("\n\t PCL_Flow_Add \n");
+
+    // validate interface id
+    if (InterfaceId >= ADAPTER_PCL_MAX_FLUE_DEVICES)
+        return PCL_INVALID_PARAMETER;
+
+    // check valid flow handle
+    if (Element_p == NULL)
+        return PCL_INVALID_PARAMETER;
+
+    FlowDescriptor_p = (EIP207_Flow_FR_Dscr_t *)Element_p->DataObject_p;
+
+    // check valid flow record descriptor
+    if (FlowDescriptor_p == NULL)
+        return PCL_INVALID_PARAMETER;
+
+    Dev_p = &Dev_Instance[InterfaceId];
+
+    if (Adapter_Lock_CS_Get(&Dev_p->AdapterPCL_DevCS) == Adapter_Lock_NULL)
+    {
+        LOG_CRIT("PCL_Flow_Add: no device lock, not initialized?\n");
+        return PCL_ERROR;
+    }
+
+    if (!Adapter_Lock_CS_Enter(&Dev_p->AdapterPCL_DevCS))
+        return PCL_STATUS_BUSY;
+
+    // check interface is initialised
+    if (!Dev_p->PCL_IsInitialized)
+    {
+        LOG_CRIT("PCL_Flow_Add: Not initialized\n");
+        goto error_exit;
+    }
+
+    // Fill in the input data
+    DMAHandle = Adapter_DMABuf_Handle2DMAResourceHandle(FlowParams->transform);
+    if (DMAHandle)
+    {
+        if (DMAResource_Translate(DMAHandle, DMARES_DOMAIN_BUS, &PhysAddr) < 0)
+        {
+            LOG_CRIT("PCL_Flow_Add: Failed to obtain physical address.\n");
+            goto error_exit;
+        }
+    }
+    else
+    {
+        PhysAddr.Domain    = DMARES_DOMAIN_BUS;
+        PhysAddr.Address_p = AdapterPCL_Int_To_Ptr(
+                                    EIP207_Flow_Record_Dummy_Addr_Get());
+    }
+
+    FlowData.Flags               = FlowParams->flags;
+    FlowData.HashID.Word32[0]    = FlowParams->FlowID[0];
+    FlowData.HashID.Word32[1]    = FlowParams->FlowID[1];
+    FlowData.HashID.Word32[2]    = FlowParams->FlowID[2];
+    FlowData.HashID.Word32[3]    = FlowParams->FlowID[3];
+    FlowData.SW_FR_Reference     = FlowParams->FlowIndex;
+    Adapter_AddrToWordPair(PhysAddr.Address_p,0,
+                           &FlowData.Xform_DMA_Addr.Addr,
+                           &FlowData.Xform_DMA_Addr.UpperAddr);
+
+    FlowData.fLarge = false;
+
+#ifndef ADAPTER_PCL_USE_LARGE_TRANSFORM_DISABLE
+    /* Determine whether we have a large transform record. */
+    if (DMAHandle)
+    {
+        DMAResource_Record_t * Rec_p = DMAResource_Handle2RecordPtr(DMAHandle);
+
+        if (Rec_p->fIsLargeTransform)
+           FlowData.fLarge = true;
+    }
+#endif // !ADAPTER_PCL_USE_LARGE_TRANSFORM_DISABLE
+
+    LOG_INFO("\n\t\t EIP207_Flow_FR_Add \n");
+
+    // Add the record
+    res = EIP207_Flow_FR_Add(Dev_p->EIP207_IOArea_p,
+                             FlowHashTableId,
+                             FlowDescriptor_p,
+                             &FlowData);
+    if (res == EIP207_FLOW_OUT_OF_MEMORY_ERROR)
+    {
+        LOG_CRIT("PCL_FLow_Add: failed to install flow, out of memory\n");
+    }
+    else if (res == EIP207_FLOW_NO_ERROR)
+    {
+       PCL_Rc = PCL_STATUS_OK;
+    }
+    else
+    {
+        LOG_CRIT("PCL_FLow_Add: failed to install flow, internal error\n");
+    }
+
+error_exit:
+
+    Adapter_Lock_CS_Leave(&Dev_p->AdapterPCL_DevCS);
+    return PCL_Rc;
+}
+
+
+/*-----------------------------------------------------------------------------
+ * PCL_Flow_Release
+ */
+PCL_Status_t
+PCL_Flow_Release(
+        const unsigned int InterfaceId,
+        const unsigned int FlowHashTableId,
+        const PCL_FlowHandle_t FlowHandle)
+{
+    PCL_Status_t PCL_Rc = PCL_ERROR;
+    EIP207_Flow_FR_Dscr_t * FlowDescriptor_p;
+    List_Element_t * Element_p = (List_Element_t*)FlowHandle;
+    AdapterPCL_Device_Instance_Data_t * Dev_p;
+
+    LOG_INFO("\n\t PCL_Flow_Release \n");
+
+    IDENTIFIER_NOT_USED(InterfaceId);
+    IDENTIFIER_NOT_USED(FlowHashTableId);
+    IDENTIFIER_NOT_USED(FlowHandle);
+
+    // check valid flow handle
+    if (Element_p == NULL)
+        return PCL_INVALID_PARAMETER;
+
+    FlowDescriptor_p = (EIP207_Flow_FR_Dscr_t *)Element_p->DataObject_p;
+
+    // check valid flow record descriptor
+    if (FlowDescriptor_p == NULL)
+        return PCL_INVALID_PARAMETER;
+
+    Dev_p = &Dev_Instance[InterfaceId];
+
+    if (Adapter_Lock_CS_Get(&Dev_p->AdapterPCL_DevCS) == Adapter_Lock_NULL)
+    {
+        LOG_CRIT("PCL_Flow_Release: no device lock, not initialized?\n");
+        return PCL_ERROR;
+    }
+
+    if (!Adapter_Lock_CS_Enter(&Dev_p->AdapterPCL_DevCS))
+        return PCL_STATUS_BUSY;
+
+    // check interface is initialised
+    if (!Dev_p->PCL_IsInitialized)
+    {
+        LOG_CRIT("PCL_Flow_Release: Not initialized\n");
+        goto error_exit;
+    }
+
+    DMAResource_Release(FlowDescriptor_p->DMA_Handle);
+
+    // Put the record descriptor back on the free list
+    {
+        List_Status_t List_Rc;
+
+        List_Rc = List_AddToHead(Dev_p->FreeListID,
+                                 NULL,
+                                 Element_p);
+        if (List_Rc != LIST_STATUS_OK)
+        {
+            LOG_CRIT("PCL_Flow_Release: "
+                     "failed to put descriptor on the free list\n");
+            goto error_exit;
+        }
+    }
+
+    PCL_Rc = PCL_STATUS_OK;
+
+error_exit:
+    Adapter_Lock_CS_Leave(&Dev_p->AdapterPCL_DevCS);
+
+    return PCL_Rc;
+}
+
+
+/*-----------------------------------------------------------------------------
+ * PCL_Flow_Get_ReadOnly
+ */
+PCL_Status_t
+PCL_Flow_Get_ReadOnly(
+        const PCL_FlowHandle_t FlowHandle,
+        PCL_FlowParams_t * const FlowParams_p)
+{
+    EIP207_Flow_FR_Dscr_t * FlowDescriptor_p;
+    EIP207_Flow_FR_OutputData_t FlowData;
+    EIP207_Flow_Error_t res;
+    List_Element_t * Element_p = (List_Element_t*)FlowHandle;
+
+    LOG_INFO("\n\t PCL_Flow_Get_ReadOnly \n");
+
+    // check valid flow handle
+    if (Element_p == NULL)
+        return PCL_INVALID_PARAMETER;
+
+    FlowDescriptor_p = (EIP207_Flow_FR_Dscr_t *)Element_p->DataObject_p;
+
+    // check valid flow record descriptor
+    if (FlowDescriptor_p == NULL)
+        return PCL_INVALID_PARAMETER;
+
+    LOG_INFO("\n\t\t EIP207_Flow_FR_Read \n");
+
+    res = EIP207_Flow_FR_Read(Dev_Instance[0].EIP207_IOArea_p,
+                             0,
+                             FlowDescriptor_p,
+                             &FlowData);
+    if (res == EIP207_FLOW_ARGUMENT_ERROR)
+    {
+        return PCL_INVALID_PARAMETER;
+    }
+    else if (res != EIP207_FLOW_NO_ERROR)
+    {
+        return PCL_ERROR;
+    }
+
+    FlowParams_p->LastTimeLo = FlowData.LastTimeLo;
+    FlowParams_p->LastTimeHi = FlowData.LastTimeHi;
+
+    FlowParams_p->PacketsCounterLo = FlowData.PacketsCounter;
+    FlowParams_p->PacketsCounterHi = 0;
+
+    FlowParams_p->OctetsCounterLo = FlowData.OctetsCounterLo;
+    FlowParams_p->OctetsCounterHi = FlowData.OctetsCounterHi;
+
+    return PCL_STATUS_OK;
+}
+
+/* end of file adapter_pcl_generic.c */
diff --git a/package-21.02/kernel/crypto-eip/src/ddk/slad/adapter_pec_dma.c b/package-21.02/kernel/crypto-eip/src/ddk/slad/adapter_pec_dma.c
new file mode 100644
index 0000000..4bf0a49
--- /dev/null
+++ b/package-21.02/kernel/crypto-eip/src/ddk/slad/adapter_pec_dma.c
@@ -0,0 +1,1989 @@
+/* adapter_pec_dma.c
+ *
+ * Packet Engine Control (PEC) API Implementation
+ * using DMA mode.
+ */
+
+/*****************************************************************************
+* Copyright (c) 2011-2022 by Rambus, Inc. and/or its subsidiaries.
+*
+* This program is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 2 of the License, or
+* any later version.
+*
+* This program is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with this program. If not, see <http://www.gnu.org/licenses/>.
+******************************************************************************/
+
+/*----------------------------------------------------------------------------
+ * This module implements (provides) the following interface(s):
+ */
+
+#include "api_pec.h"            // PEC_* (the API we implement here)
+
+
+/*----------------------------------------------------------------------------
+ * This module uses (requires) the following interface(s):
+ */
+
+// Default Adapter PEC configuration
+#include "c_adapter_pec.h"
+
+// DMABuf API
+#include "api_dmabuf.h"         // DMABuf_*
+
+// Adapter DMABuf internal API
+#include "adapter_dmabuf.h"
+
+// Adapter PEC device API
+#include "adapter_pecdev_dma.h" // Adapter_PECDev_*
+
+// Adapter Locking internal API
+#include "adapter_lock.h"       // Adapter_Lock_*
+
+#ifdef ADAPTER_PEC_ENABLE_SCATTERGATHER
+#include "api_pec_sg.h"         // PEC_SG_* (the API we implement here)
+#endif
+
+// Runtime Power Management Device Macros API
+#include "rpm_device_macros.h"  // RPM_*
+
+// Logging API
+#include "log.h"
+
+// Driver Framework DMAResource API
+#include "dmares_types.h"       // DMAResource_Handle_t
+#include "dmares_mgmt.h"        // DMAResource management functions
+#include "dmares_rw.h"          // DMAResource buffer access.
+#include "dmares_addr.h"        // DMAResource addr translation functions.
+#include "dmares_buf.h"         // DMAResource buffer allocations
+
+// Standard IOToken API
+#include "iotoken.h"
+
+// Driver Framework C Run-Time Library API
+#include "clib.h"               // memcpy, memset
+
+// Driver Framework Basic Definitions API
+#include "basic_defs.h"         // bool, uint32_t
+
+
+#ifndef ADAPTER_PE_MODE_DHM
+/*----------------------------------------------------------------------------
+ * Definitions and macros
+ */
+
+typedef struct
+{
+    void * User_p;
+    DMABuf_Handle_t SrcPkt_Handle;
+    DMABuf_Handle_t DstPkt_Handle;
+    DMABuf_Handle_t Token_Handle;
+    unsigned int Bypass_WordCount;
+} Adapter_SideChannelRecord_t;
+
+
+/* Side channel FIFO
+   - Normal operation: PEC_Packet_Put adds a record containing several
+                                      words for each packet.
+                       PEC_Packet_Get pops one record for each packet, fills
+                                      fields into result descriptor.
+   - Contiuous scatter mode: PEC_Scatter_Preload adds a record
+                                      with DestPkt_Handle only for each scatter
+                                      buffer.
+                             PEC_Packet_Get pops a record for each scatter
+                                      buffer used. Can do PostDMA for each
+                                      scatter buffer, will not fill in fields
+                                      in result descriptor.
+*/
+typedef struct
+{
+    int Size;
+    int ReadIndex;
+    int WriteIndex;
+    Adapter_SideChannelRecord_t Records[1 + ADAPTER_PEC_MAX_PACKETS +
+                                        ADAPTER_PEC_MAX_LOGICDESCR];
+} AdapterPEC_SideChannelFIFO_t;
+
+
+/*----------------------------------------------------------------------------
+ * Local variables
+ */
+static volatile bool PEC_IsInitialized[ADAPTER_PEC_DEVICE_COUNT];
+static volatile bool PEC_ContinuousScatter[ADAPTER_PEC_DEVICE_COUNT];
+
+// Lock and critical section for PEC_Init/Uninit()
+static ADAPTER_LOCK_DEFINE(AdapterPEC_InitLock);
+static Adapter_Lock_CS_t AdapterPEC_InitCS;
+
+// Locks and critical sections for PEC_Packet_Put()
+static Adapter_Lock_t AdapterPEC_PutLock[ADAPTER_PEC_DEVICE_COUNT];
+static Adapter_Lock_CS_t AdapterPEC_PutCS[ADAPTER_PEC_DEVICE_COUNT];
+
+// Locks and critical sections for PEC_Packet_Get()
+static Adapter_Lock_t AdapterPEC_GetLock[ADAPTER_PEC_DEVICE_COUNT];
+static Adapter_Lock_CS_t AdapterPEC_GetCS[ADAPTER_PEC_DEVICE_COUNT];
+
+static AdapterPEC_SideChannelFIFO_t
+Adapter_SideChannelFIFO[ADAPTER_PEC_DEVICE_COUNT];
+
+static struct
+{
+    volatile PEC_NotifyFunction_t ResultNotifyCB_p;
+    volatile unsigned int ResultsCount;
+
+    volatile PEC_NotifyFunction_t CommandNotifyCB_p;
+    volatile unsigned int CommandsCount;
+
+} PEC_Notify[ADAPTER_PEC_DEVICE_COUNT];
+
+
+#ifdef ADAPTER_PEC_INTERRUPTS_ENABLE
+/*----------------------------------------------------------------------------
+ * AdapterPEC_InterruptHandlerResultNotify
+ *
+ * This function is the interrupt handler for the PEC interrupt
+ * sources that indicate the arrival of a a result descriptor..There
+ * may be several interrupt sources.
+ *
+ * This function is used to invoke the PEC result notification callback.
+ */
+static void
+AdapterPEC_InterruptHandlerResultNotify(
+        const int nIRQ,
+        const unsigned int flags)
+{
+    unsigned int InterfaceId = Adapter_PECDev_IRQToInferfaceId(nIRQ);
+
+    IDENTIFIER_NOT_USED(flags);
+
+    if (InterfaceId >= ADAPTER_PEC_DEVICE_COUNT)
+    {
+        LOG_CRIT("AdapterPEC_InterruptHandlerResultNotify"
+                 "InterfaceId out of range\n");
+        return;
+    }
+
+    Adapter_PECDev_Disable_ResultIRQ(InterfaceId);
+
+    LOG_INFO("AdapterPEC_InterruptHandlerResultNotify: Enter\n");
+
+    if (PEC_Notify[InterfaceId].ResultNotifyCB_p != NULL)
+    {
+        PEC_NotifyFunction_t CBFunc_p;
+
+        // Keep the callback on stack to allow registration
+        // of another result notify request from callback
+        CBFunc_p = PEC_Notify[InterfaceId].ResultNotifyCB_p;
+
+        PEC_Notify[InterfaceId].ResultNotifyCB_p = NULL;
+        PEC_Notify[InterfaceId].ResultsCount = 0;
+
+        LOG_INFO(
+            "AdapterPEC_InterruptHandlerResultNotify: "
+            "Invoking PEC result notify callback for interface %d\n",
+            InterfaceId);
+
+        CBFunc_p();
+    }
+}
+
+
+/*----------------------------------------------------------------------------
+ * AdapterPEC_InterruptHandlerCommandNotify
+ *
+ * This function is the interrupt handler for the PEC interrupt sources.that
+ * indicate that there is again freee space for new command descriptors.
+ *
+ * This function is used to invoke the PEC command notification callback.
+ */
+static void
+AdapterPEC_InterruptHandlerCommandNotify(
+        const int nIRQ,
+        const unsigned int flags)
+{
+    unsigned int InterfaceId = Adapter_PECDev_IRQToInferfaceId(nIRQ);
+
+    IDENTIFIER_NOT_USED(flags);
+
+    if (InterfaceId >= ADAPTER_PEC_DEVICE_COUNT)
+    {
+        LOG_CRIT("AdapterPEC_InterruptHandlerCommandNotify"
+                 "InterfaceId out of range\n");
+        return;
+    }
+
+    Adapter_PECDev_Disable_CommandIRQ(InterfaceId);
+
+    LOG_INFO("AdapterPEC_InterruptHandlerCommandNotify: Enter\n");
+
+    if (PEC_Notify[InterfaceId].CommandNotifyCB_p != NULL)
+    {
+        PEC_NotifyFunction_t CBFunc_p;
+
+        // Keep the callback on stack to allow registration
+        // of another command notify request from callback
+        CBFunc_p = PEC_Notify[InterfaceId].CommandNotifyCB_p;
+
+        PEC_Notify[InterfaceId].CommandNotifyCB_p = NULL;
+        PEC_Notify[InterfaceId].CommandsCount = 0;
+
+        LOG_INFO(
+            "AdapterPEC_InterruptHandlerCommandNotify: "
+            "Invoking PEC command notify callback interface=%d\n",
+            InterfaceId);
+
+        CBFunc_p();
+    }
+}
+#endif /* ADAPTER_PEC_INTERRUPTS_ENABLE */
+
+
+/*----------------------------------------------------------------------------
+ * Adapter_MakeCommandNotify_CallBack
+ */
+static inline void
+Adapter_MakeCommandNotify_CallBack(unsigned int InterfaceId)
+{
+    unsigned int PacketSlotsEmptyCount;
+
+    if (InterfaceId >= ADAPTER_PEC_DEVICE_COUNT)
+        return;
+
+    if (PEC_Notify[InterfaceId].CommandNotifyCB_p != NULL)
+    {
+        PacketSlotsEmptyCount = Adapter_PECDev_GetFreeSpace(InterfaceId);
+
+        if (PEC_Notify[InterfaceId].CommandsCount <= PacketSlotsEmptyCount)
+        {
+            PEC_NotifyFunction_t CBFunc_p;
+
+            // Keep the callback on stack to allow registeration
+            // of another result notify request from callback
+            CBFunc_p = PEC_Notify[InterfaceId].CommandNotifyCB_p;
+
+            PEC_Notify[InterfaceId].CommandNotifyCB_p = NULL;
+            PEC_Notify[InterfaceId].CommandsCount = 0;
+
+            LOG_INFO(
+                "PEC_Packet_Get: "
+                "Invoking command notify callback\n");
+
+            CBFunc_p();
+        }
+    }
+}
+
+
+/*----------------------------------------------------------------------------
+ * Adapter_PECResgisterSA_BounceIfRequired
+ *
+ * Returns false in case of error.
+ * Allocate a bounce buffer and copy the data in case this if required.
+ */
+#ifndef ADAPTER_PEC_REMOVE_BOUNCEBUFFERS
+static bool
+Adapter_PECRegisterSA_BounceIfRequired(
+        DMAResource_Handle_t *DMAHandle_p)
+{
+    DMAResource_Handle_t DMAHandle = *DMAHandle_p;
+    DMAResource_Record_t * Rec_p;
+    DMAResource_AddrPair_t BounceHostAddr;
+    void * HostAddr;
+    int dmares;
+
+    // skip null handles
+    if (!DMAResource_IsValidHandle(DMAHandle))
+        return true;    // no error
+
+    Rec_p = DMAResource_Handle2RecordPtr(DMAHandle);
+
+
+    // skip proper buffers
+    if (!Adapter_DMAResource_IsForeignAllocated(DMAHandle))
+    {
+        Rec_p->bounce.Bounce_Handle = NULL;
+        return true;    // no error
+    }
+
+    {
+        DMAResource_Properties_t BounceProperties;
+
+        // used as uint32_t array
+        BounceProperties.Alignment  = Adapter_DMAResource_Alignment_Get();
+        BounceProperties.Bank       = ADAPTER_PEC_BANK_SA;
+        BounceProperties.fCached    = false;
+        BounceProperties.Size       = Rec_p->Props.Size;
+
+        HostAddr = Adapter_DMAResource_HostAddr(DMAHandle);
+
+        dmares = DMAResource_Alloc(
+                     BounceProperties,
+                     &BounceHostAddr,
+                     &Rec_p->bounce.Bounce_Handle);
+
+        // bounce buffer handle is stored in the DMA Resource Record
+        // of the original buffer, which links the two
+        // this will be used when freeing the buffer
+        // but also when the SA is referenced in packet put
+
+        if (dmares != 0)
+        {
+            LOG_CRIT(
+                "PEC_SA_Register: "
+                "Failed to alloc bounce buffer (error %d)\n",
+                dmares);
+            return false;   // error!
+        }
+        LOG_INFO(
+            "PEC_SA_Register: "
+            "Bouncing SA: %p to %p\n",
+            DMAHandle,
+            Rec_p->bounce.Bounce_Handle);
+#ifdef ADAPTER_PEC_ARMRING_ENABLE_SWAP
+        DMAResource_SwapEndianness_Set(Rec_p->bounce.Bounce_Handle, true);
+#endif
+
+    }
+
+    // copy the data to the bounce buffer
+    memcpy(
+        BounceHostAddr.Address_p,
+        HostAddr,
+        Rec_p->Props.Size);
+
+    *DMAHandle_p = Rec_p->bounce.Bounce_Handle;
+    return true;        // no error
+}
+#endif /* ADAPTER_PEC_REMOVE_BOUNCEBUFFERS */
+
+
+/*----------------------------------------------------------------------------
+ * Adapter_FIFO_Put
+ *
+ * Put packet information into the side channel FIFO
+ */
+static bool
+Adapter_FIFO_Put(AdapterPEC_SideChannelFIFO_t *FIFO,
+                 void *User_p,
+                 DMABuf_Handle_t SrcPkt_Handle,
+                 DMABuf_Handle_t DstPkt_Handle,
+                 DMABuf_Handle_t Token_Handle,
+                 unsigned int Bypass_WordCount)
+{
+    int WriteIndex = FIFO->WriteIndex;
+    int ReadIndex = FIFO->ReadIndex;
+    if (WriteIndex == ReadIndex - 1 ||
+        (ReadIndex == 0 && WriteIndex == FIFO->Size - 1))
+    {
+        LOG_CRIT("Side channel FIFO full\n");
+        return false;
+    }
+    FIFO->Records[WriteIndex].User_p = User_p;
+    FIFO->Records[WriteIndex].SrcPkt_Handle = SrcPkt_Handle;
+    FIFO->Records[WriteIndex].DstPkt_Handle = DstPkt_Handle;
+
+    FIFO->Records[WriteIndex].Token_Handle = Token_Handle;
+    if (!DMABuf_Handle_IsSame(&Token_Handle, &DMABuf_NULLHandle))
+    {
+        FIFO->Records[WriteIndex].Bypass_WordCount = Bypass_WordCount;
+    }
+
+    WriteIndex += 1;
+    if (WriteIndex == FIFO->Size)
+        WriteIndex = 0;
+    FIFO->WriteIndex = WriteIndex;
+    return true;
+}
+
+
+/*----------------------------------------------------------------------------
+ * Adapter_FIFO_Get
+ *
+ * Get and remove the oldest entry from the side channel FIFO.
+ */
+static bool
+Adapter_FIFO_Get(AdapterPEC_SideChannelFIFO_t *FIFO,
+                 void **User_p,
+                 DMABuf_Handle_t *SrcPkt_Handle_p,
+                 DMABuf_Handle_t *DstPkt_Handle_p,
+                 DMABuf_Handle_t *Token_Handle_p,
+                 unsigned int *Bypass_WordCount_p)
+{
+    int WriteIndex = FIFO->WriteIndex;
+    int ReadIndex = FIFO->ReadIndex;
+    if (WriteIndex == ReadIndex)
+    {
+        LOG_CRIT("Trying to read from empty FIFO\n");
+        return false;
+    }
+    if (User_p)
+        *User_p = FIFO->Records[ReadIndex].User_p;
+    if (SrcPkt_Handle_p)
+        *SrcPkt_Handle_p = FIFO->Records[ReadIndex].SrcPkt_Handle;
+    *DstPkt_Handle_p = FIFO->Records[ReadIndex].DstPkt_Handle;
+
+    if (Token_Handle_p)
+        *Token_Handle_p = FIFO->Records[ReadIndex].Token_Handle;
+    if (Token_Handle_p != NULL &&
+        !DMABuf_Handle_IsSame(Token_Handle_p, &DMABuf_NULLHandle) &&
+        Bypass_WordCount_p != NULL)
+        *Bypass_WordCount_p = FIFO->Records[ReadIndex].Bypass_WordCount;
+
+    ReadIndex += 1;
+    if (ReadIndex == FIFO->Size)
+        ReadIndex = 0;
+    FIFO->ReadIndex = ReadIndex;
+    return true;
+}
+
+
+/*----------------------------------------------------------------------------
+ * Adapter_FIFO_Withdraw
+ *
+ * Withdraw the most recently added record from the side channel FIFO.
+ */
+static void
+Adapter_FIFO_Withdraw(
+        AdapterPEC_SideChannelFIFO_t *FIFO)
+{
+    int WriteIndex = FIFO->WriteIndex;
+    if (WriteIndex == FIFO->ReadIndex)
+    {
+        LOG_CRIT("Adapter_FIFO_Withdraw: FIFO is empty\n");
+    }
+    if (WriteIndex == 0)
+        WriteIndex = FIFO->Size - 1;
+    else
+        WriteIndex -= 1;
+    FIFO->WriteIndex = WriteIndex;
+}
+
+
+/* Adapter_Packet_Prepare
+ *
+ * In case of bounce buffers, allocate bounce buffers for the packet and
+ * the packet token.
+ * Copy source packet and token into the bounce buffers.
+ * Perform PreDMA on all packet buffers (source, destination and token).
+ */
+static PEC_Status_t
+Adapter_Packet_Prepare(
+        const unsigned int InterfaceId,
+        const PEC_CommandDescriptor_t *Cmd_p)
+{
+    DMAResource_Handle_t SrcPkt_Handle, DstPkt_Handle, Token_Handle;
+#ifdef ADAPTER_PEC_ENABLE_SCATTERGATHER
+    unsigned int ParticleCount;
+    unsigned int i;
+    DMABuf_Handle_t ParticleHandle;
+    DMAResource_Handle_t DMARes_Handle;
+    uint8_t * DummyPtr;
+    unsigned int ParticleSize;
+#endif
+
+    SrcPkt_Handle =
+        Adapter_DMABuf_Handle2DMAResourceHandle(Cmd_p->SrcPkt_Handle);
+    DstPkt_Handle =
+        Adapter_DMABuf_Handle2DMAResourceHandle(Cmd_p->DstPkt_Handle);
+    Token_Handle = Adapter_DMABuf_Handle2DMAResourceHandle(Cmd_p->Token_Handle);
+
+    if (!DMAResource_IsValidHandle(SrcPkt_Handle) &&
+        !DMAResource_IsValidHandle(DstPkt_Handle))
+        return PEC_STATUS_OK; // For record invalidation in the Record Cache
+    else if (!DMAResource_IsValidHandle(SrcPkt_Handle) ||
+             (!DMAResource_IsValidHandle(DstPkt_Handle) &&
+              !PEC_ContinuousScatter[InterfaceId]))
+    {
+        LOG_CRIT("PEC_Packet_Put: invalid source or destination handle\n");
+        return PEC_ERROR_BAD_PARAMETER;
+    }
+
+    // Token handle
+    if (DMAResource_IsValidHandle(Token_Handle))
+    {
+#ifndef ADAPTER_PEC_REMOVE_BOUNCEBUFFERS
+        DMAResource_Record_t * Rec_p =
+            DMAResource_Handle2RecordPtr(Token_Handle);
+        if (Adapter_DMAResource_IsForeignAllocated(Token_Handle))
+        {
+            // Bounce buffer required.
+            DMAResource_AddrPair_t BounceHostAddr;
+            void * HostAddr;
+            int dmares;
+            DMAResource_Properties_t BounceProperties;
+
+            // used as uint32_t array
+            BounceProperties.Alignment  = Adapter_DMAResource_Alignment_Get();
+            BounceProperties.Bank       = ADAPTER_PEC_BANK_TOKEN;
+            BounceProperties.fCached    = false;
+            BounceProperties.Size       = Rec_p->Props.Size;
+
+            HostAddr = Adapter_DMAResource_HostAddr(Token_Handle);
+
+            dmares = DMAResource_Alloc(
+                BounceProperties,
+                &BounceHostAddr,
+                &Rec_p->bounce.Bounce_Handle);
+
+            // bounce buffer handle is stored in the DMA Resource Record
+            // of the original buffer, which links the two
+            // this will be used when freeing the buffer
+            // but also when obtaining the bus address.
+
+            if (dmares != 0)
+            {
+                LOG_CRIT(
+                    "PEC_Packet_Put: "
+                    "Failed to alloc bounce buffer (error %d)\n",
+                dmares);
+                return PEC_ERROR_INTERNAL;   // error!
+            }
+
+            LOG_INFO(
+                "PEC_Packet_Putr: "
+                "Bouncing Token: %p to %p\n",
+                Token_Handle,
+                Rec_p->bounce.Bounce_Handle);
+
+            // copy the data to the bounce buffer
+            memcpy(
+                BounceHostAddr.Address_p,
+                HostAddr,
+                Rec_p->Props.Size);
+
+            Token_Handle = Rec_p->bounce.Bounce_Handle;
+        }
+        else
+        {
+            Rec_p->bounce.Bounce_Handle = NULL;
+        }
+#endif // !ADAPTER_PEC_REMOVE_BOUNCEBUFFERS
+
+#ifdef ADAPTER_PEC_ARMRING_ENABLE_SWAP
+        // Convert token data to packet engine endianness format
+        DMAResource_SwapEndianness_Set(Token_Handle, true);
+
+        DMAResource_Write32Array(
+            Token_Handle,
+            0,
+            Cmd_p->Token_WordCount,
+            Adapter_DMAResource_HostAddr(Token_Handle));
+#endif // ADAPTER_PEC_ARMRING_ENABLE_SWAP
+
+        DMAResource_PreDMA(Token_Handle, 0, 0);
+    }
+
+    // Source packet handle
+#ifdef ADAPTER_PEC_ENABLE_SCATTERGATHER
+    PEC_SGList_GetCapacity(Cmd_p->SrcPkt_Handle, &ParticleCount);
+
+    if (ParticleCount > 0)
+    {
+        for (i=0; i<ParticleCount; i++)
+        {
+            PEC_SGList_Read(Cmd_p->SrcPkt_Handle,
+                            i,
+                            &ParticleHandle,
+                            &ParticleSize,
+                            &DummyPtr);
+            DMARes_Handle =
+                Adapter_DMABuf_Handle2DMAResourceHandle(ParticleHandle);
+            DMAResource_PreDMA(DMARes_Handle, 0, 0);
+        }
+    }
+    else
+#endif
+    { // Not a gather packet,
+#ifndef ADAPTER_PEC_REMOVE_BOUNCEBUFFERS
+        DMAResource_Record_t * Rec_p =
+            DMAResource_Handle2RecordPtr(SrcPkt_Handle);
+        DMAResource_Record_t * Dst_Rec_p =
+            DMAResource_Handle2RecordPtr(DstPkt_Handle);
+        if (Adapter_DMAResource_IsForeignAllocated(SrcPkt_Handle) ||
+            Adapter_DMAResource_IsForeignAllocated(DstPkt_Handle))
+        {
+            // Bounce buffer required. Use a single bounce buffer for
+            // both the source and the destination packet.
+            DMAResource_AddrPair_t BounceHostAddr;
+            void * HostAddr;
+            int dmares;
+            DMAResource_Properties_t BounceProperties;
+
+            // used as uint32_t array
+            BounceProperties.Alignment  = Adapter_DMAResource_Alignment_Get();
+            BounceProperties.Bank       = ADAPTER_PEC_BANK_PACKET;
+            BounceProperties.fCached    = false;
+            BounceProperties.Size       = MAX(Rec_p->Props.Size,
+                                              Dst_Rec_p->Props.Size);
+
+            HostAddr = Adapter_DMAResource_HostAddr(SrcPkt_Handle);
+
+            dmares = DMAResource_Alloc(
+                BounceProperties,
+                &BounceHostAddr,
+                &Rec_p->bounce.Bounce_Handle);
+
+            // bounce buffer handle is stored in the DMA Resource Record
+            // of the original buffer, which links the two
+            // this will be used when freeing the buffer
+            // but also when obtaining the bus address.
+
+            if (dmares != 0)
+            {
+                LOG_CRIT(
+                    "PEC_Packet_Put: "
+                    "Failed to alloc bounce buffer (error %d)\n",
+                dmares);
+                return PEC_ERROR_INTERNAL;   // error!
+            }
+            LOG_INFO(
+                "PEC_Packet_Putr: "
+                "Bouncing Packet: %p to %p\n",
+                SrcPkt_Handle,
+                Rec_p->bounce.Bounce_Handle);
+
+
+            // copy the data to the bounce buffer
+            memcpy(
+                BounceHostAddr.Address_p,
+                HostAddr,
+                Rec_p->Props.Size);
+
+            DstPkt_Handle = SrcPkt_Handle = Rec_p->bounce.Bounce_Handle;
+
+            Dst_Rec_p->bounce.Bounce_Handle = Rec_p->bounce.Bounce_Handle;
+        }
+        else
+        {
+            Rec_p->bounce.Bounce_Handle = NULL;
+            Dst_Rec_p->bounce.Bounce_Handle = NULL;
+        }
+#endif
+        DMAResource_PreDMA(SrcPkt_Handle, 0, 0);
+    }
+    // Destination packet handle, not for continuous scatter.
+    if (PEC_ContinuousScatter[InterfaceId])
+        return PEC_STATUS_OK;
+#ifdef ADAPTER_PEC_ENABLE_SCATTERGATHER
+    PEC_SGList_GetCapacity(Cmd_p->DstPkt_Handle, &ParticleCount);
+
+    if (ParticleCount > 0)
+    {
+        for (i=0; i<ParticleCount; i++)
+        {
+            PEC_SGList_Read(Cmd_p->DstPkt_Handle,
+                            i,
+                            &ParticleHandle,
+                            &ParticleSize,
+                            &DummyPtr);
+            DMARes_Handle =
+                Adapter_DMABuf_Handle2DMAResourceHandle(ParticleHandle);
+            DMAResource_PreDMA(DMARes_Handle, 0, 0);
+        }
+    }
+    else
+#endif
+    if (SrcPkt_Handle != DstPkt_Handle)
+    {
+        // Only if source and destination are distinct.
+        // When bounce buffers were used, these are not distinct.
+        DMAResource_PreDMA(DstPkt_Handle, 0, 0);
+    }
+    return PEC_STATUS_OK;
+}
+
+
+/* Adapter_Packet_Finalize
+ *
+ * Perform PostDMA on all DMA buffers (source, destination and token).
+ * Copy the destination packet from the bounce buffer into the final location.
+ * Deallocate any bounce buffers (packet and token).
+ */
+static PEC_Status_t
+Adapter_Packet_Finalize(
+        DMABuf_Handle_t DMABuf_SrcPkt_Handle,
+        DMABuf_Handle_t DMABuf_DstPkt_Handle,
+        DMABuf_Handle_t DMABuf_Token_Handle)
+{
+    DMAResource_Handle_t SrcPkt_Handle, DstPkt_Handle, Token_Handle;
+
+#ifdef ADAPTER_PEC_ENABLE_SCATTERGATHER
+    unsigned int ParticleCount;
+    unsigned int i;
+    DMABuf_Handle_t ParticleHandle;
+    DMAResource_Handle_t DMARes_Handle;
+    uint8_t * DummyPtr;
+    unsigned int ParticleSize;
+#endif
+
+    SrcPkt_Handle =
+        Adapter_DMABuf_Handle2DMAResourceHandle(DMABuf_SrcPkt_Handle);
+    DstPkt_Handle =
+        Adapter_DMABuf_Handle2DMAResourceHandle(DMABuf_DstPkt_Handle);
+
+    if (!DMAResource_IsValidHandle(SrcPkt_Handle) &&
+        !DMAResource_IsValidHandle(DstPkt_Handle))
+        return PEC_STATUS_OK; // For record invalidation in the Record Cache
+
+    Token_Handle = Adapter_DMABuf_Handle2DMAResourceHandle(DMABuf_Token_Handle);
+
+    // Token Handle.
+    if (DMAResource_IsValidHandle(Token_Handle))
+    {
+#ifndef ADAPTER_PEC_REMOVE_BOUNCEBUFFERS
+        DMAResource_Record_t * Rec_p =
+            DMAResource_Handle2RecordPtr(Token_Handle);
+        if (Rec_p->bounce.Bounce_Handle != NULL)
+        {
+            // Post DMA and release the bounce buffer.
+            DMAResource_PostDMA(Rec_p->bounce.Bounce_Handle, 0, 0);
+            DMAResource_Release(Rec_p->bounce.Bounce_Handle);
+        }
+        else
+#endif
+        {
+            DMAResource_PostDMA(Token_Handle, 0, 0);
+        }
+    }
+    // Destination packet handle
+
+#ifdef ADAPTER_PEC_ENABLE_SCATTERGATHER
+    PEC_SGList_GetCapacity(DMABuf_DstPkt_Handle, &ParticleCount);
+
+    if (ParticleCount > 0)
+    {
+        for (i=0; i<ParticleCount; i++)
+        {
+            PEC_SGList_Read(DMABuf_DstPkt_Handle,
+                            i,
+                            &ParticleHandle,
+                            &ParticleSize,
+                            &DummyPtr);
+            DMARes_Handle =
+                Adapter_DMABuf_Handle2DMAResourceHandle(ParticleHandle);
+            DMAResource_PostDMA(DMARes_Handle, 0, 0);
+        }
+    }
+    else
+#endif
+    {
+#ifndef ADAPTER_PEC_REMOVE_BOUNCEBUFFERS
+        DMAResource_Record_t * Rec_p =
+            DMAResource_Handle2RecordPtr(DstPkt_Handle);
+        void * HostAddr = Adapter_DMAResource_HostAddr(DstPkt_Handle);
+        if (Rec_p->bounce.Bounce_Handle != NULL)
+        {
+            void * BounceHostAddr =
+                Adapter_DMAResource_HostAddr(Rec_p->bounce.Bounce_Handle);
+            // Post DMA, copy and release the bounce buffer.
+            DMAResource_PostDMA(Rec_p->bounce.Bounce_Handle, 0, 0);
+
+            memcpy( HostAddr, BounceHostAddr, Rec_p->Props.Size);
+
+            DMAResource_Release(Rec_p->bounce.Bounce_Handle);
+            SrcPkt_Handle = DstPkt_Handle;
+        }
+        else
+#endif
+        {
+            DMAResource_PostDMA(DstPkt_Handle, 0, 0);
+        }
+
+    }
+    // Source packet handle
+#ifdef ADAPTER_PEC_ENABLE_SCATTERGATHER
+    PEC_SGList_GetCapacity(DMABuf_SrcPkt_Handle, &ParticleCount);
+
+    if (ParticleCount > 0)
+    {
+        for (i=0; i<ParticleCount; i++)
+        {
+            PEC_SGList_Read(DMABuf_SrcPkt_Handle,
+                            i,
+                            &ParticleHandle,
+                            &ParticleSize,
+                            &DummyPtr);
+            DMARes_Handle =
+                Adapter_DMABuf_Handle2DMAResourceHandle(ParticleHandle);
+            DMAResource_PostDMA(DMARes_Handle, 0, 0);
+        }
+    }
+    else
+#endif
+    if (SrcPkt_Handle != DstPkt_Handle)
+    {
+        // Only if source and destination are distinct.
+        // When bounce buffers were used, these are not distinct.
+        DMAResource_PostDMA(SrcPkt_Handle, 0, 0);
+    }
+
+    return PEC_STATUS_OK;
+}
+
+
+#ifdef ADAPTER_PEC_RPM_EIP202_DEVICE0_ID
+/*----------------------------------------------------------------------------
+ * AdapterPEC_Resume
+ */
+static int
+AdapterPEC_Resume(void * p)
+{
+    int InterfaceId = *(int *)p;
+
+    if (InterfaceId < 0 || InterfaceId < ADAPTER_PEC_RPM_EIP202_DEVICE0_ID)
+        return -3; // error
+
+    InterfaceId -= ADAPTER_PEC_RPM_EIP202_DEVICE0_ID;
+
+    return Adapter_PECDev_Resume(InterfaceId);
+}
+
+
+/*----------------------------------------------------------------------------
+ * AdapterPEC_Suspend
+ */
+static int
+AdapterPEC_Suspend(void * p)
+{
+    int InterfaceId = *(int *)p;
+
+    if (InterfaceId < 0 || InterfaceId < ADAPTER_PEC_RPM_EIP202_DEVICE0_ID)
+        return -3; // error
+
+    InterfaceId -= ADAPTER_PEC_RPM_EIP202_DEVICE0_ID;
+
+    return Adapter_PECDev_Suspend(InterfaceId);
+}
+#endif
+
+
+/*----------------------------------------------------------------------------
+ * PEC_Capabilities_Get
+ */
+PEC_Status_t
+PEC_Capabilities_Get(
+        PEC_Capabilities_t * const Capabilities_p)
+{
+    return Adapter_PECDev_Capabilities_Get(Capabilities_p);
+}
+
+
+/*----------------------------------------------------------------------------
+ * PEC_Init
+ */
+PEC_Status_t
+PEC_Init(
+        const unsigned int InterfaceId,
+        const PEC_InitBlock_t * const InitBlock_p)
+{
+    LOG_INFO("\n\t PEC_Init \n");
+
+    if (!InitBlock_p)
+        return PEC_ERROR_BAD_PARAMETER;
+
+    if (InterfaceId >= ADAPTER_PEC_DEVICE_COUNT)
+        return PEC_ERROR_BAD_PARAMETER;
+
+    Adapter_Lock_CS_Set(&AdapterPEC_InitCS, &AdapterPEC_InitLock);
+
+    if (!Adapter_Lock_CS_Enter(&AdapterPEC_InitCS))
+        return PEC_STATUS_BUSY;
+
+    // ensure we init only once
+    if (PEC_IsInitialized[InterfaceId])
+    {
+        Adapter_Lock_CS_Leave(&AdapterPEC_InitCS);
+        return PEC_STATUS_OK;
+    }
+    PEC_ContinuousScatter[InterfaceId] = InitBlock_p->fContinuousScatter;
+
+    // Allocate the Put lock
+    AdapterPEC_PutLock[InterfaceId] = Adapter_Lock_Alloc();
+    if (AdapterPEC_PutLock[InterfaceId] == NULL)
+    {
+        LOG_CRIT("PEC_Init: PutLock allocation failed\n");
+        Adapter_Lock_CS_Leave(&AdapterPEC_InitCS);
+        return PEC_ERROR_INTERNAL;
+    }
+    Adapter_Lock_CS_Set(&AdapterPEC_PutCS[InterfaceId],
+                         AdapterPEC_PutLock[InterfaceId]);
+
+    // Allocate the Get lock
+    AdapterPEC_GetLock[InterfaceId] = Adapter_Lock_Alloc();
+    if (AdapterPEC_GetLock[InterfaceId] == NULL)
+    {
+        LOG_CRIT("PEC_Init: GetLock allocation failed\n");
+        Adapter_Lock_Free(AdapterPEC_PutLock[InterfaceId]);
+        Adapter_Lock_CS_Leave(&AdapterPEC_InitCS);
+        return PEC_ERROR_INTERNAL;
+    }
+    Adapter_Lock_CS_Set(&AdapterPEC_GetCS[InterfaceId],
+                         AdapterPEC_GetLock[InterfaceId]);
+
+    ZEROINIT(PEC_Notify[InterfaceId]);
+
+    if (RPM_DEVICE_INIT_START_MACRO(ADAPTER_PEC_RPM_EIP202_DEVICE0_ID + InterfaceId,
+                                    AdapterPEC_Suspend,
+                                    AdapterPEC_Resume) != RPM_SUCCESS)
+        return PEC_ERROR_INTERNAL;
+
+    // Init the device
+    if (Adapter_PECDev_Init(InterfaceId, InitBlock_p) != PEC_STATUS_OK)
+    {
+        (void)RPM_DEVICE_INIT_STOP_MACRO(ADAPTER_PEC_RPM_EIP202_DEVICE0_ID + InterfaceId);
+        LOG_CRIT("PEC_Init: Adapter_PECDev_Init failed\n");
+        Adapter_Lock_Free(AdapterPEC_PutLock[InterfaceId]);
+        Adapter_Lock_Free(AdapterPEC_GetLock[InterfaceId]);
+        Adapter_Lock_CS_Leave(&AdapterPEC_InitCS);
+        return PEC_ERROR_INTERNAL;
+    }
+
+    (void)RPM_DEVICE_INIT_STOP_MACRO(ADAPTER_PEC_RPM_EIP202_DEVICE0_ID + InterfaceId);
+
+    Adapter_SideChannelFIFO[InterfaceId].Size =
+        sizeof(Adapter_SideChannelFIFO[InterfaceId].Records) /
+        sizeof(Adapter_SideChannelFIFO[InterfaceId].Records[0]);
+    Adapter_SideChannelFIFO[InterfaceId].WriteIndex = 0;
+    Adapter_SideChannelFIFO[InterfaceId].ReadIndex = 0;
+
+#ifdef ADAPTER_PEC_INTERRUPTS_ENABLE
+    // enable the descriptor done interrupt
+    LOG_INFO("PEC_Init: Registering interrupt handler\n");
+
+    Adapter_PECDev_SetResultHandler(
+            InterfaceId,
+            AdapterPEC_InterruptHandlerResultNotify);
+
+    Adapter_PECDev_SetCommandHandler(
+            InterfaceId,
+            AdapterPEC_InterruptHandlerCommandNotify);
+#endif /* ADAPTER_PEC_INTERRUPTS_ENABLE */
+
+    PEC_IsInitialized[InterfaceId] = true;
+
+    LOG_INFO("\n\t PEC_Init done \n");
+
+    Adapter_Lock_CS_Leave(&AdapterPEC_InitCS);
+
+    return PEC_STATUS_OK;
+}
+
+
+/*----------------------------------------------------------------------------
+ * PEC_UnInit
+ */
+PEC_Status_t
+PEC_UnInit(
+        const unsigned int InterfaceId)
+{
+    LOG_INFO("\n\t PEC_UnInit \n");
+
+    if (InterfaceId >= ADAPTER_PEC_DEVICE_COUNT)
+        return PEC_ERROR_BAD_PARAMETER;
+
+    Adapter_Lock_CS_Set(&AdapterPEC_InitCS, &AdapterPEC_InitLock);
+
+    if (!Adapter_Lock_CS_Enter(&AdapterPEC_InitCS))
+        return PEC_STATUS_BUSY;
+
+    // ensure we uninit only once
+    if (!PEC_IsInitialized[InterfaceId])
+    {
+        Adapter_Lock_CS_Leave(&AdapterPEC_InitCS);
+        return PEC_STATUS_OK;
+    }
+
+    if (!Adapter_Lock_CS_Enter(&AdapterPEC_PutCS[InterfaceId]))
+    {
+        Adapter_Lock_CS_Leave(&AdapterPEC_InitCS);
+        return PEC_STATUS_BUSY;
+    }
+
+    if (!Adapter_Lock_CS_Enter(&AdapterPEC_GetCS[InterfaceId]))
+    {
+        Adapter_Lock_CS_Leave(&AdapterPEC_PutCS[InterfaceId]);
+        Adapter_Lock_CS_Leave(&AdapterPEC_InitCS);
+        return PEC_STATUS_BUSY;
+    }
+
+    if (RPM_DEVICE_UNINIT_START_MACRO(ADAPTER_PEC_RPM_EIP202_DEVICE0_ID + InterfaceId,
+                                true) != RPM_SUCCESS)
+    {
+        Adapter_Lock_CS_Leave(&AdapterPEC_PutCS[InterfaceId]);
+        Adapter_Lock_CS_Leave(&AdapterPEC_InitCS);
+        return PEC_ERROR_INTERNAL;
+    }
+
+#ifdef ADAPTER_PEC_INTERRUPTS_ENABLE
+    Adapter_PECDev_Disable_ResultIRQ(InterfaceId);
+    Adapter_PECDev_Disable_CommandIRQ(InterfaceId);
+#endif
+
+    Adapter_PECDev_UnInit(InterfaceId);
+
+    PEC_IsInitialized[InterfaceId] = false;
+
+    (void)RPM_DEVICE_UNINIT_STOP_MACRO(ADAPTER_PEC_RPM_EIP202_DEVICE0_ID + InterfaceId);
+
+    Adapter_Lock_CS_Leave(&AdapterPEC_GetCS[InterfaceId]);
+    Adapter_Lock_CS_Leave(&AdapterPEC_PutCS[InterfaceId]);
+
+    // Free Get lock
+    Adapter_Lock_Free(Adapter_Lock_CS_Get(&AdapterPEC_GetCS[InterfaceId]));
+    Adapter_Lock_CS_Set(&AdapterPEC_GetCS[InterfaceId], Adapter_Lock_NULL);
+
+    // Free Put lock
+    Adapter_Lock_Free(Adapter_Lock_CS_Get(&AdapterPEC_PutCS[InterfaceId]));
+    Adapter_Lock_CS_Set(&AdapterPEC_PutCS[InterfaceId], Adapter_Lock_NULL);
+
+    LOG_INFO("\n\t PEC_UnInit done \n");
+
+    Adapter_Lock_CS_Leave(&AdapterPEC_InitCS);
+
+    return PEC_STATUS_OK;
+}
+
+
+/*----------------------------------------------------------------------------
+ * PEC_SA_Register
+ */
+PEC_Status_t
+PEC_SA_Register(
+        const unsigned int InterfaceId,
+        DMABuf_Handle_t SA_Handle1,
+        DMABuf_Handle_t SA_Handle2,
+        DMABuf_Handle_t SA_Handle3)
+{
+    DMAResource_Handle_t DMAHandle1, DMAHandle2, DMAHandle3;
+    PEC_Status_t res;
+
+    LOG_INFO("\n\t PEC_SA_Register \n");
+
+    IDENTIFIER_NOT_USED(InterfaceId);
+
+    DMAHandle1 = Adapter_DMABuf_Handle2DMAResourceHandle(SA_Handle1);
+    DMAHandle2 = Adapter_DMABuf_Handle2DMAResourceHandle(SA_Handle2);
+    DMAHandle3 = Adapter_DMABuf_Handle2DMAResourceHandle(SA_Handle3);
+
+    // The SA, State Record and ARC4 State Record are arrays of uint32_t.
+    // The caller provides them in host-native format.
+    // This function converts them to device-native format
+    // using DMAResource and in-place operations.
+
+    // Endianness conversion for the 1st SA memory block (Main SA Record)
+#ifdef ADAPTER_PEC_ARMRING_ENABLE_SWAP
+    {
+        DMAResource_Record_t * const Rec_p =
+            DMAResource_Handle2RecordPtr(DMAHandle1);
+
+        if (Rec_p == NULL)
+            return PEC_ERROR_INTERNAL;
+
+        DMAResource_SwapEndianness_Set(DMAHandle1, true);
+
+        DMAResource_Write32Array(
+            DMAHandle1,
+            0,
+            Rec_p->Props.Size / 4,
+            Adapter_DMAResource_HostAddr(DMAHandle1));
+    }
+
+    // Endianness conversion for the 2nd SA memory block (State Record)
+    if (DMAHandle2 != NULL)
+    {
+        DMAResource_Record_t * const Rec_p =
+            DMAResource_Handle2RecordPtr(DMAHandle2);
+
+        if (Rec_p == NULL)
+            return PEC_ERROR_INTERNAL;
+
+        // The 2nd SA memory block can never be a subset of
+        // the 1st SA memory block so it is safe to perform
+        // the endianness conversion
+        DMAResource_SwapEndianness_Set(DMAHandle2, true);
+
+        DMAResource_Write32Array(
+            DMAHandle2,
+            0,
+            Rec_p->Props.Size / 4,
+            Adapter_DMAResource_HostAddr(DMAHandle2));
+    }
+
+    // Endianness conversion for the 3d SA memory block (ARC4 State Record)
+    if (DMAHandle3 != NULL)
+    {
+        DMAResource_Record_t * const Rec_p =
+            DMAResource_Handle2RecordPtr(DMAHandle3);
+
+        if (Rec_p == NULL)
+            return PEC_ERROR_INTERNAL;
+
+        // The 3d SA memory block can never be a subset of
+        // the 2nd SA memory block.
+
+        // Check if the 3d SA memory block is not a subset of the 1st one
+        if (!Adapter_DMAResource_IsSubRangeOf(DMAHandle3, DMAHandle1))
+        {
+            // The 3d SA memory block is a separate buffer and does not
+            // overlap with the 1st SA memory block,
+            // so the endianness conversion must be done
+            DMAResource_SwapEndianness_Set(DMAHandle3, true);
+
+            DMAResource_Write32Array(
+                    DMAHandle3,
+                    0,
+                    Rec_p->Props.Size / 4,
+                    Adapter_DMAResource_HostAddr(DMAHandle3));
+        }
+    }
+#endif // ADAPTER_PEC_ARMRING_ENABLE_SWAP
+
+#ifndef ADAPTER_PEC_REMOVE_BOUNCEBUFFERS
+    // Bounce the SA buffers if required
+    // Check if the 3d SA memory block is not a subset of the 1st one
+    if (DMAHandle3 != NULL &&
+        !Adapter_DMAResource_IsSubRangeOf(DMAHandle3, DMAHandle1))
+    {
+        if (!Adapter_PECRegisterSA_BounceIfRequired(&DMAHandle3))
+            return PEC_ERROR_INTERNAL;
+    }
+
+    if (!Adapter_PECRegisterSA_BounceIfRequired(&DMAHandle1))
+        return PEC_ERROR_INTERNAL;
+
+    if (!Adapter_PECRegisterSA_BounceIfRequired(&DMAHandle2))
+        return PEC_ERROR_INTERNAL;
+#endif
+
+    res = Adapter_PECDev_SA_Prepare(SA_Handle1, SA_Handle2, SA_Handle3);
+    if (res != PEC_STATUS_OK)
+    {
+        LOG_WARN(
+            "PEC_SA_Register: "
+            "Adapter_PECDev_PrepareSA returned %d\n",
+            res);
+        return PEC_ERROR_INTERNAL;
+    }
+
+    // now use DMAResource to ensure the engine
+    // can read the memory blocks using DMA
+    DMAResource_PreDMA(DMAHandle1, 0, 0);     // 0,0 = "entire buffer"
+
+    if (DMAHandle2 != NULL)
+        DMAResource_PreDMA(DMAHandle2, 0, 0);
+
+    // Check if the 3d SA memory block is not a subset of the 1st one
+    if (DMAHandle3 != NULL &&
+        !Adapter_DMAResource_IsSubRangeOf(DMAHandle3, DMAHandle1))
+        DMAResource_PreDMA(DMAHandle3, 0, 0);
+
+    LOG_INFO("\n\t PEC_SA_Register done \n");
+
+    return PEC_STATUS_OK;
+}
+
+
+/*----------------------------------------------------------------------------
+ * PEC_SA_UnRegister
+ */
+PEC_Status_t
+PEC_SA_UnRegister(
+        const unsigned int InterfaceId,
+        DMABuf_Handle_t SA_Handle1,
+        DMABuf_Handle_t SA_Handle2,
+        DMABuf_Handle_t SA_Handle3)
+{
+    DMAResource_Handle_t SA_Handle[3];
+    PEC_Status_t res;
+    int i, MaxHandles;
+
+    LOG_INFO("\n\t PEC_SA_UnRegister \n");
+
+    IDENTIFIER_NOT_USED(InterfaceId);
+
+    res = Adapter_PECDev_SA_Remove(SA_Handle1, SA_Handle2, SA_Handle3);
+    if (res != PEC_STATUS_OK)
+    {
+        LOG_CRIT(
+            "PEC_SA_UnRegister: "
+            "Adapter_PECDev_SA_Remove returned %d\n",
+            res);
+        return PEC_ERROR_INTERNAL;
+    }
+
+    SA_Handle[0] = Adapter_DMABuf_Handle2DMAResourceHandle(SA_Handle1);
+    SA_Handle[1] = Adapter_DMABuf_Handle2DMAResourceHandle(SA_Handle2);
+    SA_Handle[2] = Adapter_DMABuf_Handle2DMAResourceHandle(SA_Handle3);
+
+    // Check if the 3d SA memory block is not a subset of the 1st one
+    if (SA_Handle[0] != NULL &&
+        SA_Handle[2] != NULL &&
+        Adapter_DMAResource_IsSubRangeOf(SA_Handle[2], SA_Handle[0]))
+        MaxHandles = 2;
+    else
+        MaxHandles = 3;
+
+    for (i = 0; i < MaxHandles; i++)
+    {
+        if (DMAResource_IsValidHandle(SA_Handle[i]))
+        {
+            DMAResource_Handle_t DMAHandle = SA_Handle[i];
+            void *HostAddr;
+            DMAResource_Record_t * Rec_p =
+                DMAResource_Handle2RecordPtr(DMAHandle);
+
+            // Check if a bounce buffer is in use
+#ifndef ADAPTER_PEC_REMOVE_BOUNCEBUFFERS
+            void * OrigHostAddr;
+            DMAResource_Record_t * HostRec_p = Rec_p;
+
+            OrigHostAddr = Adapter_DMAResource_HostAddr(DMAHandle);
+
+            if (Adapter_DMAResource_IsForeignAllocated(SA_Handle[i]))
+            {
+                // Get bounce buffer handle and its record
+                DMAHandle = HostRec_p->bounce.Bounce_Handle;
+                Rec_p = DMAResource_Handle2RecordPtr(DMAHandle);
+            }
+#endif /* ADAPTER_PEC_REMOVE_BOUNCEBUFFERS */
+
+            HostAddr = Adapter_DMAResource_HostAddr(DMAHandle);
+            // ensure we look at valid engine-written data
+            // 0,0 = "entire buffer"
+            DMAResource_PostDMA(DMAHandle, 0, 0);
+
+            // convert to host format
+            if (Rec_p != NULL)
+                DMAResource_Read32Array(
+                    DMAHandle,
+                    0,
+                    Rec_p->Props.Size / 4,
+                    HostAddr);
+
+            // copy from bounce buffer to original buffer
+#ifndef ADAPTER_PEC_REMOVE_BOUNCEBUFFERS
+            if (Adapter_DMAResource_IsForeignAllocated(SA_Handle[i]) &&
+                HostRec_p != NULL)
+            {
+                // copy the data from bounce to original buffer
+                memcpy(
+                    OrigHostAddr,
+                    HostAddr,
+                    HostRec_p->Props.Size);
+
+                // free the bounce handle
+                DMAResource_Release(HostRec_p->bounce.Bounce_Handle);
+                HostRec_p->bounce.Bounce_Handle = NULL;
+            }
+#endif /* ADAPTER_PEC_REMOVE_BOUNCEBUFFERS */
+        } // if handle valid
+    } // for
+
+    LOG_INFO("\n\t PEC_SA_UnRegister done\n");
+
+    return PEC_STATUS_OK;
+}
+
+
+/*----------------------------------------------------------------------------
+ * PEC_Packet_Put
+ */
+PEC_Status_t
+PEC_Packet_Put(
+        const unsigned int InterfaceId,
+        const PEC_CommandDescriptor_t * Commands_p,
+        const unsigned int CommandsCount,
+        unsigned int * const PutCount_p)
+{
+    unsigned int CmdLp;
+    unsigned int PktCnt;
+    unsigned int CmdDescriptorCount;
+    PEC_Status_t res = 0, res2, PEC_Rc = PEC_STATUS_OK;
+    unsigned int FreeSlots;
+
+    LOG_INFO("\n\t PEC_Packet_Put \n");
+
+    if (InterfaceId >= ADAPTER_PEC_DEVICE_COUNT)
+        return PEC_ERROR_BAD_PARAMETER;
+
+#ifdef ADAPTER_PEC_STRICT_ARGS
+    if (Commands_p == NULL ||
+        CommandsCount == 0 ||
+        PutCount_p == NULL)
+    {
+        return PEC_ERROR_BAD_PARAMETER;
+    }
+#endif
+
+    // initialize the output parameters
+    *PutCount_p = 0;
+
+#ifdef ADAPTER_PEC_STRICT_ARGS
+    // validate the descriptors
+    // (error out before bounce buffer allocation)
+    for (CmdLp = 0; CmdLp < CommandsCount; CmdLp++)
+        if (Commands_p[CmdLp].Bypass_WordCount > 255)
+            return PEC_ERROR_BAD_PARAMETER;
+#endif /* ADAPTER_PEC_STRICT_ARGS */
+
+    if (!Adapter_Lock_CS_Enter(&AdapterPEC_PutCS[InterfaceId]))
+        return PEC_STATUS_BUSY;
+
+    if (!PEC_IsInitialized[InterfaceId])
+    {
+        Adapter_Lock_CS_Leave(&AdapterPEC_PutCS[InterfaceId]);
+        return PEC_ERROR_BAD_USE_ORDER;
+    }
+
+    CmdDescriptorCount = MIN(ADAPTER_PEC_MAX_LOGICDESCR, CommandsCount);
+    FreeSlots = 0;
+    CmdLp = 0;
+    while (CmdLp < CmdDescriptorCount)
+    {
+        unsigned int j;
+        unsigned int count;
+        unsigned int NonSGPackets;
+
+#ifndef ADAPTER_PEC_ENABLE_SCATTERGATHER
+        NonSGPackets = CmdDescriptorCount - CmdLp;
+        // All remaining packets are non-SG.
+#else
+        unsigned int GatherParticles;
+        unsigned int ScatterParticles;
+        unsigned int i;
+
+        for (i = CmdLp; i < CmdDescriptorCount; i++)
+        {
+            PEC_SGList_GetCapacity(Commands_p[i].SrcPkt_Handle,
+                                   &GatherParticles);
+            if (PEC_ContinuousScatter[InterfaceId])
+                ScatterParticles = 0;
+            else
+                PEC_SGList_GetCapacity(Commands_p[i].DstPkt_Handle,
+                                       &ScatterParticles);
+            if ( GatherParticles > 0 || ScatterParticles > 0)
+                break;
+        }
+        NonSGPackets = i - CmdLp;
+
+        if (NonSGPackets == 0)
+        {
+            bool fSuccess;
+
+            if (RPM_DEVICE_IO_START_MACRO(ADAPTER_PEC_RPM_EIP202_DEVICE0_ID +
+                                                                   InterfaceId,
+                                          RPM_FLAG_SYNC) != RPM_SUCCESS)
+            {
+                PEC_Rc = PEC_ERROR_INTERNAL;
+                break;
+            }
+
+            // First packet found is scatter gather.
+            fSuccess = Adapter_PECDev_TestSG(InterfaceId,
+                                             GatherParticles,
+                                             ScatterParticles);
+
+            (void)RPM_DEVICE_IO_STOP_MACRO(ADAPTER_PEC_RPM_EIP202_DEVICE0_ID +
+                                                           InterfaceId,
+                                           RPM_FLAG_ASYNC);
+
+            if (!fSuccess)
+            {
+                PEC_Rc = PEC_ERROR_INTERNAL;
+                break;
+            }
+
+            // Process a single SG packet in this iteration.
+            FreeSlots = 1;
+        }
+        else
+#endif
+        if (FreeSlots == 0)
+        {
+            if (RPM_DEVICE_IO_START_MACRO(ADAPTER_PEC_RPM_EIP202_DEVICE0_ID +
+                                                                   InterfaceId,
+                                          RPM_FLAG_SYNC) != RPM_SUCCESS)
+            {
+                PEC_Rc = PEC_ERROR_INTERNAL;
+                break;
+            }
+
+            // Allow all non-SG packets to be processed in this iteration,
+            // but limited by the number of free slots in the ring(s).
+            FreeSlots = Adapter_PECDev_GetFreeSpace(InterfaceId);
+
+            (void)RPM_DEVICE_IO_STOP_MACRO(ADAPTER_PEC_RPM_EIP202_DEVICE0_ID +
+                                                           InterfaceId,
+                                           RPM_FLAG_ASYNC);
+
+            if (FreeSlots > NonSGPackets)
+                FreeSlots = NonSGPackets;
+
+            if (FreeSlots == 0)
+                break;
+        }
+
+        for (PktCnt=0; PktCnt<FreeSlots; PktCnt++)
+        {
+            res = Adapter_Packet_Prepare(InterfaceId,
+                                         Commands_p + CmdLp + PktCnt);
+            if (res != PEC_STATUS_OK)
+            {
+                LOG_CRIT("%s: Adapter_Packet_Prepare error %d\n", __func__, res);
+                PEC_Rc = res;
+                break;
+            }
+
+            if (!PEC_ContinuousScatter[InterfaceId])
+            {
+                Adapter_FIFO_Put(&(Adapter_SideChannelFIFO[InterfaceId]),
+                                 Commands_p[CmdLp+PktCnt].User_p,
+                                 Commands_p[CmdLp+PktCnt].SrcPkt_Handle,
+                                 Commands_p[CmdLp+PktCnt].DstPkt_Handle,
+                                 Commands_p[CmdLp+PktCnt].Token_Handle,
+                                 Commands_p[CmdLp+PktCnt].Bypass_WordCount);
+            }
+        }
+
+        // RPM_Device_IO_Start() must be called for each successfully submitted
+        // packet
+        for (j = 0; j < PktCnt; j++)
+        {
+            // Skipped error checking to reduce code complexity
+            (void)RPM_DEVICE_IO_START_MACRO(ADAPTER_PEC_RPM_EIP202_DEVICE0_ID +
+                                                                InterfaceId,
+                                            RPM_FLAG_SYNC);
+        }
+
+        res2 = Adapter_PECDev_Packet_Put(InterfaceId,
+                                         Commands_p + CmdLp,
+                                         PktCnt,
+                                         &count);
+        if (res2 != PEC_STATUS_OK)
+        {
+            LOG_CRIT("%s: Adapter_PECDev_Packet_Put error %d\n", __func__, res2);
+            PEC_Rc = res2;
+        }
+
+        FreeSlots -= count;
+        *PutCount_p += count;
+
+        if (count <  PktCnt)
+        {
+            LOG_WARN("PEC_Packet_Put: withdrawing %d prepared packets\n",
+                     PktCnt - count);
+
+            for (j = count; j < PktCnt; j++)
+            {
+                if (!PEC_ContinuousScatter[InterfaceId])
+                {
+                    Adapter_FIFO_Withdraw(&(Adapter_SideChannelFIFO[InterfaceId]));
+                    Adapter_Packet_Finalize(Commands_p[CmdLp + j].SrcPkt_Handle,
+                                            Commands_p[CmdLp + j].DstPkt_Handle,
+                                            Commands_p[CmdLp + j].Token_Handle);
+                }
+
+                // RPM_DEVICE_IO_STOP_MACRO() must be called here for packets
+                // which could not be successfully submitted,
+                // for example because device queue was full
+                (void)RPM_DEVICE_IO_STOP_MACRO(ADAPTER_PEC_RPM_EIP202_DEVICE0_ID +
+                                                               InterfaceId,
+                                               RPM_FLAG_ASYNC);
+            }
+            break;
+        }
+
+        CmdLp += count;
+
+        if (res != PEC_STATUS_OK || res2 != PEC_STATUS_OK)
+        {
+            PEC_Rc = PEC_ERROR_INTERNAL;
+            break;
+        }
+    } // while
+
+    LOG_INFO("\n\t PEC_Packet_Put done \n");
+
+    Adapter_Lock_CS_Leave(&AdapterPEC_PutCS[InterfaceId]);
+
+    return PEC_Rc;
+}
+
+
+/*----------------------------------------------------------------------------
+ * PEC_Packet_Get
+ */
+PEC_Status_t
+PEC_Packet_Get(
+        const unsigned int InterfaceId,
+        PEC_ResultDescriptor_t * Results_p,
+        const unsigned int ResultsLimit,
+        unsigned int * const GetCount_p)
+{
+    LOG_INFO("\n\t PEC_Packet_Get \n");
+
+    if (InterfaceId >= ADAPTER_PEC_DEVICE_COUNT)
+        return PEC_ERROR_BAD_PARAMETER;
+
+#ifdef ADAPTER_PEC_STRICT_ARGS
+    if (Results_p == NULL ||
+        GetCount_p == NULL ||
+        ResultsLimit == 0)
+    {
+        return PEC_ERROR_BAD_PARAMETER;
+    }
+#endif
+
+    // initialize the output parameter
+    *GetCount_p = 0;
+
+    if (!Adapter_Lock_CS_Enter(&AdapterPEC_GetCS[InterfaceId]))
+        return PEC_STATUS_BUSY;
+
+    if (!PEC_IsInitialized[InterfaceId])
+    {
+        Adapter_Lock_CS_Leave(&AdapterPEC_GetCS[InterfaceId]);
+        return PEC_ERROR_BAD_USE_ORDER;
+    }
+
+    // read descriptors from PEC device
+    {
+        PEC_Status_t res;
+        unsigned int ResLp;
+        unsigned int Limit = MIN(ResultsLimit, ADAPTER_PEC_MAX_LOGICDESCR);
+        unsigned int count;
+        DMABuf_Handle_t Token_Handle = DMABuf_NULLHandle;
+
+        res=Adapter_PECDev_Packet_Get(InterfaceId,
+                                      Results_p,
+                                      Limit,
+                                      &count);
+        if (res != PEC_STATUS_OK)
+        {
+            LOG_CRIT("PEC_Packet_Get() returned error: %d\n", res);
+            Adapter_Lock_CS_Leave(&AdapterPEC_GetCS[InterfaceId]);
+            return res;
+        }
+
+        for (ResLp = 0; ResLp < count; ResLp++)
+        {
+            // To help CommandNotifyCB
+            if (ResLp == count-1)
+                Adapter_MakeCommandNotify_CallBack(InterfaceId);
+
+            (void)RPM_DEVICE_IO_STOP_MACRO(ADAPTER_PEC_RPM_EIP202_DEVICE0_ID +
+                                                        InterfaceId,
+                                           RPM_FLAG_ASYNC);
+            if (PEC_ContinuousScatter[InterfaceId])
+            {
+                unsigned int i;
+                DMABuf_Handle_t DestHandle = DMABuf_NULLHandle;
+                DMAResource_Handle_t DMARes_Handle;
+                if (Results_p[ResLp].NumParticles == 1)
+                {
+                    /* No real scatter, can fixup using single destination
+                       handle */
+                    Adapter_FIFO_Get(&Adapter_SideChannelFIFO[InterfaceId],
+                                     NULL,
+                                     NULL,
+                                     &DestHandle,
+                                     NULL,
+                                     NULL);
+                    DMARes_Handle =
+                        Adapter_DMABuf_Handle2DMAResourceHandle(DestHandle);
+                    DMAResource_PostDMA(DMARes_Handle, 0, 0);
+#ifdef ADAPTER_AUTO_FIXUP
+                    IOToken_Fixup(Results_p[ResLp].OutputToken_p,
+                                  DestHandle);
+#endif
+                    Results_p[ResLp].User_p = NULL;
+                    Results_p[ResLp].SrcPkt_Handle = DMABuf_NULLHandle;
+                    Results_p[ResLp].DstPkt_Handle = DestHandle;
+                    Results_p[ResLp].Bypass_WordCount = 0;
+                    if (!DMABuf_Handle_IsSame(&Results_p[ResLp].DstPkt_Handle,
+                                              &DMABuf_NULLHandle))
+                    {
+                        Results_p[ResLp].DstPkt_p =
+                            Adapter_DMAResource_HostAddr(
+                                Adapter_DMABuf_Handle2DMAResourceHandle(
+                                    Results_p[ResLp].DstPkt_Handle));
+                    }
+                    else
+                    {
+                        Results_p[ResLp].DstPkt_p = NULL;
+                    }
+                }
+                else
+                {
+#if defined(ADAPTER_PEC_ENABLE_SCATTERGATHER) && defined(ADAPTER_AUTO_FIXUP)
+                    DMAResource_Record_t * Rec_p;
+                    PEC_Status_t PEC_Rc;
+                    DMABuf_Handle_t Fixup_SGList; /* scatter list for Fixup in continuous scatter mode */
+                    PEC_Rc = PEC_SGList_Create(Results_p[ResLp].NumParticles,
+                                               &Fixup_SGList);
+#endif
+                    for (i = 0; i < Results_p[ResLp].NumParticles; i++)
+                    {
+                        Adapter_FIFO_Get(&Adapter_SideChannelFIFO[InterfaceId],
+                                         NULL,
+                                         NULL,
+                                         &DestHandle,
+                                         NULL,
+                                     NULL);
+                        DMARes_Handle =
+                            Adapter_DMABuf_Handle2DMAResourceHandle(DestHandle);
+                        DMAResource_PostDMA(DMARes_Handle, 0, 0);
+#if defined(ADAPTER_PEC_ENABLE_SCATTERGATHER) && defined(ADAPTER_AUTO_FIXUP)
+                        if (PEC_Rc == PEC_STATUS_OK)
+                        {
+                            Rec_p = DMAResource_Handle2RecordPtr(DMARes_Handle);
+
+                            PEC_SGList_Write(Fixup_SGList,
+                                             i,
+                                             DestHandle,
+                                             Rec_p->Props.Size);
+                        }
+#endif
+                    }
+#if defined(ADAPTER_PEC_ENABLE_SCATTERGATHER) && defined(ADAPTER_AUTO_FIXUP)
+                    if (PEC_Rc == PEC_STATUS_OK)
+                    {
+                        IOToken_Fixup(Results_p[ResLp].OutputToken_p,
+                              Fixup_SGList);
+                        PEC_SGList_Destroy(Fixup_SGList);
+                    }
+
+#endif
+                    Results_p[ResLp].User_p = NULL;
+                    Results_p[ResLp].SrcPkt_Handle = DMABuf_NULLHandle;
+                    Results_p[ResLp].DstPkt_Handle = DMABuf_NULLHandle;
+                    Results_p[ResLp].Bypass_WordCount = 0;
+                }
+            }
+            else
+            {
+                Adapter_FIFO_Get(&(Adapter_SideChannelFIFO[InterfaceId]),
+                                 &(Results_p[ResLp].User_p),
+                                 &(Results_p[ResLp].SrcPkt_Handle),
+                                 &(Results_p[ResLp].DstPkt_Handle),
+                                 &Token_Handle,
+                                 &(Results_p[ResLp].Bypass_WordCount));
+
+                Adapter_Packet_Finalize(Results_p[ResLp].SrcPkt_Handle,
+                                    Results_p[ResLp].DstPkt_Handle,
+                                    Token_Handle);
+#ifdef ADAPTER_AUTO_FIXUP
+                IOToken_Fixup(Results_p[ResLp].OutputToken_p,
+                              Results_p[ResLp].DstPkt_Handle);
+#endif
+
+                if (!DMABuf_Handle_IsSame(&Results_p[ResLp].DstPkt_Handle,
+                                          &DMABuf_NULLHandle))
+                {
+                    Results_p[ResLp].DstPkt_p =
+                        Adapter_DMAResource_HostAddr(
+                            Adapter_DMABuf_Handle2DMAResourceHandle(
+                                Results_p[ResLp].DstPkt_Handle));
+                }
+                else
+                {
+                    Results_p[ResLp].DstPkt_p = NULL;
+                }
+            }
+            *GetCount_p += 1;
+        } // for
+    }
+
+    LOG_INFO("\n\t PEC_Packet_Get done \n");
+
+    Adapter_Lock_CS_Leave(&AdapterPEC_GetCS[InterfaceId]);
+
+    return PEC_STATUS_OK;
+}
+
+
+/*----------------------------------------------------------------------------
+ * PEC_CD_Control_Write
+ *
+ * Write the Control1 and Control2 engine-specific fields in the
+ * Command Descriptor The other fields (such as SrcPkt_ByteCount and
+ * Bypass_WordCount must have been filled in already.
+ *
+ * Command_p (input, output)
+ *     Command descriptor whose Control1 and Control2 fields must be filled in.
+ *
+ * PacketParams_p (input)
+ *     Per-packet parameters.
+ *
+ * This function is not implemented for all engine types.
+ */
+PEC_Status_t
+PEC_CD_Control_Write(
+    PEC_CommandDescriptor_t *Command_p,
+    const PEC_PacketParams_t *PacketParams_p)
+{
+    return Adapter_PECDev_CD_Control_Write(Command_p, PacketParams_p);
+}
+
+
+/*----------------------------------------------------------------------------
+ * PEC_RD_Status_Read
+ */
+PEC_Status_t
+PEC_RD_Status_Read(
+        const PEC_ResultDescriptor_t * const Result_p,
+        PEC_ResultStatus_t * const ResultStatus_p)
+{
+    return Adapter_PECDev_RD_Status_Read(Result_p, ResultStatus_p);
+}
+
+
+/*----------------------------------------------------------------------------
+ * PEC_CommandNotify_Request
+ */
+PEC_Status_t
+PEC_CommandNotify_Request(
+        const unsigned int InterfaceId,
+        PEC_NotifyFunction_t CBFunc_p,
+        const unsigned int CommandsCount)
+{
+    unsigned int PacketSlotsEmptyCount;
+
+    LOG_INFO("\n\t PEC_CommandNotify_Request \n");
+
+    if (InterfaceId >= ADAPTER_PEC_DEVICE_COUNT)
+        return PEC_ERROR_BAD_PARAMETER;
+
+    if (CBFunc_p == NULL ||
+        CommandsCount == 0 ||
+        CommandsCount > ADAPTER_PEC_MAX_PACKETS)
+    {
+        return PEC_ERROR_BAD_PARAMETER;
+    }
+
+    if (!PEC_IsInitialized[InterfaceId])
+        return PEC_ERROR_BAD_USE_ORDER;
+
+    if (RPM_DEVICE_IO_START_MACRO(ADAPTER_PEC_RPM_EIP202_DEVICE0_ID + InterfaceId,
+                                  RPM_FLAG_SYNC) != RPM_SUCCESS)
+        return PEC_ERROR_INTERNAL;
+
+    PacketSlotsEmptyCount = Adapter_PECDev_GetFreeSpace(InterfaceId);
+
+    (void)RPM_DEVICE_IO_STOP_MACRO(ADAPTER_PEC_RPM_EIP202_DEVICE0_ID + InterfaceId,
+                                   RPM_FLAG_ASYNC);
+
+    if (CommandsCount <= PacketSlotsEmptyCount)
+    {
+        LOG_INFO(
+            "PEC_CommandNotify_Request: "
+            "Invoking command notify callback immediately\n");
+
+        CBFunc_p();
+    }
+    else
+    {
+        PEC_Notify[InterfaceId].CommandsCount = CommandsCount;
+        PEC_Notify[InterfaceId].CommandNotifyCB_p = CBFunc_p;
+
+#ifdef ADAPTER_PEC_INTERRUPTS_ENABLE
+        if (RPM_DEVICE_IO_START_MACRO(ADAPTER_PEC_RPM_EIP202_DEVICE0_ID + InterfaceId,
+                                      RPM_FLAG_SYNC) != RPM_SUCCESS)
+            return PEC_ERROR_INTERNAL;
+
+        /* Note that space for new commands may have become available before
+         * the call to PEC_CommandNotify_Request and the associated interrupt
+         * may already be pending. In this case the interrupt will occur
+         * immediately.
+         */
+        Adapter_PECDev_Enable_CommandIRQ(InterfaceId);
+
+        (void)RPM_DEVICE_IO_STOP_MACRO(ADAPTER_PEC_RPM_EIP202_DEVICE0_ID + InterfaceId,
+                                       RPM_FLAG_ASYNC);
+#endif /* ADAPTER_PEC_INTERRUPTS_ENABLE */
+    }
+
+    LOG_INFO("\n\t PEC_CommandNotify_Request done \n");
+
+    return PEC_STATUS_OK;
+}
+
+
+/*----------------------------------------------------------------------------
+ * PEC_ResultNotify_Request
+ */
+PEC_Status_t
+PEC_ResultNotify_Request(
+        const unsigned int InterfaceId,
+        PEC_NotifyFunction_t CBFunc_p,
+        const unsigned int ResultsCount)
+{
+    LOG_INFO("\n\t PEC_ResultNotify_Request \n");
+
+    if (InterfaceId >= ADAPTER_PEC_DEVICE_COUNT)
+        return PEC_ERROR_BAD_PARAMETER;
+
+    if (CBFunc_p == NULL ||
+        ResultsCount == 0 ||
+        ResultsCount > ADAPTER_PEC_MAX_PACKETS)
+    {
+        return PEC_ERROR_BAD_PARAMETER;
+    }
+
+    if (!PEC_IsInitialized[InterfaceId])
+        return PEC_ERROR_BAD_USE_ORDER;
+
+    // install it
+    PEC_Notify[InterfaceId].ResultsCount = ResultsCount;
+    PEC_Notify[InterfaceId].ResultNotifyCB_p = CBFunc_p;
+
+#ifdef ADAPTER_PEC_INTERRUPTS_ENABLE
+    if (RPM_DEVICE_IO_START_MACRO(ADAPTER_PEC_RPM_EIP202_DEVICE0_ID + InterfaceId,
+                                  RPM_FLAG_SYNC) != RPM_SUCCESS)
+        return PEC_ERROR_INTERNAL;
+
+    /* Note that results may have become available before the call
+       to PEC_ResultNotify_Request and the associated interrupts may already
+       be pending. In this case the interrupt will occur immediately.
+     */
+    Adapter_PECDev_Enable_ResultIRQ(InterfaceId);
+
+    (void)RPM_DEVICE_IO_STOP_MACRO(ADAPTER_PEC_RPM_EIP202_DEVICE0_ID + InterfaceId,
+                                   RPM_FLAG_ASYNC);
+#endif /* ADAPTER_PEC_INTERRUPTS_ENABLE */
+
+    LOG_INFO("\n\t PEC_ResultNotify_Request done\n");
+
+    return PEC_STATUS_OK;
+}
+
+
+/*----------------------------------------------------------------------------
+ * PEC_Scatter_Preload
+ */
+PEC_Status_t
+PEC_Scatter_Preload(
+        const unsigned int InterfaceId,
+        DMABuf_Handle_t * Handles_p,
+        const unsigned int HandlesCount,
+        unsigned int * const AcceptedCount_p)
+{
+    PEC_Status_t rc;
+    unsigned int i;
+    unsigned int HandlesToUse,ri,wi;
+        LOG_INFO("\n\t PEC_Scatter_Preload\n");
+
+    if (InterfaceId >= ADAPTER_PEC_DEVICE_COUNT)
+        return PEC_ERROR_BAD_PARAMETER;
+
+    if (!Adapter_Lock_CS_Enter(&AdapterPEC_PutCS[InterfaceId]))
+        return PEC_STATUS_BUSY;
+
+    if (!PEC_IsInitialized[InterfaceId] || !PEC_ContinuousScatter[InterfaceId])
+    {
+        Adapter_Lock_CS_Leave(&AdapterPEC_PutCS[InterfaceId]);
+        return PEC_ERROR_BAD_USE_ORDER;
+    }
+    ri = Adapter_SideChannelFIFO[InterfaceId].ReadIndex;
+    wi = Adapter_SideChannelFIFO[InterfaceId].WriteIndex;
+    // Compute the number of free slots in the ring from the read/write index
+    // of the side channel FIFO (which is larger than the ring)
+    if (wi >= ri)
+        HandlesToUse = ADAPTER_PEC_MAX_PACKETS - 1 - wi + ri ;
+    else
+        HandlesToUse = ADAPTER_PEC_MAX_PACKETS - 1
+            - Adapter_SideChannelFIFO[InterfaceId].Size - wi + ri;
+    if (HandlesToUse > ADAPTER_PEC_MAX_LOGICDESCR)
+        HandlesToUse = ADAPTER_PEC_MAX_LOGICDESCR;
+    if (HandlesToUse > HandlesCount)
+        HandlesToUse = HandlesCount;
+    for (i=0; i < HandlesToUse; i++)
+    {
+        DMAResource_Handle_t DMARes_Handle =
+            Adapter_DMABuf_Handle2DMAResourceHandle(Handles_p[i]);
+        DMAResource_PreDMA(DMARes_Handle, 0, 0);
+        Adapter_FIFO_Put(&Adapter_SideChannelFIFO[InterfaceId],
+                         NULL,
+                         DMABuf_NULLHandle,
+                         Handles_p[i],
+                         DMABuf_NULLHandle,
+                         0);
+    }
+    rc = Adapter_PECDev_Scatter_Preload(InterfaceId,
+                                        Handles_p,
+                                        HandlesToUse);
+
+    *AcceptedCount_p = HandlesToUse;
+    Adapter_Lock_CS_Leave(&AdapterPEC_PutCS[InterfaceId]);
+    return rc;
+}
+
+
+/*----------------------------------------------------------------------------
+ * PEC_Scatter_PreloadNotify_Request
+ */
+PEC_Status_t
+PEC_Scatter_PreloadNotify_Request(
+        const unsigned int InterfaceId,
+        PEC_NotifyFunction_t CBFunc_p,
+        const unsigned int ConsumedCount)
+{
+    IDENTIFIER_NOT_USED(InterfaceId);
+    IDENTIFIER_NOT_USED(CBFunc_p);
+    IDENTIFIER_NOT_USED(ConsumedCount);
+
+    return PEC_ERROR_NOT_IMPLEMENTED;
+}
+
+
+/*----------------------------------------------------------------------------
+ * PEC_Put_Dump
+ */
+void
+PEC_Put_Dump(
+        const unsigned int InterfaceId,
+        const unsigned int FirstSlotId,
+        const unsigned int LastSlotId,
+        const bool fDumpRDRAdmin,
+        const bool fDumpRDRCache)
+{
+    Adapter_PECDev_Put_Dump(InterfaceId,
+                            FirstSlotId,
+                            LastSlotId,
+                            fDumpRDRAdmin,
+                            fDumpRDRCache);
+}
+
+
+
+
+/*----------------------------------------------------------------------------
+ * PEC_Get_Dump
+ */
+void
+PEC_Get_Dump(
+        const unsigned int InterfaceId,
+        const unsigned int FirstSlotId,
+        const unsigned int LastSlotId,
+        const bool fDumpRDRAdmin,
+        const bool fDumpRDRCache)
+{
+    Adapter_PECDev_Get_Dump(InterfaceId,
+                            FirstSlotId,
+                            LastSlotId,
+                            fDumpRDRAdmin,
+                            fDumpRDRCache);
+}
+
+
+#endif /* ADAPTER_PE_MODE_DHM */
+
+
+/* end of file adapter_pec_dma.c */
diff --git a/package-21.02/kernel/crypto-eip/src/ddk/slad/adapter_pec_pktbuf.c b/package-21.02/kernel/crypto-eip/src/ddk/slad/adapter_pec_pktbuf.c
new file mode 100644
index 0000000..d0eec29
--- /dev/null
+++ b/package-21.02/kernel/crypto-eip/src/ddk/slad/adapter_pec_pktbuf.c
@@ -0,0 +1,206 @@
+/* adapter_pec_pktbuf.c
+ *
+ * Helper functions to access packet data via DMABuf handles, possibly
+ * in scatter-gather lists.
+ */
+
+/*****************************************************************************
+* Copyright (c) 2020-2021 by Rambus, Inc. and/or its subsidiaries.
+*
+* This program is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 2 of the License, or
+* any later version.
+*
+* This program is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with this program. If not, see <http://www.gnu.org/licenses/>.
+*****************************************************************************/
+
+
+/*----------------------------------------------------------------------------
+ * This module implements (provides) the following interface(s):
+ */
+
+#include "adapter_pec_pktbuf.h"
+
+/*----------------------------------------------------------------------------
+ * This module uses (requires) the following interface(s):
+ */
+
+// Default Adapter PEC configuration
+#include "c_adapter_pec.h"
+
+#include "api_pec_sg.h"         // PEC_SG_* (the API we implement here)
+
+
+// DMABuf API
+#include "api_dmabuf.h"         // DMABuf_*
+
+// Adapter DMABuf internal API
+#include "adapter_dmabuf.h"
+
+// Logging API
+#include "log.h"
+
+// Driver Framework DMAResource API
+#include "dmares_types.h"       // DMAResource_Handle_t
+#include "dmares_mgmt.h"        // DMAResource management functions
+#include "dmares_rw.h"          // DMAResource buffer access.
+#include "dmares_addr.h"        // DMAResource addr translation functions.
+#include "dmares_buf.h"         // DMAResource buffer allocations
+
+// Driver Framework C Run-Time Library API
+#include "clib.h"               // memcpy, memset
+
+// Driver Framework Basic Definitions API
+#include "basic_defs.h"         // bool, uint32_t
+
+
+/*----------------------------------------------------------------------------
+ * Definitions and macros
+ */
+
+/*----------------------------------------------------------------------------
+ * Adapter_PEC_PktData_Get
+ */
+uint8_t *
+Adapter_PEC_PktData_Get(
+        DMABuf_Handle_t PacketHandle,
+        uint8_t *CopyBuffer_p,
+        unsigned int StartOffs,
+        unsigned int ByteCount)
+{
+#ifdef ADAPTER_PEC_ENABLE_SCATTERGATHER
+    unsigned int NofParticles;
+    PEC_SGList_GetCapacity(PacketHandle, &NofParticles);
+    if (NofParticles != 0)
+    {
+        unsigned int TotalByteCount = 0;
+        unsigned int BytesCopied = 0;
+        unsigned int BytesSkip;
+        unsigned int i;
+        unsigned int FragmentByteCount;
+        DMABuf_Handle_t FragmentHandle;
+        uint8_t *FragmentPtr;
+        for (i=0; i<NofParticles; i++)
+        {
+            PEC_SGList_Read(PacketHandle, i, &FragmentHandle,
+                            &FragmentByteCount, &FragmentPtr);
+            if (TotalByteCount + FragmentByteCount >=
+                StartOffs + ByteCount)
+            {
+                // This is the last fragment to visit (possibly the first).
+                if (BytesCopied == 0)
+                {
+                    // No need to copy everything is in single fragment.
+                    return FragmentPtr + StartOffs - TotalByteCount;
+                }
+                else
+                {
+                    // Copy the final fragment.
+                    memcpy(CopyBuffer_p + BytesCopied,
+                           FragmentPtr, ByteCount - BytesCopied);
+                    return CopyBuffer_p;
+                }
+            }
+            else if (TotalByteCount + FragmentByteCount >
+                     StartOffs)
+            {
+                // This fragment contains data that must be copied
+                if (BytesCopied == 0)
+                {
+                    // First fragment containing data to copy, may need to skip
+                    // bytes at start of fragment.
+                    BytesSkip = StartOffs - TotalByteCount;
+                }
+                else
+                {   // Later fragments, copy from start of fragment.
+                    BytesSkip = 0;
+                }
+                if (CopyBuffer_p == NULL)
+                    return NULL; // Skip copying altogether.
+                memcpy(CopyBuffer_p + BytesCopied,
+                       FragmentPtr + BytesSkip,
+                       FragmentByteCount - BytesSkip);
+                BytesCopied += FragmentByteCount - BytesSkip;
+            }
+            TotalByteCount += FragmentByteCount;
+        }
+        // We haven't collected enough data here, return NULL pointer.
+        return NULL;
+    }
+    else
+#endif
+    {
+        DMAResource_Handle_t DMAHandle =
+            Adapter_DMABuf_Handle2DMAResourceHandle(PacketHandle);
+        uint8_t *Packet_p;
+        IDENTIFIER_NOT_USED(CopyBuffer_p);
+        IDENTIFIER_NOT_USED(ByteCount);
+        if (DMAResource_IsValidHandle(DMAHandle))
+        {
+            Packet_p = (uint8_t *)Adapter_DMAResource_HostAddr(DMAHandle) + StartOffs;
+        }
+        else
+        {
+            Packet_p = NULL;
+        }
+        return Packet_p;
+    }
+}
+
+/*----------------------------------------------------------------------------
+ * Adapter_PEC_PktByte_Put
+ */
+void
+Adapter_PEC_PktByte_Put(
+        DMABuf_Handle_t PacketHandle,
+        unsigned int Offset,
+        unsigned int Byte)
+{
+#ifdef ADAPTER_PEC_ENABLE_SCATTERGATHER
+    unsigned int NofParticles;
+    PEC_SGList_GetCapacity(PacketHandle, &NofParticles);
+    if (NofParticles != 0)
+    {
+        unsigned int TotalByteCount = 0;
+        unsigned int i;
+        unsigned int FragmentByteCount;
+        DMABuf_Handle_t FragmentHandle;
+        uint8_t *FragmentPtr;
+        for (i=0; i<NofParticles; i++)
+        {
+            PEC_SGList_Read(PacketHandle, i, &FragmentHandle,
+                            &FragmentByteCount, &FragmentPtr);
+            if (TotalByteCount + FragmentByteCount > Offset)
+            {
+                // Found the fragment where the byte must be changed..
+                FragmentPtr[Offset - TotalByteCount] = Byte;
+                return;
+            }
+            TotalByteCount += FragmentByteCount;
+        }
+    }
+    else
+#endif
+    {
+        DMAResource_Handle_t DMAHandle =
+            Adapter_DMABuf_Handle2DMAResourceHandle(PacketHandle);
+        uint8_t *Packet_p;
+        if (DMAResource_IsValidHandle(DMAHandle))
+        {
+            Packet_p = (uint8_t *)Adapter_DMAResource_HostAddr(DMAHandle) + Offset;
+            Packet_p[0] = Byte;
+        }
+    }
+}
+
+
+
+
+/* end of file adapter_pec_dmabuf.c */
diff --git a/package-21.02/kernel/crypto-eip/src/ddk/slad/adapter_ring_eip202.c b/package-21.02/kernel/crypto-eip/src/ddk/slad/adapter_ring_eip202.c
new file mode 100644
index 0000000..470378a
--- /dev/null
+++ b/package-21.02/kernel/crypto-eip/src/ddk/slad/adapter_ring_eip202.c
@@ -0,0 +1,3012 @@
+/* adapter_ring_eip202.c
+ *
+ * Adapter EIP-202 implementation: EIP-202 specific layer.
+ */
+
+/*****************************************************************************
+* Copyright (c) 2011-2022 by Rambus, Inc. and/or its subsidiaries.
+*
+* This program is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 2 of the License, or
+* any later version.
+*
+* This program is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with this program. If not, see <http://www.gnu.org/licenses/>.
+*****************************************************************************/
+
+/*----------------------------------------------------------------------------
+ * This module implements (provides) the following interface(s):
+ */
+
+// SLAD Adapter PEC Device-specific API
+#include "adapter_pecdev_dma.h"
+
+// Ring Control configuration API
+#include "adapter_ring_eip202.h"
+
+#if defined(ADAPTER_EIP202_RC_DIRECT_INVALIDATE_SUPPORT) || \
+    defined(ADAPTER_EIP202_RC_DMA_BANK_SUPPORT)
+// Record Cache configuration API
+#include "adapter_rc_eip207.h"
+#endif
+
+
+/*----------------------------------------------------------------------------
+ * This module uses (requires) the following interface(s):
+ */
+
+// Default configuration
+#include "c_adapter_eip202.h"
+
+// Driver Framework Basic Definitions API
+#include "basic_defs.h"         // bool
+#include "api_pec.h"
+#include "api_dmabuf.h"
+
+// Adapter DMABuf internal API
+#include "adapter_dmabuf.h"
+
+// Convert address to pair of 32-bit words.
+#include "adapter_addrpair.h"
+
+// Adapter interrupts API
+#include "adapter_interrupts.h" // Adapter_Interrupt_*
+
+// Adapter memory allocation API
+#include "adapter_alloc.h"      // Adapter_Alloc/Free
+
+// Driver Framework DMAResource API
+#include "dmares_addr.h"      // AddrTrans_*
+#include "dmares_buf.h"       // DMAResource_Alloc/Release
+#include "dmares_rw.h"        // DMAResource_PreDMA/PostDMA
+#include "dmares_mgmt.h"      // DMAResource_Alloc/Release
+
+#include "device_types.h"  // Device_Handle_t
+#include "device_mgmt.h" // Device_find
+#include "device_rw.h" // Device register read/write
+
+#ifdef ADAPTER_EIP202_ENABLE_SCATTERGATHER
+#include "api_pec_sg.h"         // PEC_SG_* (the API we implement here)
+#endif
+
+// EIP97 Ring Control
+#include "eip202_ring_types.h"
+#include "eip202_cdr.h"
+#include "eip202_rdr.h"
+
+// Standard IOToken API
+#include "iotoken.h"
+
+
+#ifdef ADAPTER_EIP202_USE_SHDEVXS
+#include "shdevxs_prng.h"
+#else
+#include "eip97_global_init.h"
+#endif
+
+#if defined(ADAPTER_EIP202_RC_DIRECT_INVALIDATE_SUPPORT) || \
+    defined(ADAPTER_EIP202_RC_DMA_BANK_SUPPORT)
+#ifdef ADAPTER_EIP202_USE_SHDEVXS
+// EIP-207 Record Cache (RC) interface
+#include "shdevxs_dmapool.h"
+#include "shdevxs_rc.h"
+#else
+// EIP-207 Record Cache (RC) interface
+#include "eip207_rc.h"                  // EIP207_RC_*
+#endif // ADAPTER_EIP202_USE_SHDEVXS
+#endif
+
+#include "clib.h"  // memcpy, ZEROINIT
+
+// Log API
+#include "log.h"
+
+
+/*----------------------------------------------------------------------------
+ * Definitions and macros
+ */
+
+#if defined(ADAPTER_EIP202_RC_DIRECT_INVALIDATE_SUPPORT) || \
+    defined(ADAPTER_EIP202_RC_DMA_BANK_SUPPORT)
+#ifndef ADAPTER_EIP202_USE_SHDEVXS
+// The default Record Cache set number to be used
+// Note: Only one cache set is supported by this implementation!
+#define EIP207_RC_SET_NR_DEFAULT              0
+#endif
+#endif // ADAPTER_EIP202_RC_DIRECT_INVALIDATE_SUPPORT || ADAPTER_EIP202_RC_DMA_BANK_SUPPORT
+
+#if defined(ADAPTER_EIP202_RC_DIRECT_INVALIDATE_SUPPORT) || \
+    defined(ADAPTER_EIP202_RC_DMA_BANK_SUPPORT)
+#ifdef ADAPTER_EIP202_USE_SHDEVXS
+#define ADAPTER_EIP202_DUMMY_DMA_ADDRESS_LO   SHDevXS_RC_Record_Dummy_Addr_Get()
+#define ADAPTER_EIP202_DUMMY_DMA_ADDRESS_HI   0
+#else
+#define ADAPTER_EIP202_DUMMY_DMA_ADDRESS_LO   EIP207_RC_Record_Dummy_Addr_Get()
+#define ADAPTER_EIP202_DUMMY_DMA_ADDRESS_HI   0
+#endif // ADAPTER_EIP202_USE_SHDEVXS
+#else
+
+#ifdef ADAPTER_EIP202_USE_POINTER_TYPES
+#define ADAPTER_EIP202_DUMMY_DMA_ADDRESS_LO       0xfffffffc
+#define ADAPTER_EIP202_DUMMY_DMA_ADDRESS_HI       0xffffffff
+#else
+#define ADAPTER_EIP202_DUMMY_DMA_ADDRESS_LO       3
+#define ADAPTER_EIP202_DUMMY_DMA_ADDRESS_HI       0
+#endif
+
+#endif // ADAPTER_EIP202_RC_DIRECT_INVALIDATE_SUPPORT || ADAPTER_EIP202_RC_DMA_BANK_SUPPORT
+
+// Move bit position src in value v to dst.
+#define BIT_MOVE(v, src, dst)  ( ((src) < (dst)) ? \
+    ((v) << ((dst) - (src))) & (1 << (dst)) :  \
+    ((v) >> ((src) - (dst))) & (1 << (dst)))
+
+#ifndef ADAPTER_EIP202_SEPARATE_RINGS
+#define ADAPTER_EIP202_CDR_BYTE_OFFSET              \
+                    (EIP202_RD_CTRL_DATA_MAX_WORD_COUNT * sizeof(uint32_t))
+#endif
+
+
+typedef struct
+{
+    unsigned int CDR_IRQ_ID;
+
+    unsigned int CDR_IRQ_Flags;
+
+    const char * CDR_DeviceName_p;
+
+    unsigned int RDR_IRQ_ID;
+
+    unsigned int RDR_IRQ_Flags;
+
+    const char * RDR_DeviceName_p;
+
+} Adapter_Ring_EIP202_Device_t;
+
+
+#ifdef ADAPTER_EIP202_USE_POINTER_TYPES
+#define ADAPTER_EIP202_TR_ADDRESS       2
+#ifndef ADAPTER_EIP202_USE_LARGE_TRANSFORM_DISABLE
+#define ADAPTER_EIP202_TR_LARGE_ADDRESS 3
+// Bit in first word of SA record to indicate it is large.
+#define ADAPTER_EIP202_TR_ISLARGE              BIT_4
+#endif
+#endif
+
+
+/*----------------------------------------------------------------------------
+ * Local variables
+ */
+
+static const Adapter_Ring_EIP202_Device_t EIP202_Devices [] =
+{
+    ADAPTER_EIP202_DEVICES
+};
+
+// number of devices supported calculated on ADAPTER_EIP202_DEVICES defined
+// in c_adapter_eip202.h
+#define ADAPTER_EIP202_DEVICE_COUNT_ACTUAL \
+        (sizeof(EIP202_Devices) / sizeof(Adapter_Ring_EIP202_Device_t))
+
+static EIP202_CDR_Settings_t  CDR_Settings;
+static EIP202_RDR_Settings_t  RDR_Settings;
+
+#ifdef ADAPTER_EIP202_INTERRUPTS_ENABLE
+static unsigned int EIP202_Interrupts[ADAPTER_EIP202_DEVICE_COUNT];
+#endif
+
+static EIP202_Ring_IOArea_t CDR_IOArea[ADAPTER_EIP202_DEVICE_COUNT];
+static EIP202_Ring_IOArea_t RDR_IOArea[ADAPTER_EIP202_DEVICE_COUNT];
+
+static DMAResource_Handle_t CDR_Handle[ADAPTER_EIP202_DEVICE_COUNT];
+static DMAResource_Handle_t RDR_Handle[ADAPTER_EIP202_DEVICE_COUNT];
+
+static  EIP202_ARM_CommandDescriptor_t
+    EIP202_CDR_Entries[ADAPTER_EIP202_DEVICE_COUNT][ADAPTER_EIP202_MAX_LOGICDESCR];
+
+static  EIP202_ARM_PreparedDescriptor_t
+    EIP202_RDR_Prepared[ADAPTER_EIP202_DEVICE_COUNT][ADAPTER_EIP202_MAX_LOGICDESCR];
+
+static  EIP202_ARM_ResultDescriptor_t
+    EIP202_RDR_Entries[ADAPTER_EIP202_DEVICE_COUNT][ADAPTER_EIP202_MAX_LOGICDESCR];
+
+static bool EIP202_ContinuousScatter[ADAPTER_EIP202_DEVICE_COUNT];
+
+static const PEC_Capabilities_t CapabilitiesString =
+{
+    "EIP-202 Packet Engine rings=__ (ARM,"        // szTextDescription
+#ifdef ADAPTER_EIP202_ENABLE_SCATTERGATHER
+    "SG,"
+#endif
+#ifndef ADAPTER_EIP202_REMOVE_BOUNCEBUFFERS
+    "BB,"
+#endif
+#ifdef ADAPTER_EIP202_INTERRUPTS_ENABLE
+    "Int)",
+#else
+    "Poll)",
+#endif
+    0
+};
+
+// Static variables used by the adapter_ring_eip202.h interface implementation
+static bool    Adapter_Ring_EIP202_Configured;
+static uint8_t Adapter_Ring_EIP202_HDW;
+static uint8_t Adapter_Ring_EIP202_CFSize;
+static uint8_t Adapter_Ring_EIP202_RFSize;
+
+#ifdef ADAPTER_EIP202_DMARESOURCE_BANKS_ENABLE
+#ifdef ADAPTER_EIP202_RC_DMA_BANK_SUPPORT
+static uint32_t EIP202_SABaseAddr;
+static uint32_t EIP202_SABaseUpperAddr;
+#endif // ADAPTER_EIP202_RC_DMA_BANK_SUPPORT
+#endif // ADAPTER_EIP202_DMARESOURCE_BANKS_ENABLE
+
+#ifdef ADAPTER_EIP202_RC_DIRECT_INVALIDATE_SUPPORT
+// Static variables used by the adapter_rc_eip207.h interface implementation
+static bool Adapter_RC_EIP207_Configured = true;
+static bool Adapter_RC_EIP207_TRC_Enabled = true;
+static bool Adapter_RC_EIP207_ARC4RC_Enabled;
+static bool Adapter_RC_EIP207_Combined;
+#endif // ADAPTER_EIP202_RC_DIRECT_INVALIDATE_SUPPORT
+
+// DMA buffer allocation alignment in bytes
+static int Adapter_Ring_EIP202_DMA_Alignment_ByteCount =
+                                        ADAPTER_DMABUF_ALIGNMENT_INVALID;
+
+
+#ifdef ADAPTER_EIP202_ADD_INIT_DIAGNOSTICS
+static void
+Adapter_Register_Dump(void)
+{
+    Device_Handle_t Device=Device_Find("EIP197_GLOBAL");
+    unsigned int i,j,v[256];
+    LOG_CRIT("REGISTER DUMP\n");
+    for (i=0; i<0x100000; i+=1024)
+    {
+        Device_Read32Array(Device, i, v, 256);
+        for (j=0; j<256; j++)
+        {
+            if (v[j])
+            {
+                LOG_CRIT("Addr 0x%08x = 0x%08x\n",i+j*4,v[j]);
+            }
+        }
+    }
+    LOG_CRIT("END REGISTER DUMP\n");
+}
+#endif
+
+/*----------------------------------------------------------------------------
+ * AdapterLib_RD_OutTokens_Free
+ *
+ * Free Output Tokens in the EIP-202 result descriptors.
+ */
+static void
+AdapterLib_RD_OutTokens_Free(
+        const unsigned int InterfaceId)
+{
+    unsigned int i;
+
+    for (i = 0; i < ADAPTER_EIP202_MAX_LOGICDESCR; i++)
+        Adapter_Free(EIP202_RDR_Entries[InterfaceId][i].Token_p);
+}
+
+
+/*----------------------------------------------------------------------------
+ * AdapterLib_RD_OutTokens_Alloc
+ *
+ * Allocate Output Tokens in the EIP-202 result descriptors.
+ */
+static bool
+AdapterLib_RD_OutTokens_Alloc(
+        const unsigned int InterfaceId)
+{
+    unsigned int i;
+
+    for (i = 0; i < ADAPTER_EIP202_MAX_LOGICDESCR; i++)
+    {
+        uint32_t * p =
+               Adapter_Alloc(IOToken_OutWordCount_Get() * sizeof (uint32_t));
+
+        if (p)
+            EIP202_RDR_Entries[InterfaceId][i].Token_p = p;
+        else
+            goto exit_error;
+    }
+
+    return true;
+
+exit_error:
+    AdapterLib_RD_OutTokens_Free(InterfaceId);
+
+    return false;
+}
+
+
+/*----------------------------------------------------------------------------
+ * Adapter_GetPhysAddr
+ *
+ * Obtain the physical address from a DMABuf handle.
+ * Take the bounce handle into account.
+ *
+ */
+static void
+Adapter_GetPhysAddr(
+        const DMABuf_Handle_t Handle,
+        EIP202_DeviceAddress_t *PhysAddr_p)
+{
+    DMAResource_Handle_t DMAHandle =
+        Adapter_DMABuf_Handle2DMAResourceHandle(Handle);
+    DMAResource_Record_t * Rec_p = NULL;
+    DMAResource_AddrPair_t PhysAddr_Pair;
+
+    if (PhysAddr_p == NULL)
+    {
+        LOG_CRIT("Adapter_GetPhysAddr: PANIC\n");
+        return;
+    }
+
+    PhysAddr_p->Addr        = ADAPTER_EIP202_DUMMY_DMA_ADDRESS_LO;
+    PhysAddr_p->UpperAddr   = ADAPTER_EIP202_DUMMY_DMA_ADDRESS_HI;
+
+    // Note: this function is sometimes invoked with invalid DMA handle
+    //       to obtain a dummy address, not an error.
+    if (!DMAResource_IsValidHandle(DMAHandle))
+        return; // success!
+
+    Rec_p = DMAResource_Handle2RecordPtr(DMAHandle);
+
+    if (Rec_p == NULL)
+    {
+        LOG_CRIT("Adapter_GetPhysAddr: failed\n");
+        return;
+    }
+
+#ifndef ADAPTER_EIP202_REMOVE_BOUNCEBUFFERS
+    if (Rec_p->bounce.Bounce_Handle != NULL)
+        DMAHandle = Rec_p->bounce.Bounce_Handle;
+#endif
+
+    if (DMAResource_Translate(DMAHandle, DMARES_DOMAIN_BUS,
+                              &PhysAddr_Pair) == 0)
+    {
+        Adapter_AddrToWordPair(PhysAddr_Pair.Address_p, 0, &PhysAddr_p->Addr,
+                              &PhysAddr_p->UpperAddr);
+        // success!
+    }
+    else
+    {
+        LOG_CRIT("Adapter_GetPhysAddr: failed\n");
+    }
+}
+
+
+/*----------------------------------------------------------------------------
+ * BoolToString()
+ *
+ * Convert boolean value to string.
+ */
+static const char *
+BoolToString(
+        bool b)
+{
+    if (b)
+        return "TRUE";
+    else
+        return "false";
+}
+
+
+/*----------------------------------------------------------------------------
+ * AdapterLib_Ring_EIP202_CDR_Status_Report
+ *
+ * Report the status of the CDR interface
+ *
+ */
+static void
+AdapterLib_Ring_EIP202_CDR_Status_Report(
+        unsigned int InterfaceId)
+{
+    EIP202_Ring_Error_t res;
+    EIP202_CDR_Status_t CDR_Status;
+
+    LOG_CRIT("Status of CDR interface %d\n",InterfaceId);
+
+    LOG_INFO("\n\t\t\t EIP202_CDR_Status_Get \n");
+
+    ZEROINIT(CDR_Status);
+    res = EIP202_CDR_Status_Get(CDR_IOArea + InterfaceId, &CDR_Status);
+    if (res != EIP202_RING_NO_ERROR)
+    {
+        LOG_CRIT("EIP202_CDR_Status_Get returned error\n");
+        return;
+    }
+
+    // Report CDR status
+    LOG_CRIT("CDR Status: CD prep/proc count %d/%d, proc pkt count %d\n",
+             CDR_Status.CDPrepWordCount,
+             CDR_Status.CDProcWordCount,
+             CDR_Status.CDProcPktWordCount);
+
+    if (CDR_Status.fDMAError    ||
+        CDR_Status.fError       ||
+        CDR_Status.fOUFlowError ||
+        CDR_Status.fTresholdInt ||
+        CDR_Status.fTimeoutInt)
+    {
+        // Report CDR errors
+        LOG_CRIT("CDR Status: error(s) detected\n");
+        LOG_CRIT("\tDMA err:       %s\n"
+                 "\tErr:           %s\n"
+                 "\tOvf/under err: %s\n"
+                 "\tThreshold int: %s\n"
+                 "\tTimeout int:   %s\n"
+                 "\tFIFO count:    %d\n",
+                 BoolToString(CDR_Status.fDMAError),
+                 BoolToString(CDR_Status.fError),
+                 BoolToString(CDR_Status.fOUFlowError),
+                 BoolToString(CDR_Status.fTresholdInt),
+                 BoolToString(CDR_Status.fTimeoutInt),
+                 CDR_Status.CDFIFOWordCount);
+    }
+    else
+        LOG_CRIT("CDR Status: all OK, FIFO count: %d\n",
+                 CDR_Status.CDFIFOWordCount);
+}
+
+
+/*----------------------------------------------------------------------------
+ * AdapterLib_Ring_EIP202_RDR_Status_Report
+ *
+ * Report the status of the RDR interface
+ *
+ */
+static void
+AdapterLib_Ring_EIP202_RDR_Status_Report(
+        unsigned int InterfaceId)
+{
+    EIP202_Ring_Error_t res;
+    EIP202_RDR_Status_t RDR_Status;
+
+    LOG_CRIT("Status of RDR interface %d\n",InterfaceId);
+    if (EIP202_ContinuousScatter[InterfaceId])
+        LOG_CRIT("Ring is in continuous scatter mode\n");
+
+    LOG_INFO("\n\t\t\t EIP202_RDR_Status_Get \n");
+
+    ZEROINIT(RDR_Status);
+    res = EIP202_RDR_Status_Get(RDR_IOArea + InterfaceId, &RDR_Status);
+    if (res != EIP202_RING_NO_ERROR)
+    {
+        LOG_CRIT("EIP202_RDR_Status_Get returned error\n");
+        return;
+    }
+
+    // Report RDR status
+    LOG_CRIT("RDR Status: RD prep/proc count %d/%d, proc pkt count %d\n",
+             RDR_Status.RDPrepWordCount,
+             RDR_Status.RDProcWordCount,
+             RDR_Status.RDProcPktWordCount);
+
+    if (RDR_Status.fDMAError         ||
+        RDR_Status.fError            ||
+        RDR_Status.fOUFlowError      ||
+        RDR_Status.fRDBufOverflowInt ||
+        RDR_Status.fRDOverflowInt    ||
+        RDR_Status.fTresholdInt      ||
+        RDR_Status.fTimeoutInt)
+    {
+        // Report RDR errors
+        LOG_CRIT("RDR Status: error(s) detected\n");
+        LOG_CRIT("\tDMA err:        %s\n"
+                 "\tErr:            %s\n"
+                 "\tOvf/under err:  %s\n"
+                 "\tBuf ovf:        %s\n"
+                 "\tDescriptor ovf: %s\n"
+                 "\tThreshold int:  %s\n"
+                 "\tTimeout int:    %s\n"
+                 "\tFIFO count:     %d\n",
+                 BoolToString(RDR_Status.fDMAError),
+                 BoolToString(RDR_Status.fError),
+                 BoolToString(RDR_Status.fOUFlowError),
+                 BoolToString(RDR_Status.fRDBufOverflowInt),
+                 BoolToString(RDR_Status.fRDOverflowInt),
+                 BoolToString(RDR_Status.fTresholdInt),
+                 BoolToString(RDR_Status.fTimeoutInt),
+                 RDR_Status.RDFIFOWordCount);
+    }
+    else
+        LOG_CRIT("RDR Status: all OK, FIFO count: %d\n",
+                 RDR_Status.RDFIFOWordCount);
+}
+
+
+/*----------------------------------------------------------------------------
+ * AdapterLib_Ring_EIP202_Status_Report
+ *
+ * Report the status of the CDR and RDR interface
+ *
+ */
+static void
+AdapterLib_Ring_EIP202_Status_Report(
+        unsigned int InterfaceId)
+{
+    AdapterLib_Ring_EIP202_CDR_Status_Report(InterfaceId);
+
+    AdapterLib_Ring_EIP202_RDR_Status_Report(InterfaceId);
+}
+
+
+/*----------------------------------------------------------------------------
+ * AdapterLib_Ring_EIP202_AlignForSize
+ */
+static unsigned int
+AdapterLib_Ring_EIP202_AlignForSize(
+        const unsigned int ByteCount,
+        const unsigned int AlignTo)
+{
+    unsigned int AlignedByteCount = ByteCount;
+
+    // Check if alignment and padding for length alignment is required
+    if (AlignTo > 1 && ByteCount % AlignTo)
+        AlignedByteCount = ByteCount / AlignTo * AlignTo + AlignTo;
+
+    return AlignedByteCount;
+}
+
+
+/*----------------------------------------------------------------------------
+ * AdapterLib_Ring_EIP202_DMA_Alignment_Determine
+ *
+ * Determine the required EIP-202 DMA alignment value
+ *
+ */
+static bool
+AdapterLib_Ring_EIP202_DMA_Alignment_Determine(void)
+{
+#ifdef ADAPTER_EIP202_ALLOW_UNALIGNED_DMA
+    Adapter_DMAResource_Alignment_Set(1);
+#else
+    // Default alignment value is invalid
+    Adapter_Ring_EIP202_DMA_Alignment_ByteCount =
+                                ADAPTER_DMABUF_ALIGNMENT_INVALID;
+
+    if (Adapter_Ring_EIP202_Configured)
+    {
+        int AlignTo = Adapter_Ring_EIP202_HDW;
+
+        // Determine the EIP-202 master interface hardware data width
+        switch (AlignTo)
+        {
+            case EIP202_RING_DMA_ALIGNMENT_4_BYTES:
+                Adapter_DMAResource_Alignment_Set(4);
+                break;
+            case EIP202_RING_DMA_ALIGNMENT_8_BYTES:
+                Adapter_DMAResource_Alignment_Set(8);
+                break;
+            case EIP202_RING_DMA_ALIGNMENT_16_BYTES:
+                Adapter_DMAResource_Alignment_Set(16);
+                break;
+            case EIP202_RING_DMA_ALIGNMENT_32_BYTES:
+                Adapter_DMAResource_Alignment_Set(32);
+                break;
+            default:
+                // Not supported, the alignment value cannot be determined
+                LOG_CRIT("AdapterLib_Ring_EIP202_DMA_Alignment_Determine: "
+                         "EIP-202 master interface HW data width "
+                         "(%d) is unsupported\n",
+                         AlignTo);
+                return false; // Error
+        } // switch
+    }
+    else
+    {
+#if ADAPTER_EIP202_DMA_ALIGNMENT_BYTE_COUNT == 0
+        // The alignment value cannot be determined
+        return false; // Error
+#else
+        // Set the configured non-zero alignment value
+        Adapter_DMAResource_Alignment_Set(
+                ADAPTER_EIP202_DMA_ALIGNMENT_BYTE_COUNT);
+#endif
+    }
+#endif
+
+    Adapter_Ring_EIP202_DMA_Alignment_ByteCount =
+                            Adapter_DMAResource_Alignment_Get();
+
+    return true; // Success
+}
+
+
+/*----------------------------------------------------------------------------
+ * AdapterLib_Ring_EIP202_DMA_Alignment_Get
+ *
+ * Get the required EIP-202 DMA alignment value
+ *
+ */
+inline static int
+AdapterLib_Ring_EIP202_DMA_Alignment_Get(void)
+{
+    return Adapter_Ring_EIP202_DMA_Alignment_ByteCount;
+}
+
+
+/*----------------------------------------------------------------------------
+ * AdapterLib_Ring_EIP202_DMAAddr_IsSane
+ *
+ * Validate the DMA address for the EIP-202 device
+ *
+ */
+inline static bool
+AdapterLib_Ring_EIP202_DMAAddr_IsSane(
+        const EIP202_DeviceAddress_t * const DevAddr_p,
+        const char * BufferName_p)
+{
+#ifndef ADAPTER_EIP202_64BIT_DEVICE
+    // Check if 64-bit DMA address is used for EIP-202 configuration
+    // that supports 32-bit addresses only
+    if (DevAddr_p->UpperAddr)
+    {
+        LOG_CRIT("%s: failed, "
+                 "%s bus address (low/high 32 bits 0x%08x/0x%08x) too big\n",
+                 __func__,
+                 BufferName_p,
+                 DevAddr_p->Addr,
+                 DevAddr_p->UpperAddr);
+        return false;
+    }
+    else
+        return true;
+#else
+    IDENTIFIER_NOT_USED(DevAddr_p);
+    IDENTIFIER_NOT_USED(BufferName_p);
+    return true;
+#endif
+}
+
+
+/*----------------------------------------------------------------------------
+ * Implementation of the adapter_ring_eip202.h interface
+ *
+ */
+
+/*----------------------------------------------------------------------------
+ * Adapter_Ring_EIP202_Configure
+ */
+void
+Adapter_Ring_EIP202_Configure(
+        const uint8_t HostDataWidth,
+        const uint8_t CF_Size,
+        const uint8_t RF_Size)
+{
+    Adapter_Ring_EIP202_HDW    = HostDataWidth;
+    Adapter_Ring_EIP202_CFSize = CF_Size;
+    Adapter_Ring_EIP202_RFSize = RF_Size;
+
+    Adapter_Ring_EIP202_Configured = true;
+}
+
+/*----------------------------------------------------------------------------
+ * Implementation of the adapter_rc_eip207.h interface
+ *
+ */
+
+#ifdef ADAPTER_EIP202_RC_DIRECT_INVALIDATE_SUPPORT
+/*----------------------------------------------------------------------------
+ * Adapter_RC_EIP207_Configure
+ */
+void
+Adapter_RC_EIP207_Configure(
+        const bool fEnabledTRC,
+        const bool fEnabledARC4RC,
+        const bool fCombined)
+{
+    Adapter_RC_EIP207_Combined       = fCombined;
+    Adapter_RC_EIP207_TRC_Enabled    = fEnabledTRC;
+    Adapter_RC_EIP207_ARC4RC_Enabled = fEnabledARC4RC;
+
+    Adapter_RC_EIP207_Configured     = true;
+
+}
+#endif // ADAPTER_EIP202_RC_DIRECT_INVALIDATE_SUPPORT
+
+
+/*----------------------------------------------------------------------------
+ * Implementation of the adapter_pecdev_dma.h interface
+ *
+ */
+
+/*----------------------------------------------------------------------------
+ * Adapter_PECDev_Capabilities_Get
+ */
+PEC_Status_t
+Adapter_PECDev_Capabilities_Get(
+        PEC_Capabilities_t * const Capabilities_p)
+{
+    uint8_t Versions[2];
+
+    if (Capabilities_p == NULL)
+        return PEC_ERROR_BAD_PARAMETER;
+
+    memcpy(Capabilities_p, &CapabilitiesString, sizeof(CapabilitiesString));
+
+    // now fill in the number of rings.
+    {
+        Versions[0] = ADAPTER_EIP202_DEVICE_COUNT / 10;
+        Versions[1] = ADAPTER_EIP202_DEVICE_COUNT % 10;
+    }
+
+    {
+        char * p = Capabilities_p->szTextDescription;
+        int VerIndex = 0;
+        int i = 0;
+
+        if (p[sizeof(CapabilitiesString)-1] != 0)
+            return PEC_ERROR_INTERNAL;
+
+        while(p[i])
+        {
+            if (p[i] == '_')
+            {
+                if (VerIndex == sizeof(Versions)/sizeof(Versions[0]))
+                    return PEC_ERROR_INTERNAL;
+                if (Versions[VerIndex] > 9)
+                    p[i] = '?';
+                else
+                    p[i] = '0' + Versions[VerIndex++];
+            }
+
+            i++;
+        }
+    }
+#ifdef ADAPTER_EIP202_USE_SHDEVXS
+    Capabilities_p->SupportedFuncs = SHDevXS_SupportedFuncs_Get();
+#else
+    Capabilities_p->SupportedFuncs = EIP97_SupportedFuncs_Get();
+#endif
+    return PEC_STATUS_OK;
+}
+
+/*----------------------------------------------------------------------------
+ * Adapter_PECDev_Control_Write
+ */
+PEC_Status_t
+Adapter_PECDev_CD_Control_Write(
+    PEC_CommandDescriptor_t *Command_p,
+    const PEC_PacketParams_t *PacketParams_p)
+{
+    IDENTIFIER_NOT_USED(Command_p);
+    IDENTIFIER_NOT_USED(PacketParams_p);
+
+    return PEC_ERROR_NOT_IMPLEMENTED;
+}
+
+
+/*----------------------------------------------------------------------------
+ * Adapter_PECDev_RD_Status_Read
+ */
+PEC_Status_t
+Adapter_PECDev_RD_Status_Read(
+        const PEC_ResultDescriptor_t * const Result_p,
+        PEC_ResultStatus_t * const ResultStatus_p)
+{
+    unsigned int s;
+
+#ifdef ADAPTER_EIP202_STRICT_ARGS
+    if (ResultStatus_p == NULL)
+        return PEC_ERROR_BAD_PARAMETER;
+#endif
+
+    if (IOToken_ErrorCode_Get(Result_p->OutputToken_p, &s) < 0)
+        return PEC_ERROR_BAD_PARAMETER;
+
+    // Translate the EIP-96 error codes to the PEC error codes
+    ResultStatus_p->errors =
+        BIT_MOVE(s,  0, 11) | // EIP-96 Packet length error
+        BIT_MOVE(s,  1, 17) | // EIP-96 Token error
+        BIT_MOVE(s,  2, 18) | // EIP-96 Bypass error
+        BIT_MOVE(s,  3,  9) | // EIP-96 Block size error
+        BIT_MOVE(s,  4, 16) | // EIP-96 Hash block size error.
+        BIT_MOVE(s,  5, 10) | // EIP-96 Invalid combo
+        BIT_MOVE(s,  6,  5) | // EIP-96 Prohibited algo
+        BIT_MOVE(s,  7, 19) | // EIP-96 Hash overflow
+#ifndef ADAPTER_EIP202_RING_TTL_ERROR_WA
+        BIT_MOVE(s,  8, 20) | // EIP-96 TTL/Hop limit underflow.
+#endif
+        BIT_MOVE(s,  9,  0) | // EIP-96 Authentication failed
+        BIT_MOVE(s, 10,  2) | // EIP-96 Sequence number check failed.
+        BIT_MOVE(s, 11,  8) | // EIP-96 SPI check failed.
+        BIT_MOVE(s, 12, 21) | // EIP-96 Incorrect checksum
+        BIT_MOVE(s, 12,  1) | // EIP-96 Pad verification.
+        BIT_MOVE(s, 14, 22);  // EIP-96 Timeout
+
+    // Translate the EIP-202 error codes to the PEC error codes
+    s = Result_p->Status1;
+    ResultStatus_p->errors  |=
+        BIT_MOVE(s, 21, 26) | // EIP-202 Buffer overflow
+        BIT_MOVE(s, 20, 25);  // EIP-202 Descriptor overflow
+
+    return PEC_STATUS_OK;
+}
+
+
+/*----------------------------------------------------------------------------
+ * Adapter_PECDev_Init
+ */
+PEC_Status_t
+Adapter_PECDev_Init(
+        const unsigned int InterfaceId,
+        const PEC_InitBlock_t * const InitBlock_p)
+{
+    Device_Handle_t CDR_Device, RDR_Device;
+    EIP202_Ring_Error_t res;
+    DMAResource_AddrPair_t PhysAddr_Pair;
+    unsigned int CDWordCount, RDWordCount; // Command and Result Descriptor size
+    unsigned int CDOffset, RDOffset; // Command and Result Descriptor Offsets
+    unsigned int RDTokenOffsWordCount;
+
+    IDENTIFIER_NOT_USED(InitBlock_p);
+
+    LOG_INFO("\n\t\t Adapter_PECDev_Init \n");
+
+    if (ADAPTER_EIP202_DEVICE_COUNT > ADAPTER_EIP202_DEVICE_COUNT_ACTUAL)
+    {
+        LOG_CRIT("Adapter_PECDev_Init: "
+                 "Adapter EIP-202 devices configuration is invalid\n");
+        return PEC_ERROR_BAD_PARAMETER;
+    }
+
+    if (InterfaceId >= ADAPTER_EIP202_DEVICE_COUNT)
+        return PEC_ERROR_BAD_PARAMETER;
+
+    CDR_Device = Device_Find(EIP202_Devices[InterfaceId].CDR_DeviceName_p);
+    RDR_Device = Device_Find(EIP202_Devices[InterfaceId].RDR_DeviceName_p);
+
+    if (CDR_Device == NULL || RDR_Device == NULL)
+        return PEC_ERROR_INTERNAL;
+    EIP202_ContinuousScatter[InterfaceId] = InitBlock_p->fContinuousScatter;
+
+    LOG_INFO("\n\t\t\t EIP202_CDR_Reset \n");
+
+    // Reset both the CDR and RDR devives.
+    res = EIP202_CDR_Reset(CDR_IOArea + InterfaceId, CDR_Device);
+    if (res != EIP202_RING_NO_ERROR)
+        return PEC_ERROR_INTERNAL;
+
+    LOG_INFO("\n\t\t\t EIP202_RDR_Reset \n");
+
+    res = EIP202_RDR_Reset(RDR_IOArea + InterfaceId, RDR_Device);
+    if (res != EIP202_RING_NO_ERROR)
+        return PEC_ERROR_INTERNAL;
+
+    // Determine the DMA buffer allocation alignment
+    if (!AdapterLib_Ring_EIP202_DMA_Alignment_Determine())
+        return PEC_ERROR_INTERNAL;
+
+#ifdef ADAPTER_EIP202_RING_LOCAL_CONFIGURE
+    // Configure the EIP-202 Ring Managers with configuration
+    // parameters obtained from local CDR device.
+    {
+      EIP202_Ring_Options_t options;
+
+      res = EIP202_CDR_Options_Get(CDR_Device, &options);
+      if (res != EIP202_RING_NO_ERROR)
+      {
+          LOG_CRIT("%s: EIP202_CDR_Options_Get failed, error %d\n",
+                   __func__,
+                   res);
+          return PEC_ERROR_INTERNAL;
+      }
+      Adapter_Ring_EIP202_Configure(options.HDW,
+                                    options.CF_Size,
+                                    options.RF_Size);
+    }
+#endif
+    // Determine required command and result descriptor size and offset
+    {
+        unsigned int ByteCount;
+
+        CDWordCount = EIP202_CD_CTRL_DATA_MAX_WORD_COUNT +
+                                            IOToken_InWordCount_Get();
+        ByteCount = MAX(AdapterLib_Ring_EIP202_DMA_Alignment_Get(),
+                        ADAPTER_EIP202_CD_OFFSET_BYTE_COUNT);
+        ByteCount = AdapterLib_Ring_EIP202_AlignForSize(
+                                CDWordCount * sizeof(uint32_t),
+                                ByteCount);
+        CDOffset = ByteCount / sizeof(uint32_t);
+
+        LOG_CRIT("%s: EIP-202 CD size/offset %d/%d (32-bit words)\n",
+                 __func__,
+                 CDWordCount,
+                 CDOffset);
+
+        if (Adapter_Ring_EIP202_HDW == 3)
+        {
+            RDTokenOffsWordCount = 8;
+        }
+        else
+        {
+            RDTokenOffsWordCount = EIP202_RD_CTRL_DATA_MAX_WORD_COUNT;
+        }
+        RDWordCount = RDTokenOffsWordCount +
+                                            IOToken_OutWordCount_Get();
+        ByteCount = MAX(AdapterLib_Ring_EIP202_DMA_Alignment_Get(),
+                        ADAPTER_EIP202_RD_OFFSET_BYTE_COUNT);
+        ByteCount = AdapterLib_Ring_EIP202_AlignForSize(
+                                RDWordCount * sizeof(uint32_t),
+                                ByteCount);
+        RDOffset = ByteCount / sizeof(uint32_t);
+
+        LOG_CRIT("%s: EIP-202 RD size/offset %d/%d (32-bit words)\n",
+                 __func__,
+                 RDWordCount,
+                 RDOffset);
+
+#ifndef ADAPTER_EIP202_SEPARATE_RINGS
+        {
+            unsigned int RDMaxTokenWordCount = RDOffset -
+                                           EIP202_RD_CTRL_DATA_MAX_WORD_COUNT;
+
+            if (CDWordCount > RDMaxTokenWordCount)
+            {
+                LOG_CRIT("%s: failed, EIP-202 CD (%d 32-bit words) "
+                         "exceeds max RD token space (%d 32-bit words)\n",
+                         __func__,
+                         CDWordCount,
+                         RDMaxTokenWordCount);
+                return PEC_ERROR_INTERNAL;
+            }
+        }
+#endif
+    }
+
+#ifdef ADAPTER_EIP202_DMARESOURCE_BANKS_ENABLE
+#ifdef ADAPTER_EIP202_RC_DMA_BANK_SUPPORT
+#ifdef ADAPTER_EIP202_USE_SHDEVXS
+    {
+        void *SABaseAddr;
+
+        SHDevXS_DMAPool_GetBase(&SABaseAddr);
+
+        LOG_INFO("Adapter_PECDev_Init: got SA base %p\n",SABaseAddr);
+
+        Adapter_AddrToWordPair(SABaseAddr,
+                               0,
+                               &EIP202_SABaseAddr,
+                               &EIP202_SABaseUpperAddr);
+    }
+#else
+    { // Set the SA pool base address.
+        int dmares;
+        Device_Handle_t Device;
+        DMAResource_Handle_t DMAHandle;
+        DMAResource_Properties_t DMAProperties;
+        DMAResource_AddrPair_t DMAAddr;
+
+        // Perform a dummy allocation in bank 1 to obtain the pool base
+        // address.
+        DMAProperties.Alignment = AdapterLib_Ring_EIP202_DMA_Alignment_Get();
+        DMAProperties.Bank      = ADAPTER_EIP202_BANK_SA;
+        DMAProperties.fCached   = false;
+        DMAProperties.Size      = ADAPTER_EIP202_TRANSFORM_RECORD_COUNT *
+                                    ADAPTER_EIP202_TRANSFORM_RECORD_BYTE_COUNT;
+
+        dmares = DMAResource_Alloc(DMAProperties, &DMAAddr, &DMAHandle);
+        if (dmares != 0)
+            return PEC_ERROR_INTERNAL;
+
+        // Derive the physical address from the DMA resource.
+        if (DMAResource_Translate(DMAHandle,
+                                  DMARES_DOMAIN_BUS,
+                                  &DMAAddr) < 0)
+        {
+            DMAResource_Release(DMAHandle);
+            return PEC_ERROR_INTERNAL;
+        }
+
+        Adapter_AddrToWordPair(DMAAddr.Address_p,
+                               0,
+                               &EIP202_SABaseAddr,
+                               &EIP202_SABaseUpperAddr);
+
+        // Set the cache base address.
+        Device = Device_Find(ADAPTER_EIP202_GLOBAL_DEVICE_NAME);
+        if (Device == NULL)
+        {
+            LOG_CRIT("Adapter_PECDev_UnInit: Could not find device\n");
+            return PEC_ERROR_INTERNAL;
+        }
+
+        LOG_INFO("\n\t\t\t EIP207_RC_BaseAddr_Set \n");
+
+        EIP207_RC_BaseAddr_Set(
+            Device,
+            EIP207_TRC_REG_BASE,
+            EIP207_RC_SET_NR_DEFAULT,
+            EIP202_SABaseAddr,
+            EIP202_SABaseUpperAddr);
+
+        // Release the DMA resource.
+        DMAResource_Release(DMAHandle);
+    }
+#endif // ADAPTER_EIP202_USE_SHDEVXS
+#endif // ADAPTER_EIP202_RC_DMA_BANK_SUPPORT
+#endif // ADAPTER_EIP202_DMARESOURCE_BANKS_ENABLE
+
+    // Allocate the ring buffers(s).
+    {
+        int dmares;
+#ifdef ADAPTER_EIP202_SEPARATE_RINGS
+        unsigned int CDRByteCount = 4 * ADAPTER_EIP202_MAX_PACKETS * CDOffset;
+        unsigned int RDRByteCount = 4 * ADAPTER_EIP202_MAX_PACKETS * RDOffset;
+#else
+        unsigned int RDRByteCount = 4 * ADAPTER_EIP202_MAX_PACKETS * CDOffset +
+                                                ADAPTER_EIP202_CDR_BYTE_OFFSET;
+#endif
+
+        DMAResource_Properties_t RingProperties;
+        DMAResource_AddrPair_t RingHostAddr;
+
+        // used as uint32_t array
+        RingProperties.Alignment = AdapterLib_Ring_EIP202_DMA_Alignment_Get();
+        RingProperties.Bank      = ADAPTER_EIP202_BANK_RING;
+        RingProperties.fCached   = false;
+        RingProperties.Size      = RDRByteCount;
+
+        dmares = DMAResource_Alloc(RingProperties,
+                                   &RingHostAddr,
+                                   RDR_Handle + InterfaceId);
+        if (dmares != 0)
+            return PEC_ERROR_INTERNAL;
+
+#ifdef ADAPTER_EIP202_ARMRING_ENABLE_SWAP
+        DMAResource_SwapEndianness_Set(RDR_Handle[InterfaceId],true);
+#endif
+
+        memset (RingHostAddr.Address_p, 0, RDRByteCount);
+
+#ifdef ADAPTER_EIP202_SEPARATE_RINGS
+
+        RingProperties.Size = CDRByteCount;
+
+        dmares = DMAResource_Alloc(RingProperties,
+                                   &RingHostAddr,
+                                   CDR_Handle + InterfaceId);
+        if (dmares != 0)
+        {
+            DMAResource_Release(RDR_Handle[InterfaceId]);
+            return PEC_ERROR_INTERNAL;
+        }
+
+#ifdef ADAPTER_EIP202_ARMRING_ENABLE_SWAP
+        DMAResource_SwapEndianness_Set(CDR_Handle[InterfaceId], true);
+#endif
+
+        memset (RingHostAddr.Address_p, 0, CDRByteCount);
+
+#else
+        RingProperties.Size -= ADAPTER_EIP202_CDR_BYTE_OFFSET;
+        RingProperties.fCached = false;
+
+        {
+            uint8_t * Byte_p = (uint8_t*)RingHostAddr.Address_p;
+
+            Byte_p += ADAPTER_EIP202_CDR_BYTE_OFFSET;
+
+            RingHostAddr.Address_p = Byte_p;
+        }
+
+        dmares = DMAResource_CheckAndRegister(RingProperties,
+                                              RingHostAddr,
+                                              'R',
+                                              CDR_Handle + InterfaceId);
+        if (dmares != 0)
+        {
+            DMAResource_Release(RDR_Handle[InterfaceId]);
+            return PEC_ERROR_INTERNAL;
+        }
+
+#ifdef ADAPTER_EIP202_ARMRING_ENABLE_SWAP
+        DMAResource_SwapEndianness_Set(CDR_Handle[InterfaceId], true);
+#endif
+
+#endif
+
+        LOG_CRIT("%s: CDR/RDR byte count %d/%d, %s, CDR offset %d bytes\n",
+                 __func__,
+#ifdef ADAPTER_EIP202_SEPARATE_RINGS
+                 CDRByteCount,
+                 RDRByteCount,
+                 "non-overlapping",
+                 0);
+#else
+                 0,
+                 RDRByteCount,
+                 "overlapping",
+                 (int)ADAPTER_EIP202_CDR_BYTE_OFFSET);
+#endif
+    }
+
+    // Initialize the CDR and RDR devices
+    {
+        ZEROINIT(CDR_Settings);
+
+#ifdef ADAPTER_EIP202_RING_MANUAL_CONFIGURE
+        // Configure the EIP-202 Ring Managers with manually set
+        // configuration parameters
+        Adapter_Ring_EIP202_Configure(ADAPTER_EIP202_HOST_DATA_WIDTH,
+                                      ADAPTER_EIP202_CF_SIZE,
+                                      ADAPTER_EIP202_RF_SIZE);
+#endif
+
+        CDR_Settings.fATP        = (ADAPTER_EIP202_CDR_ATP_PRESENT > 0) ?
+                                                                true : false;
+        CDR_Settings.fATPtoToken = false;
+
+        CDR_Settings.Params.DataBusWidthWordCount = 1;
+
+        // Not used for CDR
+        CDR_Settings.Params.ByteSwap_DataType_Mask      = 0;
+        CDR_Settings.Params.ByteSwap_Packet_Mask        = 0;
+
+        // Enable endianess conversion for the RDR master interface
+        // if configured
+#ifdef ADAPTER_EIP202_CDR_BYTE_SWAP_ENABLE
+        CDR_Settings.Params.ByteSwap_Token_Mask         =
+        CDR_Settings.Params.ByteSwap_Descriptor_Mask    =
+                                            EIP202_RING_BYTE_SWAP_METHOD_32;
+#else
+        CDR_Settings.Params.ByteSwap_Token_Mask         = 0;
+        CDR_Settings.Params.ByteSwap_Descriptor_Mask    = 0;
+#endif
+
+        CDR_Settings.Params.Bufferability = 0;
+#ifdef ADAPTER_EIP202_64BIT_DEVICE
+        CDR_Settings.Params.DMA_AddressMode = EIP202_RING_64BIT_DMA_DSCR_PTR;
+#else
+        CDR_Settings.Params.DMA_AddressMode = EIP202_RING_64BIT_DMA_DISABLED;
+#endif
+        CDR_Settings.Params.RingSizeWordCount =
+                                        CDOffset * ADAPTER_EIP202_MAX_PACKETS;
+        CDR_Settings.Params.RingDMA_Handle = CDR_Handle[InterfaceId];
+
+#ifdef ADAPTER_EIP202_SEPARATE_RINGS
+        if (DMAResource_Translate(CDR_Handle[InterfaceId], DMARES_DOMAIN_BUS,
+                                  &PhysAddr_Pair) < 0)
+        {
+            Adapter_PECDev_UnInit(InterfaceId);
+            return PEC_ERROR_INTERNAL;
+        }
+        Adapter_AddrToWordPair(PhysAddr_Pair.Address_p, 0,
+                               &CDR_Settings.Params.RingDMA_Address.Addr,
+                               &CDR_Settings.Params.RingDMA_Address.UpperAddr);
+#else
+        if (DMAResource_Translate(RDR_Handle[InterfaceId], DMARES_DOMAIN_BUS,
+                                  &PhysAddr_Pair) < 0)
+        {
+            Adapter_PECDev_UnInit(InterfaceId);
+            return PEC_ERROR_INTERNAL;
+        }
+        Adapter_AddrToWordPair(PhysAddr_Pair.Address_p,
+                               ADAPTER_EIP202_CDR_BYTE_OFFSET,
+                               &CDR_Settings.Params.RingDMA_Address.Addr,
+                               &CDR_Settings.Params.RingDMA_Address.UpperAddr);
+#endif
+
+        CDR_Settings.Params.DscrSizeWordCount = CDWordCount;
+        CDR_Settings.Params.DscrOffsWordCount = CDOffset;
+
+#ifndef ADAPTER_EIP202_AUTO_THRESH_DISABLE
+        if(Adapter_Ring_EIP202_Configured)
+        {
+            uint32_t cd_size_rndup;
+            int cfcount;
+
+            // Use configuration parameters received via
+            // the Ring 97 Configuration (adapter_ring_eip202.h) interface
+            if(CDR_Settings.Params.DscrOffsWordCount &
+                    ((1 << Adapter_Ring_EIP202_HDW) - 1))
+            {
+                LOG_CRIT("Adapter_PECDev_Init: Error, "
+                         "Command Descriptor Offset %d"
+                         " is not an integer multiple of Host Data Width %d\n",
+                         CDR_Settings.Params.DscrOffsWordCount,
+                         Adapter_Ring_EIP202_HDW);
+
+                Adapter_PECDev_UnInit(InterfaceId);
+                return PEC_ERROR_INTERNAL;
+            }
+
+            // Round up to the next multiple of HDW words
+            cd_size_rndup = (CDR_Settings.Params.DscrOffsWordCount +
+                                ((1 << Adapter_Ring_EIP202_HDW) - 1)) >>
+                                         Adapter_Ring_EIP202_HDW;
+
+            // Half of number of full descriptors that fit FIFO
+            // Note: Adapter_Ring_EIP202_CFSize is in HDW words
+            cfcount = (1<<(Adapter_Ring_EIP202_CFSize-1)) / cd_size_rndup;
+
+            // Check if command descriptor fits in fetch FIFO
+            if(cfcount <= 0)
+                cfcount = 1; // does not fit, adjust the count
+
+            // Note: cfcount must be also checked for not exceeding
+            //       max DMA length
+
+            // Convert to 32-bits word counts
+            CDR_Settings.Params.DscrFetchSizeWordCount =
+                (cfcount-1)* (cd_size_rndup << Adapter_Ring_EIP202_HDW);
+            CDR_Settings.Params.DscrThresholdWordCount =
+                     cfcount * (cd_size_rndup << Adapter_Ring_EIP202_HDW);
+        }
+        else
+#endif // #ifndef ADAPTER_EIP202_AUTO_THRESH_DISABLE
+        {
+            // Use default static (user-defined) configuration parameters
+#ifdef ADAPTER_EIP202_CDR_DSCR_FETCH_WORD_COUNT
+            CDR_Settings.Params.DscrFetchSizeWordCount =
+                                    ADAPTER_EIP202_CDR_DSCR_FETCH_WORD_COUNT;
+#else
+            CDR_Settings.Params.DscrFetchSizeWordCount = CDOffset;
+#endif
+            CDR_Settings.Params.DscrThresholdWordCount =
+                                    ADAPTER_EIP202_CDR_DSCR_THRESH_WORD_COUNT;
+        }
+
+        LOG_CRIT("Adapter_PECDev_Init: CDR fetch size %d, threshold %d, "
+                 "HDW=%d, CFsize=%d\n",
+                 CDR_Settings.Params.DscrFetchSizeWordCount,
+                 CDR_Settings.Params.DscrThresholdWordCount,
+                 Adapter_Ring_EIP202_HDW,
+                 Adapter_Ring_EIP202_CFSize);
+
+        // CDR Interrupts will be enabled via the Event Mgmt API functions
+        CDR_Settings.Params.IntThresholdDscrCount = 0;
+        CDR_Settings.Params.IntTimeoutDscrCount = 0;
+        if ((CDR_Settings.Params.DscrFetchSizeWordCount /
+             CDR_Settings.Params.DscrOffsWordCount) >
+            (CDR_Settings.Params.DscrThresholdWordCount /
+             CDR_Settings.Params.DscrSizeWordCount))
+        {
+            LOG_CRIT("Adapter_PECDev_Init: CDR Threshold lower than fetch size"
+                     " incorrect setting\n");
+            Adapter_PECDev_UnInit(InterfaceId);
+            return PEC_ERROR_BAD_PARAMETER;
+        }
+
+
+        LOG_INFO("\n\t\t\t EIP202_CDR_Init \n");
+
+        res = EIP202_CDR_Init(CDR_IOArea + InterfaceId,
+                              CDR_Device,
+                              &CDR_Settings);
+        if (res != EIP202_RING_NO_ERROR)
+        {
+            Adapter_PECDev_UnInit(InterfaceId);
+            return PEC_ERROR_INTERNAL;
+        }
+    }
+
+    {
+        ZEROINIT(RDR_Settings);
+
+        RDR_Settings.Params.DataBusWidthWordCount = 1;
+
+        // Not used for RDR
+        RDR_Settings.Params.ByteSwap_DataType_Mask = 0;
+        RDR_Settings.Params.ByteSwap_Token_Mask = 0;
+
+        RDR_Settings.fContinuousScatter = InitBlock_p->fContinuousScatter;
+
+        // Enable endianess conversion for the RDR master interface
+        // if configured
+        RDR_Settings.Params.ByteSwap_Packet_Mask        = 0;
+#ifdef ADAPTER_EIP202_RDR_BYTE_SWAP_ENABLE
+        RDR_Settings.Params.ByteSwap_Descriptor_Mask    =
+                                            EIP202_RING_BYTE_SWAP_METHOD_32;
+#else
+        RDR_Settings.Params.ByteSwap_Descriptor_Mask    = 0;
+#endif
+
+        RDR_Settings.Params.Bufferability = 0;
+
+#ifdef ADAPTER_EIP202_64BIT_DEVICE
+        RDR_Settings.Params.DMA_AddressMode = EIP202_RING_64BIT_DMA_DSCR_PTR;
+#else
+        RDR_Settings.Params.DMA_AddressMode = EIP202_RING_64BIT_DMA_DISABLED;
+#endif
+
+        RDR_Settings.Params.RingSizeWordCount =
+                                    RDOffset * ADAPTER_EIP202_MAX_PACKETS;
+
+        RDR_Settings.Params.RingDMA_Handle = RDR_Handle[InterfaceId];
+
+        if (DMAResource_Translate(RDR_Handle[InterfaceId], DMARES_DOMAIN_BUS,
+                                  &PhysAddr_Pair) < 0)
+        {
+            Adapter_PECDev_UnInit(InterfaceId);
+            return PEC_ERROR_INTERNAL;
+        }
+        Adapter_AddrToWordPair(PhysAddr_Pair.Address_p, 0,
+                               &RDR_Settings.Params.RingDMA_Address.Addr,
+                               &RDR_Settings.Params.RingDMA_Address.UpperAddr);
+
+        RDR_Settings.Params.DscrSizeWordCount = RDWordCount;
+        RDR_Settings.Params.DscrOffsWordCount = RDOffset;
+        RDR_Settings.Params.TokenOffsetWordCount = RDTokenOffsWordCount;
+
+#ifndef ADAPTER_EIP202_AUTO_THRESH_DISABLE
+        if(Adapter_Ring_EIP202_Configured)
+        {
+            uint32_t rd_size_rndup;
+            int rfcount;
+
+            // Use configuration parameters received via
+            // the Ring 97 Configuration (adapter_ring_eip202.h) interface
+            if(RDR_Settings.Params.DscrOffsWordCount &
+                    ((1 << Adapter_Ring_EIP202_HDW) - 1))
+            {
+                LOG_CRIT("Adapter_PECDev_Init: Error, "
+                         "Result Descriptor Offset %d"
+                         " is not an integer multiple of Host Data Width %d\n",
+                         RDR_Settings.Params.DscrOffsWordCount,
+                         Adapter_Ring_EIP202_HDW);
+
+                Adapter_PECDev_UnInit(InterfaceId);
+                return PEC_ERROR_INTERNAL;
+            }
+
+            // Round up to the next multiple of HDW words
+            rd_size_rndup = (RDR_Settings.Params.DscrOffsWordCount +
+                                ((1 << Adapter_Ring_EIP202_HDW) - 1)) >>
+                                         Adapter_Ring_EIP202_HDW;
+
+            // Half of number of full descriptors that fit FIFO
+            // Note: Adapter_Ring_EIP202_RFSize is in HDW words
+            rfcount = (1 << (Adapter_Ring_EIP202_RFSize - 1)) / rd_size_rndup;
+
+            // Check if prepared result descriptor fits in fetch FIFO
+            if(rfcount <= 0)
+                rfcount = 1; // does not fit, adjust the count
+
+            // Note: rfcount must be also checked for not exceeding
+            //       max DMA length
+
+            // Convert to 32-bit words counts
+            RDR_Settings.Params.DscrFetchSizeWordCount =
+                (rfcount - 1) * (rd_size_rndup << Adapter_Ring_EIP202_HDW);
+            RDR_Settings.Params.DscrThresholdWordCount =
+                     rfcount * (rd_size_rndup << Adapter_Ring_EIP202_HDW);
+        }
+        else
+#endif // #ifndef ADAPTER_EIP202_AUTO_THRESH_DISABLE
+        {
+            // Use default static (user-defined) configuration parameters
+            RDR_Settings.Params.DscrFetchSizeWordCount =
+                                    ADAPTER_EIP202_RDR_DSCR_FETCH_WORD_COUNT;
+            RDR_Settings.Params.DscrThresholdWordCount =
+                                    ADAPTER_EIP202_RDR_DSCR_THRESH_WORD_COUNT;
+        }
+
+        LOG_CRIT("Adapter_PECDev_Init: RDR fetch size %d, threshold %d, "
+                 "RFsize=%d\n",
+                 RDR_Settings.Params.DscrFetchSizeWordCount,
+                 RDR_Settings.Params.DscrThresholdWordCount,
+                 Adapter_Ring_EIP202_RFSize);
+
+        // RDR Interrupts will be enabled via the Event Mgmt API functions
+        RDR_Settings.Params.IntThresholdDscrCount = 0;
+        RDR_Settings.Params.IntTimeoutDscrCount = 0;
+
+        if ((RDR_Settings.Params.DscrFetchSizeWordCount /
+             RDR_Settings.Params.DscrOffsWordCount) >
+            (RDR_Settings.Params.DscrThresholdWordCount /
+#ifdef ADAPTER_EIP202_64BIT_DEVICE
+             4 /* RDR prepared descriptor size for 64-bit */
+#else
+             2 /* RDR prepared descriptor size for 32-bit */
+#endif
+                ))
+        {
+            LOG_CRIT("Adapter_PECDev_Init: RDR Threshold lower than fetch size"
+                     " incorrect setting\n");
+            Adapter_PECDev_UnInit(InterfaceId);
+            return PEC_ERROR_BAD_PARAMETER;
+        }
+        LOG_INFO("\n\t\t\t EIP202_RDR_Init \n");
+
+        res = EIP202_RDR_Init(RDR_IOArea + InterfaceId,
+                              RDR_Device,
+                              &RDR_Settings);
+        if (res != EIP202_RING_NO_ERROR)
+        {
+            Adapter_PECDev_UnInit(InterfaceId);
+            return PEC_ERROR_INTERNAL;
+        }
+    }
+
+    if (!AdapterLib_RD_OutTokens_Alloc(InterfaceId))
+    {
+        LOG_CRIT("Adapter_PECDev_Init: failed to allocate output tokens\n");
+        Adapter_PECDev_UnInit(InterfaceId);
+        return PEC_ERROR_INTERNAL; // Out of memory
+    }
+
+    AdapterLib_Ring_EIP202_Status_Report(InterfaceId);
+
+#ifdef ADAPTER_EIP202_ADD_INIT_DIAGNOSTICS
+    Adapter_Register_Dump();
+#endif
+
+    return PEC_STATUS_OK;
+}
+
+
+/*----------------------------------------------------------------------------
+ * Adapter_PECDev_UnInit
+ */
+PEC_Status_t
+Adapter_PECDev_UnInit(
+        const unsigned int InterfaceId)
+{
+    Device_Handle_t CDR_Device, RDR_Device;
+
+    LOG_INFO("\n\t\t Adapter_PECDev_UnInit \n");
+
+    if (InterfaceId >= ADAPTER_EIP202_DEVICE_COUNT)
+        return PEC_ERROR_BAD_PARAMETER;
+
+    AdapterLib_Ring_EIP202_Status_Report(InterfaceId);
+
+#ifdef ADAPTER_EIP202_ENABLE_SCATTERGATHER
+    {
+        // Make a last attempt to get rid of any remaining result descriptors
+        // belonging to unused scatter particles.
+        uint32_t DscrDoneCount,DscrCount;
+
+        LOG_INFO("\n\t\t\t EIP202_RDR_Descriptor_Get \n");
+
+        EIP202_RDR_Descriptor_Get(RDR_IOArea + InterfaceId,
+                                 EIP202_RDR_Entries[InterfaceId],
+                                 ADAPTER_EIP202_MAX_LOGICDESCR,
+                                 ADAPTER_EIP202_MAX_LOGICDESCR,
+                                 &DscrDoneCount,
+                                 &DscrCount);
+    }
+#endif
+
+    AdapterLib_RD_OutTokens_Free(InterfaceId);
+
+#ifdef ADAPTER_EIP202_RC_DMA_BANK_SUPPORT
+#ifndef ADAPTER_EIP202_USE_SHDEVXS
+    {
+        // Reset the TRC base address to 0.
+        Device_Handle_t Device;
+
+        Device = Device_Find(ADAPTER_EIP202_GLOBAL_DEVICE_NAME);
+        if (Device == NULL)
+        {
+            LOG_CRIT("Adapter_PECDev_UnInit: Could not find device\n");
+            return PEC_ERROR_INTERNAL;
+        }
+
+        LOG_INFO("\n\t\t\t EIP207_RC_BaseAddr_Set \n");
+
+        EIP207_RC_BaseAddr_Set(
+            Device,
+            EIP207_TRC_REG_BASE,
+            EIP207_RC_SET_NR_DEFAULT,
+            0,
+            0);
+    }
+#endif
+#endif // ADAPTER_EIP202_RC_DMA_BANK_SUPPORT
+
+    CDR_Device = Device_Find(EIP202_Devices[InterfaceId].CDR_DeviceName_p);
+    RDR_Device = Device_Find(EIP202_Devices[InterfaceId].RDR_DeviceName_p);
+
+    if (CDR_Device == NULL || RDR_Device == NULL)
+        return PEC_ERROR_INTERNAL;
+
+    LOG_INFO("\n\t\t\t EIP202_CDR_Reset \n");
+
+    EIP202_CDR_Reset(CDR_IOArea + InterfaceId,
+                    CDR_Device);
+
+    LOG_INFO("\n\t\t\t EIP202_RDR_Reset \n");
+
+    EIP202_RDR_Reset(RDR_IOArea + InterfaceId,
+                    RDR_Device);
+
+    if (RDR_Handle[InterfaceId] != NULL)
+    {
+        DMAResource_Release(RDR_Handle[InterfaceId]);
+        RDR_Handle[InterfaceId] = NULL;
+    }
+
+    if (CDR_Handle[InterfaceId] != NULL)
+    {
+        DMAResource_Release(CDR_Handle[InterfaceId]);
+        CDR_Handle[InterfaceId] = NULL;
+    }
+
+#ifdef ADAPTER_EIP202_INTERRUPTS_ENABLE
+    Adapter_Interrupt_SetHandler(EIP202_Devices[InterfaceId].RDR_IRQ_ID, NULL);
+    Adapter_Interrupt_SetHandler(EIP202_Devices[InterfaceId].CDR_IRQ_ID, NULL);
+#endif
+
+    return PEC_STATUS_OK;
+}
+
+
+/*----------------------------------------------------------------------------
+ * Adapter_PECDev_Resume
+ */
+int
+Adapter_PECDev_Resume(
+        const unsigned int InterfaceId)
+{
+    EIP202_Ring_Error_t res;
+
+    LOG_INFO("\n\t\t %s \n", __func__);
+
+    LOG_INFO("\n\t\t\t EIP202_CDR_Init \n");
+    // Restore EIP-202 CDR
+    res = EIP202_CDR_Init(CDR_IOArea + InterfaceId,
+                          Device_Find(EIP202_Devices[InterfaceId].CDR_DeviceName_p),
+                          &CDR_Settings);
+    if (res != EIP202_RING_NO_ERROR)
+    {
+        LOG_CRIT("%s: EIP202_CDR_Init() error %d", __func__, res);
+        return -1;
+    }
+
+    LOG_INFO("\n\t\t\t EIP202_RDR_Init \n");
+    // Restore EIP-202 RDR
+    res = EIP202_RDR_Init(RDR_IOArea + InterfaceId,
+                          Device_Find(EIP202_Devices[InterfaceId].RDR_DeviceName_p),
+                          &RDR_Settings);
+    if (res != EIP202_RING_NO_ERROR)
+    {
+        LOG_CRIT("%s: EIP202_CDR_Init() error %d", __func__, res);
+        return -2;
+    }
+
+#ifdef ADAPTER_EIP202_DMARESOURCE_BANKS_ENABLE
+#ifdef ADAPTER_EIP202_RC_DMA_BANK_SUPPORT
+#ifndef ADAPTER_EIP202_USE_SHDEVXS
+    LOG_INFO("\n\t\t\t EIP207_RC_BaseAddr_Set \n");
+    // Restore EIP-207 Record Cache base address
+    EIP207_RC_BaseAddr_Set(
+        Device_Find(ADAPTER_EIP202_GLOBAL_DEVICE_NAME),
+        EIP207_TRC_REG_BASE,
+        EIP207_RC_SET_NR_DEFAULT,
+        EIP202_SABaseAddr,
+        EIP202_SABaseUpperAddr);
+#endif
+#endif // ADAPTER_EIP202_RC_DMA_BANK_SUPPORT
+#endif // ADAPTER_EIP202_DMARESOURCE_BANKS_ENABLE
+
+#ifdef ADAPTER_EIP202_INTERRUPTS_ENABLE
+#ifndef ADAPTER_EIP202_USE_SHDEVXS
+    // Restore RDR interrupt
+    if (EIP202_Interrupts[InterfaceId] & BIT_0)
+        Adapter_PECDev_Enable_ResultIRQ(InterfaceId);
+
+    // Restore CDR interrupt
+    if (EIP202_Interrupts[InterfaceId] & BIT_1)
+        Adapter_PECDev_Enable_CommandIRQ(InterfaceId);
+#endif // ADAPTER_EIP202_USE_SHDEVXS
+#endif // ADAPTER_EIP202_INTERRUPTS_ENABLE
+
+    return 0; // success
+}
+
+
+/*----------------------------------------------------------------------------
+ * Adapter_PECDev_Suspend
+ */
+int
+Adapter_PECDev_Suspend(
+        const unsigned int InterfaceId)
+{
+    LOG_INFO("\n\t\t %s \n", __func__);
+
+#ifdef ADAPTER_EIP202_INTERRUPTS_ENABLE
+#ifndef ADAPTER_EIP202_USE_SHDEVXS
+    // Disable RDR interrupt
+    if (EIP202_Interrupts[InterfaceId] & BIT_0)
+    {
+        Adapter_PECDev_Disable_ResultIRQ(InterfaceId);
+
+        // Remember that interrupt was enabled
+        EIP202_Interrupts[InterfaceId] |= BIT_0;
+    }
+
+    // Disable CDR interrupt
+    if (EIP202_Interrupts[InterfaceId] & BIT_1)
+    {
+        Adapter_PECDev_Disable_CommandIRQ(InterfaceId);
+
+        // Remember that interrupt was enabled
+        EIP202_Interrupts[InterfaceId] |= BIT_1;
+    }
+#endif // ADAPTER_EIP202_USE_SHDEVXS
+#endif // ADAPTER_EIP202_INTERRUPTS_ENABLE
+
+#ifdef ADAPTER_EIP202_RC_DMA_BANK_SUPPORT
+#ifndef ADAPTER_EIP202_USE_SHDEVXS
+    {
+        LOG_INFO("\n\t\t\t EIP207_RC_BaseAddr_Set \n");
+
+        // Reset the TRC base address to 0
+        EIP207_RC_BaseAddr_Set(
+            Device_Find(ADAPTER_EIP202_GLOBAL_DEVICE_NAME),
+            EIP207_TRC_REG_BASE,
+            EIP207_RC_SET_NR_DEFAULT,
+            0,
+            0);
+    }
+#endif
+#endif // ADAPTER_EIP202_RC_DMA_BANK_SUPPORT
+
+    LOG_INFO("\n\t\t\t EIP202_CDR_Reset \n");
+
+    EIP202_CDR_Reset(CDR_IOArea + InterfaceId,
+                     Device_Find(EIP202_Devices[InterfaceId].CDR_DeviceName_p));
+
+    LOG_INFO("\n\t\t\t EIP202_RDR_Reset \n");
+
+    EIP202_RDR_Reset(RDR_IOArea + InterfaceId,
+                     Device_Find(EIP202_Devices[InterfaceId].RDR_DeviceName_p));
+
+    return 0; // success
+}
+
+
+/*----------------------------------------------------------------------------
+ * Adapter_PECDev_SA_Prepare
+ */
+PEC_Status_t
+Adapter_PECDev_SA_Prepare(
+        const DMABuf_Handle_t SAHandle,
+        const DMABuf_Handle_t StateHandle,
+        const DMABuf_Handle_t ARC4Handle)
+{
+    DMAResource_Handle_t SA_DMAHandle;
+
+    IDENTIFIER_NOT_USED(StateHandle.p);
+    IDENTIFIER_NOT_USED(ARC4Handle.p);
+
+    if (DMABuf_Handle_IsSame(&SAHandle, &DMABuf_NULLHandle))
+        return PEC_ERROR_BAD_PARAMETER;
+    else
+    {
+        DMAResource_Record_t * Rec_p;
+
+        SA_DMAHandle = Adapter_DMABuf_Handle2DMAResourceHandle(SAHandle);
+        Rec_p = DMAResource_Handle2RecordPtr(SA_DMAHandle);
+
+        if (Rec_p == NULL)
+            return PEC_ERROR_INTERNAL;
+
+#ifdef ADAPTER_EIP202_DMARESOURCE_BANKS_ENABLE
+        if (Rec_p->Props.Bank != ADAPTER_EIP202_BANK_SA)
+        {
+            LOG_CRIT("PEC_SA_Register: Invalid bank for SA\n");
+            return PEC_ERROR_BAD_PARAMETER;
+        }
+#endif
+
+#ifndef ADAPTER_EIP202_USE_LARGE_TRANSFORM_DISABLE
+        {
+            uint32_t FirstWord = DMAResource_Read32(SA_DMAHandle, 0);
+            // Register in the DMA resource record whether the transform
+            // is large.
+            if ( (FirstWord & ADAPTER_EIP202_TR_ISLARGE) != 0)
+            {
+                Rec_p->fIsLargeTransform = true;
+                DMAResource_Write32(SA_DMAHandle,
+                                    0,
+                                    FirstWord & ~ADAPTER_EIP202_TR_ISLARGE);
+                // Clear that bit in the SA record itself.
+            }
+            else
+            {
+                Rec_p->fIsLargeTransform = false;
+            }
+        }
+#endif
+
+        Rec_p->fIsNewSA = true;
+    }
+
+    return PEC_STATUS_OK;
+}
+
+
+/*----------------------------------------------------------------------------
+ * Adapter_PECDev_SA_Remove
+ */
+PEC_Status_t
+Adapter_PECDev_SA_Remove(
+        const DMABuf_Handle_t SAHandle,
+        const DMABuf_Handle_t StateHandle,
+        const DMABuf_Handle_t ARC4Handle)
+{
+    IDENTIFIER_NOT_USED(StateHandle.p);
+
+    if (DMABuf_Handle_IsSame(&SAHandle, &DMABuf_NULLHandle))
+        return PEC_ERROR_BAD_PARAMETER;
+
+#ifdef ADAPTER_EIP202_RC_DIRECT_INVALIDATE_SUPPORT
+    // Invalidate the record in the EIP-207 Transform Record Cache
+    // or/and ARC4 State Record Cache
+    // Not configured = disabled
+    if (Adapter_RC_EIP207_Configured)
+    {
+#ifndef ADAPTER_EIP202_USE_SHDEVXS
+        Device_Handle_t Device;
+
+        Device = Device_Find(ADAPTER_EIP202_GLOBAL_DEVICE_NAME);
+        if (Device == NULL)
+        {
+            LOG_CRIT("Adapter_PECDev_SA_Remove: Could not find device\n");
+            return PEC_ERROR_INTERNAL;
+        }
+#endif
+
+        if (Adapter_RC_EIP207_TRC_Enabled)
+        {
+            EIP202_DeviceAddress_t DMA_Addr;
+
+            Adapter_GetPhysAddr(SAHandle, &DMA_Addr);
+
+#ifdef ADAPTER_EIP202_DMARESOURCE_BANKS_ENABLE
+            DMA_Addr.Addr -= EIP202_SABaseAddr;
+#endif
+
+            // Invalidate the SA Record in the TRC
+#ifdef ADAPTER_EIP202_USE_SHDEVXS
+            LOG_INFO("\n\t\t\t SHDevXS_TRC_Record_Invalidate \n");
+
+            SHDevXS_TRC_Record_Invalidate(DMA_Addr.Addr);
+#else
+            LOG_INFO("\n\t\t\t EIP207_RC_Record_Update \n");
+
+            EIP207_RC_Record_Update(
+                    Device,
+                    EIP207_TRC_REG_BASE,
+                    EIP207_RC_SET_NR_DEFAULT,
+                    DMA_Addr.Addr,
+                    EIP207_RC_CMD_SET_BITS,
+                    EIP207_RC_REG_DATA_BYTE_OFFSET - 3 * sizeof(uint32_t),
+                    EIP207_RC_HDR_WORD_3_RELOAD_BIT);
+#endif // ADAPTER_EIP202_USE_SHDEVXS
+        }
+
+        if (!DMABuf_Handle_IsSame(&ARC4Handle, &DMABuf_NULLHandle) &&
+            Adapter_RC_EIP207_ARC4RC_Enabled)
+        {
+            EIP202_DeviceAddress_t DMA_Addr;
+
+            Adapter_GetPhysAddr(ARC4Handle, &DMA_Addr);
+
+            // Invalidate the ARC4 State record in the TRC or ARC4RC
+#ifdef ADAPTER_EIP202_USE_SHDEVXS
+            LOG_INFO("\n\t\t\t SHDevXS_ARC4RC_Record_Invalidate \n");
+
+            SHDevXS_ARC4RC_Record_Invalidate(DMA_Addr.Addr);
+#else
+            LOG_INFO("\n\t\t\t EIP207_RC_Record_Update \n");
+
+            EIP207_RC_Record_Update(
+                    Device,
+                    EIP207_ARC4RC_REG_BASE,
+                    EIP207_RC_SET_NR_DEFAULT,
+                    DMA_Addr.Addr,
+                    EIP207_RC_CMD_SET_BITS,
+                    EIP207_RC_REG_DATA_BYTE_OFFSET - 3 * sizeof(uint32_t),
+                    EIP207_RC_HDR_WORD_3_RELOAD_BIT);
+#endif // ADAPTER_EIP202_USE_SHDEVXS
+        }
+    }
+#else
+    IDENTIFIER_NOT_USED(ARC4Handle.p);
+#endif // ADAPTER_EIP202_RC_DIRECT_INVALIDATE_SUPPORT
+
+    return PEC_STATUS_OK;
+}
+
+
+/*----------------------------------------------------------------------------
+ * Adapter_PECDev_GetFreeSpace
+ */
+unsigned int
+Adapter_PECDev_GetFreeSpace(
+        const unsigned int InterfaceId)
+{
+    unsigned int FreeCDR, FreeRDR, FilledCDR, FilledRDR;
+    EIP202_Ring_Error_t res;
+
+    LOG_INFO("\n\t\t Adapter_PECDev_GetFreeSpace \n");
+
+    if (InterfaceId >= ADAPTER_EIP202_DEVICE_COUNT)
+        return PEC_ERROR_BAD_PARAMETER;
+
+    LOG_INFO("\n\t\t\t EIP202_CDR_FillLevel_Get \n");
+
+    res = EIP202_CDR_FillLevel_Get(CDR_IOArea + InterfaceId,
+                                  &FilledCDR);
+    if (res != EIP202_RING_NO_ERROR)
+        return 0;
+
+    if (FilledCDR > ADAPTER_EIP202_MAX_PACKETS)
+        return 0;
+
+    FreeCDR = ADAPTER_EIP202_MAX_PACKETS - FilledCDR;
+
+    if (EIP202_ContinuousScatter[InterfaceId])
+    {
+        return FreeCDR;
+    }
+    else
+    {
+        LOG_INFO("\n\t\t\t EIP202_RDR_FillLevel_Get \n");
+
+        res = EIP202_RDR_FillLevel_Get(RDR_IOArea + InterfaceId,
+                                       &FilledRDR);
+        if (res != EIP202_RING_NO_ERROR)
+            return 0;
+
+        if (FilledRDR > ADAPTER_EIP202_MAX_PACKETS)
+            return 0;
+
+        FreeRDR = ADAPTER_EIP202_MAX_PACKETS - FilledRDR;
+
+        return MIN(FreeCDR, FreeRDR);
+    }
+}
+
+
+/*----------------------------------------------------------------------------
+ * Adapter_PECDev_PacketPut
+ */
+PEC_Status_t
+Adapter_PECDev_Packet_Put(
+        const unsigned int InterfaceId,
+        const PEC_CommandDescriptor_t * Commands_p,
+        const unsigned int CommandsCount,
+        unsigned int * const PutCount_p)
+{
+    unsigned int CmdLp;
+#ifdef ADAPTER_EIP202_STRICT_ARGS
+    unsigned int FreeCDR,FreeRDR;
+#endif
+    unsigned int FilledCDR, FilledRDR, CDRIndex=0, RDRIndex=0;
+    unsigned int Submitted = 0;
+    EIP202_Ring_Error_t res;
+    EIP202_CDR_Control_t CDR_Control;
+    EIP202_RDR_Prepared_Control_t RDR_Control;
+
+    LOG_INFO("\n\t\t Adapter_PECDev_Packet_Put \n");
+
+    *PutCount_p = 0;
+    if (InterfaceId >= ADAPTER_EIP202_DEVICE_COUNT)
+        return PEC_ERROR_BAD_PARAMETER;
+
+#ifdef ADAPTER_EIP202_STRICT_ARGS
+    LOG_INFO("\n\t\t\t EIP202_CDR_FillLevel_Get \n");
+
+    res = EIP202_CDR_FillLevel_Get(CDR_IOArea + InterfaceId,
+                                  &FilledCDR);
+    if (res != EIP202_RING_NO_ERROR)
+        return PEC_ERROR_INTERNAL;
+
+    if (FilledCDR > ADAPTER_EIP202_MAX_PACKETS)
+        return PEC_ERROR_INTERNAL;
+
+    FreeCDR = ADAPTER_EIP202_MAX_PACKETS - FilledCDR;
+
+    LOG_INFO("\n\t\t\t EIP202_RDR_FillLevel_Get \n");
+
+    if (!EIP202_ContinuousScatter[InterfaceId])
+    {
+        res = EIP202_RDR_FillLevel_Get(RDR_IOArea + InterfaceId,
+                                       &FilledRDR);
+        if (res != EIP202_RING_NO_ERROR)
+            return PEC_ERROR_INTERNAL;
+
+        if (FilledRDR > ADAPTER_EIP202_MAX_PACKETS)
+        return PEC_ERROR_INTERNAL;
+
+        FreeRDR = ADAPTER_EIP202_MAX_PACKETS - FilledRDR;
+        FreeRDR = MIN(ADAPTER_EIP202_MAX_LOGICDESCR, FreeRDR);
+    }
+    else
+    {
+        FreeRDR = 1;
+    }
+    FreeCDR = MIN(ADAPTER_EIP202_MAX_LOGICDESCR, FreeCDR);
+#endif
+
+    for (CmdLp = 0; CmdLp < CommandsCount; CmdLp++)
+    {
+        uint8_t TokenWordCount;
+        EIP202_DeviceAddress_t SA_PhysAddr;
+
+#ifdef ADAPTER_EIP202_STRICT_ARGS
+        if (CDRIndex == FreeCDR || (!EIP202_ContinuousScatter[InterfaceId] && RDRIndex == FreeRDR))
+            break; // Run out of free descriptors in any of the rings.
+#endif
+
+        if (!Commands_p[CmdLp].InputToken_p)
+        {
+            LOG_CRIT("Adapter_PECDev_Packet_Put: failed, missing input token "
+                     "for command descriptor %d\n",
+                     CmdLp);
+            return PEC_ERROR_BAD_PARAMETER;
+        }
+
+        // Prepare (first) descriptor, except for source pointer/size.
+        EIP202_CDR_Entries[InterfaceId][CDRIndex].SrcPacketByteCount =
+                                            Commands_p[CmdLp].SrcPkt_ByteCount;
+
+        if (DMABuf_Handle_IsSame(&Commands_p[CmdLp].Token_Handle,
+                                 &DMABuf_NULLHandle))
+        {
+            TokenWordCount = 0;
+        }
+        else
+        {
+            // Look-aside use case. token is created by the caller
+            if (Commands_p[CmdLp].Token_WordCount > 255)
+                return PEC_ERROR_INTERNAL;
+
+            TokenWordCount = (uint8_t)Commands_p[CmdLp].Token_WordCount;
+        }
+
+        CDR_Control.TokenWordCount = TokenWordCount;
+
+        Adapter_GetPhysAddr(Commands_p[CmdLp].Token_Handle,
+              &(EIP202_CDR_Entries[InterfaceId][CDRIndex].TokenDataAddr));
+
+        if (!AdapterLib_Ring_EIP202_DMAAddr_IsSane(
+                &EIP202_CDR_Entries[InterfaceId][CDRIndex].TokenDataAddr,
+                "token buffer"))
+            return PEC_ERROR_INTERNAL;
+
+        CDR_Control.fFirstSegment = true;
+        CDR_Control.fLastSegment  = false;
+        CDR_Control.fForceEngine = (Commands_p[CmdLp].Control2 & BIT_5) != 0;
+        CDR_Control.EngineId = Commands_p[CmdLp].Control2 & MASK_5_BITS;
+
+        EIP202_CDR_Entries[InterfaceId][CDRIndex].Token_p =
+                                            Commands_p[CmdLp].InputToken_p;
+
+        Adapter_GetPhysAddr(Commands_p[CmdLp].SA_Handle1, &SA_PhysAddr);
+
+        if (SA_PhysAddr.Addr != ADAPTER_EIP202_DUMMY_DMA_ADDRESS_LO ||
+            SA_PhysAddr.UpperAddr != ADAPTER_EIP202_DUMMY_DMA_ADDRESS_HI)
+        {
+            DMAResource_Handle_t DMAHandle =
+                Adapter_DMABuf_Handle2DMAResourceHandle(
+                                        Commands_p[CmdLp].SA_Handle1);
+            DMAResource_Record_t * Rec_p =
+                                    DMAResource_Handle2RecordPtr(DMAHandle);
+            if (Rec_p == NULL)
+                return PEC_ERROR_INTERNAL;
+
+#ifdef ADAPTER_EIP202_DMARESOURCE_BANKS_ENABLE
+            if (Rec_p->Props.Bank != ADAPTER_EIP202_BANK_SA)
+            {
+                LOG_CRIT("PEC_Packet_Put: Invalid bank for SA\n");
+                return PEC_ERROR_BAD_PARAMETER;
+            }
+#endif
+
+            if (IOToken_SAReuse_Update(!Rec_p->fIsNewSA,
+                                       Commands_p[CmdLp].InputToken_p) < 0)
+                return PEC_ERROR_INTERNAL;
+
+            if (Rec_p->fIsNewSA)
+                Rec_p->fIsNewSA = false;
+        }
+
+#ifdef ADAPTER_EIP202_USE_POINTER_TYPES
+        if (SA_PhysAddr.Addr != ADAPTER_EIP202_DUMMY_DMA_ADDRESS_LO ||
+            SA_PhysAddr.UpperAddr != ADAPTER_EIP202_DUMMY_DMA_ADDRESS_HI)
+        {
+#ifndef ADAPTER_EIP202_USE_LARGE_TRANSFORM_DISABLE
+            DMAResource_Handle_t DMAHandle =
+                Adapter_DMABuf_Handle2DMAResourceHandle(
+                                        Commands_p[CmdLp].SA_Handle1);
+            DMAResource_Record_t * Rec_p =
+                            DMAResource_Handle2RecordPtr(DMAHandle);
+
+            if (Rec_p->fIsLargeTransform)
+                SA_PhysAddr.Addr |= ADAPTER_EIP202_TR_LARGE_ADDRESS;
+            else
+#endif
+                SA_PhysAddr.Addr |= ADAPTER_EIP202_TR_ADDRESS;
+        }
+#endif
+
+#ifdef ADAPTER_EIP202_DMARESOURCE_BANKS_ENABLE
+#ifdef ADAPTER_EIP202_RC_DMA_BANK_SUPPORT
+        if (SA_PhysAddr.Addr != ADAPTER_EIP202_DUMMY_DMA_ADDRESS ||
+            SA_PhysAddr.UpperAddr != ADAPTER_EIP202_DUMMY_DMA_ADDRESS_HI)
+            SA_PhysAddr.Addr -= EIP202_SABaseAddr;
+
+        SA_PhysAddr.UpperAddr = 0;
+#endif // ADAPTER_EIP202_RC_DMA_BANKS_SUPPORT
+#endif // ADAPTER_EIP202_DMARESOURCE_BANKS_ENABLE
+
+        EIP202_CDR_Entries[InterfaceId][CDRIndex].ContextDataAddr = SA_PhysAddr;
+
+        if (!AdapterLib_Ring_EIP202_DMAAddr_IsSane(&SA_PhysAddr, "SA buffer"))
+            return PEC_ERROR_INTERNAL;
+
+        {
+            IOToken_PhysAddr_t tkn_pa;
+
+            tkn_pa.Lo = SA_PhysAddr.Addr;
+            tkn_pa.Hi = SA_PhysAddr.UpperAddr;
+
+            if (IOToken_SAAddr_Update(&tkn_pa,
+                                      Commands_p[CmdLp].InputToken_p) < 0)
+                return PEC_ERROR_INTERNAL;
+        }
+
+        RDR_Control.fFirstSegment           = true;
+        RDR_Control.fLastSegment            = false;
+        RDR_Control.ExpectedResultWordCount = 0;
+
+#ifdef ADAPTER_EIP202_ENABLE_SCATTERGATHER
+        {
+            unsigned int GatherParticles;
+            unsigned int ScatterParticles;
+            unsigned int RequiredCDR, RequiredRDR;
+            unsigned int i;
+            unsigned int GatherByteCount;
+
+            PEC_SGList_GetCapacity(Commands_p[CmdLp].SrcPkt_Handle,
+                                   &GatherParticles);
+            if (EIP202_ContinuousScatter[InterfaceId])
+                ScatterParticles = 1;
+            else
+                PEC_SGList_GetCapacity(Commands_p[CmdLp].DstPkt_Handle,
+                                       &ScatterParticles);
+
+            if (GatherParticles == 0)
+                RequiredCDR = 1;
+            else
+                RequiredCDR = GatherParticles;
+
+            if (ScatterParticles == 0)
+                RequiredRDR = 1;
+            else
+                RequiredRDR = ScatterParticles;
+
+#ifndef ADAPTER_EIP202_SEPARATE_RINGS
+            // If using overlapping rings, require an equal number of CDR
+            // and RDR entries for the packet, the maximum of both.
+            RequiredCDR = MAX(RequiredCDR,RequiredRDR);
+            RequiredRDR = RequiredCDR;
+#endif
+            /* Check whether it will fit into the rings and the
+             * prepared descriptor arrays.*/
+#ifdef ADAPTER_EIP202_STRICT_ARGS
+            if (CDRIndex + RequiredCDR > FreeCDR ||
+                RDRIndex + RequiredRDR > FreeRDR)
+                break;
+#endif
+
+            if (GatherParticles > 0)
+            {
+                GatherByteCount = Commands_p[CmdLp].SrcPkt_ByteCount;
+                for (i=0; i<GatherParticles; i++)
+                {
+                    DMABuf_Handle_t ParticleHandle;
+                    uint8_t * DummyPtr;
+                    unsigned int ParticleSize;
+
+                    PEC_SGList_Read(Commands_p[CmdLp].SrcPkt_Handle,
+                                    i,
+                                    &ParticleHandle,
+                                    &ParticleSize,
+                                    &DummyPtr);
+
+                    Adapter_GetPhysAddr(ParticleHandle,
+                      &(EIP202_CDR_Entries[InterfaceId][CDRIndex+i].SrcPacketAddr));
+
+                    if (!AdapterLib_Ring_EIP202_DMAAddr_IsSane(
+                            &EIP202_CDR_Entries[InterfaceId][CDRIndex+i].SrcPacketAddr,
+                            "source packet buffer"))
+                        return PEC_ERROR_INTERNAL;
+
+                    if (ParticleSize > GatherByteCount)
+                        ParticleSize = GatherByteCount;
+                    GatherByteCount -= ParticleSize;
+                    // Limit the total size of the gather particles to the
+                    // actual packet length.
+
+                    CDR_Control.fLastSegment = (RequiredCDR == i + 1);
+                    CDR_Control.SegmentByteCount = ParticleSize;
+                    EIP202_CDR_Entries[InterfaceId][CDRIndex+i].ControlWord =
+                        EIP202_CDR_Write_ControlWord(&CDR_Control);
+                    CDR_Control.fFirstSegment = false;
+                    CDR_Control.TokenWordCount = 0;
+                }
+            }
+            else
+            { /* No gather, use single source buffer */
+
+                Adapter_GetPhysAddr(Commands_p[CmdLp].SrcPkt_Handle,
+                 &(EIP202_CDR_Entries[InterfaceId][CDRIndex].SrcPacketAddr));
+
+                if (!AdapterLib_Ring_EIP202_DMAAddr_IsSane(
+                        &EIP202_CDR_Entries[InterfaceId][CDRIndex].SrcPacketAddr,
+                        "source packet buffer"))
+                    return PEC_ERROR_INTERNAL;
+
+                CDR_Control.fLastSegment = (RequiredCDR == 1);
+                CDR_Control.SegmentByteCount =
+                    Commands_p[CmdLp].SrcPkt_ByteCount;
+                EIP202_CDR_Entries[InterfaceId][CDRIndex].ControlWord =
+                    EIP202_CDR_Write_ControlWord(&CDR_Control);
+
+                CDR_Control.fFirstSegment = false;
+                CDR_Control.TokenWordCount = 0;
+                i = 1;
+            }
+
+            /* Add any dummy segments for overlapping rings */
+            for ( ; i<RequiredCDR; i++)
+            {
+
+                CDR_Control.fLastSegment = (RequiredCDR == i + 1);
+                CDR_Control.SegmentByteCount = 0;
+                EIP202_CDR_Entries[InterfaceId][CDRIndex+i].ControlWord =
+                    EIP202_CDR_Write_ControlWord(&CDR_Control);
+            }
+
+            if (!EIP202_ContinuousScatter[InterfaceId])
+            {
+                if (ScatterParticles > 0)
+                {
+                    for (i=0; i<ScatterParticles; i++)
+                    {
+                        DMABuf_Handle_t ParticleHandle;
+                        uint8_t * DummyPtr;
+                        unsigned int ParticleSize;
+
+                        PEC_SGList_Read(Commands_p[CmdLp].DstPkt_Handle,
+                                        i,
+                                        &ParticleHandle,
+                                        &ParticleSize,
+                                        &DummyPtr);
+
+                        Adapter_GetPhysAddr(ParticleHandle,
+                                            &(EIP202_RDR_Prepared[InterfaceId][RDRIndex+i].DstPacketAddr));
+
+                        if (!AdapterLib_Ring_EIP202_DMAAddr_IsSane(
+                                &EIP202_RDR_Prepared[InterfaceId][RDRIndex+i].DstPacketAddr,
+                                "destination packet buffer"))
+                            return PEC_ERROR_INTERNAL;
+
+                        RDR_Control.fLastSegment = (RequiredRDR == i + 1);
+                        RDR_Control.PrepSegmentByteCount = ParticleSize;
+                        EIP202_RDR_Prepared[InterfaceId][RDRIndex+i].PrepControlWord =
+                            EIP202_RDR_Write_Prepared_ControlWord(&RDR_Control);
+
+                        RDR_Control.fFirstSegment = false;
+                    }
+                }
+                else
+                { /* No scatter, use single destination buffer */
+                    DMAResource_Handle_t *DMAHandle =
+                    Adapter_DMABuf_Handle2DMAResourceHandle(
+                        Commands_p[CmdLp].DstPkt_Handle);
+                    DMAResource_Record_t * Rec_p;
+
+                    if (DMAResource_IsValidHandle(DMAHandle))
+                        Rec_p  = DMAResource_Handle2RecordPtr(DMAHandle);
+                    else
+                        Rec_p = NULL;
+
+                    // Check if NULL packet pointers are allowed
+                    // for record invalidation commands
+#ifndef ADAPTER_EIP202_INVALIDATE_NULL_PKT_POINTER
+                    if (Rec_p == NULL)
+                        return PEC_ERROR_INTERNAL;
+#endif
+
+                    Adapter_GetPhysAddr(Commands_p[CmdLp].DstPkt_Handle,
+                                        &(EIP202_RDR_Prepared[InterfaceId][RDRIndex].DstPacketAddr));
+
+                    if (!AdapterLib_Ring_EIP202_DMAAddr_IsSane(
+                      &EIP202_RDR_Prepared[InterfaceId][RDRIndex].DstPacketAddr,
+                      "destination packet buffer"))
+                    return PEC_ERROR_INTERNAL;
+
+                    RDR_Control.fLastSegment = (RequiredRDR==1);
+
+#ifdef ADAPTER_EIP202_INVALIDATE_NULL_PKT_POINTER
+                    // For NULL packet pointers only, record cache invalidation
+                    if (Rec_p == NULL)
+                        RDR_Control.PrepSegmentByteCount = 0;
+                    else
+#endif
+                        RDR_Control.PrepSegmentByteCount = Rec_p->Props.Size;
+
+                    EIP202_RDR_Prepared[InterfaceId][RDRIndex].PrepControlWord =
+                        EIP202_RDR_Write_Prepared_ControlWord(&RDR_Control);
+
+                    RDR_Control.fFirstSegment = false;
+                    i = 1;
+                }
+
+                /* Add any dummy segments for overlapping rings */
+                for ( ; i<RequiredRDR; i++)
+                {
+                    RDR_Control.fLastSegment = (RequiredRDR == i + 1);
+                    RDR_Control.PrepSegmentByteCount = 0;
+                    EIP202_RDR_Prepared[InterfaceId][RDRIndex+i].PrepControlWord =
+                        EIP202_RDR_Write_Prepared_ControlWord(&RDR_Control);
+                }
+                RDRIndex += RequiredRDR;
+            }
+            CDRIndex += RequiredCDR;
+        }
+#else
+        {
+            // Prepare source and destination buffer in non-SG case.
+            DMAResource_Handle_t *DMAHandle =
+                Adapter_DMABuf_Handle2DMAResourceHandle(
+                    Commands_p[CmdLp].DstPkt_Handle);
+            DMAResource_Record_t * Rec_p;
+
+            if (DMAResource_IsValidHandle(DMAHandle))
+                Rec_p  = DMAResource_Handle2RecordPtr(DMAHandle);
+            else
+                Rec_p = NULL;
+
+            // Check if NULL packet pointers are allowed
+            // for record invalidation commands
+#ifndef ADAPTER_EIP202_INVALIDATE_NULL_PKT_POINTER
+            if (Rec_p == NULL)
+                return PEC_ERROR_INTERNAL;
+#endif
+
+            Adapter_GetPhysAddr(Commands_p[CmdLp].SrcPkt_Handle,
+                 &(EIP202_CDR_Entries[InterfaceId][CDRIndex].SrcPacketAddr));
+
+            if (!AdapterLib_Ring_EIP202_DMAAddr_IsSane(
+                  &EIP202_CDR_Entries[InterfaceId][CDRIndex].SrcPacketAddr,
+                  "source packet buffer"))
+                return PEC_ERROR_INTERNAL;
+
+            CDR_Control.fLastSegment     = true;
+            CDR_Control.SegmentByteCount = Commands_p[CmdLp].SrcPkt_ByteCount;
+
+            EIP202_CDR_Entries[InterfaceId][CDRIndex].ControlWord =
+                                EIP202_CDR_Write_ControlWord(&CDR_Control);
+
+            if (!EIP202_ContinuousScatter[InterfaceId])
+            {
+                Adapter_GetPhysAddr(Commands_p[CmdLp].DstPkt_Handle,
+                                    &(EIP202_RDR_Prepared[InterfaceId][RDRIndex].DstPacketAddr));
+
+                if (!AdapterLib_Ring_EIP202_DMAAddr_IsSane(
+                        &EIP202_RDR_Prepared[InterfaceId][RDRIndex].DstPacketAddr,
+                        "destination packet buffer"))
+                    return PEC_ERROR_INTERNAL;
+
+                RDR_Control.fLastSegment = true;
+
+#ifdef ADAPTER_EIP202_INVALIDATE_NULL_PKT_POINTER
+                // For NULL packet pointers only, record cache invalidation
+                if (Rec_p == NULL)
+                    RDR_Control.PrepSegmentByteCount = 0;
+                else
+#endif
+                    RDR_Control.PrepSegmentByteCount = Rec_p->Props.Size;
+
+                EIP202_RDR_Prepared[InterfaceId][RDRIndex].PrepControlWord =
+                    EIP202_RDR_Write_Prepared_ControlWord(&RDR_Control);
+
+                RDRIndex +=1;
+            }
+            CDRIndex +=1;
+        }
+#endif
+        *PutCount_p += 1;
+    } // for, CommandsCount, CmdLp
+
+
+    if (!EIP202_ContinuousScatter[InterfaceId])
+    {
+        LOG_INFO("\n\t\t\t EIP202_RDR_Descriptor_Prepare \n");
+        res = EIP202_RDR_Descriptor_Prepare(RDR_IOArea + InterfaceId,
+                                            EIP202_RDR_Prepared[InterfaceId],
+                                            RDRIndex,
+                                            &Submitted,
+                                            &FilledRDR);
+        if (res != EIP202_RING_NO_ERROR || Submitted != RDRIndex)
+        {
+            LOG_CRIT("Adapter_PECDev_Packet_Put: writing prepared descriptors"
+                     "error code %d count=%d expected=%d\n",
+                     res, Submitted, RDRIndex);
+            return PEC_ERROR_INTERNAL;
+        }
+    }
+    LOG_INFO("\n\t\t\t EIP202_CDR_Descriptor_Put \n");
+
+    res = EIP202_CDR_Descriptor_Put(CDR_IOArea + InterfaceId,
+                                   EIP202_CDR_Entries[InterfaceId],
+                                   CDRIndex,
+                                   &Submitted,
+                                   &FilledCDR);
+    if (res != EIP202_RING_NO_ERROR || Submitted != CDRIndex)
+    {
+        LOG_CRIT("Adapter_PECDev_Packet_Put: writing command descriptors"
+                 "error code %d count=%d expected=%d\n",
+                 res, Submitted, CDRIndex);
+        return PEC_ERROR_INTERNAL;
+    }
+
+    return PEC_STATUS_OK;
+}
+
+
+/*----------------------------------------------------------------------------
+ * Adapter_PECDev_Packet_Get
+ */
+PEC_Status_t
+Adapter_PECDev_Packet_Get(
+        const unsigned int InterfaceId,
+        PEC_ResultDescriptor_t * Results_p,
+        const unsigned int ResultsLimit,
+        unsigned int * const GetCount_p)
+{
+    unsigned int ResLp;
+    unsigned int DscrCount;
+    unsigned int DscrDoneCount;
+    unsigned int ResIndex;
+
+    EIP202_Ring_Error_t res;
+
+    LOG_INFO("\n\t\t Adapter_PECDev_Packet_Get \n");
+
+    *GetCount_p = 0;
+
+    if (ResultsLimit == 0)
+        return PEC_STATUS_OK;
+
+    if (InterfaceId >= ADAPTER_EIP202_DEVICE_COUNT)
+        return PEC_ERROR_BAD_PARAMETER;
+
+    LOG_INFO("\n\t\t\t EIP202_RDR_Descriptor_Get \n");
+
+    // Assume that we do get the requested number of descriptors
+    // as they were reported available.
+    res = EIP202_RDR_Descriptor_Get(RDR_IOArea + InterfaceId,
+                                    EIP202_RDR_Entries[InterfaceId],
+                                    ResultsLimit, // Max number of packets.
+                                    ADAPTER_EIP202_MAX_LOGICDESCR,
+                                    &DscrDoneCount,
+                                    &DscrCount);
+    if (res != EIP202_RING_NO_ERROR)
+        return PEC_ERROR_INTERNAL;
+
+    ResIndex = 0;
+    for (ResLp = 0; ResLp < ResultsLimit; ResLp++)
+    {
+        EIP202_RDR_Result_Control_t ControlWord;
+        bool fEncounteredFirst = false;
+
+        if (ResIndex >= DscrDoneCount)
+            break;
+
+        for (;;)
+        {
+            LOG_INFO("\n\t\t\t EIP202_RDR_Read_Processed_ControlWord \n");
+
+            EIP202_RDR_Read_Processed_ControlWord(
+                                EIP202_RDR_Entries[InterfaceId] + ResIndex,
+                                &ControlWord,
+                                NULL);
+
+            if ( ControlWord.fFirstSegment)
+            {
+                fEncounteredFirst = true;
+                Results_p[ResLp].NumParticles = 0;
+            }
+            Results_p[ResLp].NumParticles++;
+
+            if ( ControlWord.fLastSegment && fEncounteredFirst)
+                break; // Last segment of packet, only valid when
+                       // first segment was encountered.
+            ResIndex++;
+
+            // There may be unused scatter particles after the last segment
+            // that must be skipped.
+            if (ResIndex >= DscrDoneCount)
+                return PEC_STATUS_OK;
+        }
+
+        // Presence of Output Token placeholder is optional
+        if (Results_p[ResLp].OutputToken_p)
+        {
+            // Copy Output Token from EIP-202 to PEC result descriptor
+            memcpy(Results_p[ResLp].OutputToken_p,
+                   EIP202_RDR_Entries[InterfaceId][ResIndex].Token_p,
+                   IOToken_OutWordCount_Get() * sizeof (uint32_t));
+
+            IOToken_PacketLegth_Get(Results_p[ResLp].OutputToken_p,
+                                    &Results_p[ResLp].DstPkt_ByteCount);
+
+            IOToken_BypassLegth_Get(Results_p[ResLp].OutputToken_p,
+                                    &Results_p[ResLp].Bypass_WordCount);
+        }
+
+        // Copy the first EIP-202 result descriptor word, contains
+        // - Particle byte count,
+        // - Buffer overflow (BIT_21) and Descriptor overflow (BIT_20) errors
+        // - First segment (BIT_23) and Last segment (BIT_22) indicators
+        // - Descriptor overflow word count if BIT_20 is set
+        Results_p[ResLp].Status1 =
+              EIP202_RDR_Entries[InterfaceId][ResIndex].ProcControlWord;
+
+        *GetCount_p += 1;
+        ResIndex++;
+    }
+
+    return PEC_STATUS_OK;
+}
+
+
+#ifdef ADAPTER_EIP202_ENABLE_SCATTERGATHER
+/*----------------------------------------------------------------------------
+ * Adapter_PECDev_TestSG
+ */
+bool
+Adapter_PECDev_TestSG(
+    const unsigned int InterfaceId,
+    const unsigned int GatherParticleCount,
+    const unsigned int ScatterParticleCount)
+{
+    unsigned int GCount = GatherParticleCount;
+    unsigned int SCount = ScatterParticleCount;
+    unsigned int FreeCDR, FreeRDR, FilledCDR, FilledRDR;
+    EIP202_Ring_Error_t res;
+
+    if (InterfaceId >= ADAPTER_EIP202_DEVICE_COUNT)
+        return false;
+
+    if (GCount == 0)
+        GCount = 1;
+
+    if (SCount == 0)
+        SCount = 1;
+
+#ifndef ADAPTER_EIP202_SEPARATE_RINGS
+    GCount = MAX(GCount, SCount);
+    SCount = GCount;
+#endif
+
+    if (GCount > ADAPTER_EIP202_MAX_LOGICDESCR ||
+        SCount > ADAPTER_EIP202_MAX_LOGICDESCR)
+        return false;
+
+    LOG_INFO("\n\t\t\t EIP202_CDR_FillLevel_Get \n");
+
+    res = EIP202_CDR_FillLevel_Get(CDR_IOArea + InterfaceId,
+                                  &FilledCDR);
+    if (res != EIP202_RING_NO_ERROR)
+        return false;
+
+    if (FilledCDR > ADAPTER_EIP202_MAX_PACKETS)
+        return false;
+
+    FreeCDR = ADAPTER_EIP202_MAX_PACKETS - FilledCDR;
+
+    LOG_INFO("\n\t\t\t EIP202_RDR_FillLevel_Get \n");
+
+    if (EIP202_ContinuousScatter[InterfaceId])
+    {
+        return (FreeCDR >= GCount);
+    }
+    else
+    {
+        res = EIP202_RDR_FillLevel_Get(RDR_IOArea + InterfaceId,
+                                           &FilledRDR);
+        if (res != EIP202_RING_NO_ERROR)
+            return false;
+
+        if (FilledRDR > ADAPTER_EIP202_MAX_PACKETS)
+            return false;
+
+        FreeRDR = ADAPTER_EIP202_MAX_PACKETS - FilledRDR;
+
+        return (FreeCDR >= GCount && FreeRDR >= SCount);
+    }
+}
+#endif // ADAPTER_EIP202_ENABLE_SCATTERGATHER
+
+
+#ifdef ADAPTER_EIP202_INTERRUPTS_ENABLE
+/* Adapter_PECDev_IRQToInteraceID
+ */
+unsigned int
+Adapter_PECDev_IRQToInferfaceId(
+        const int nIRQ)
+{
+    unsigned int i, IRQ_Nr;
+
+    if (nIRQ < 0)
+        return 0;
+
+    IRQ_Nr = (unsigned int)nIRQ;
+
+    for (i = 0; i < ADAPTER_EIP202_DEVICE_COUNT; i++)
+    {
+        if (IRQ_Nr == EIP202_Devices[i].RDR_IRQ_ID ||
+            IRQ_Nr == EIP202_Devices[i].CDR_IRQ_ID)
+        {
+            return i;
+        }
+    }
+
+    LOG_CRIT("Adapter_PECDev_IRQToInterfaceId: unknown interrupt %d\n",nIRQ);
+
+    return 0;
+}
+
+
+/*----------------------------------------------------------------------------
+ * Adapter_PECDev_Enable_ResultIRQ
+ */
+void
+Adapter_PECDev_Enable_ResultIRQ(
+        const unsigned int InterfaceId)
+{
+    if (InterfaceId >= ADAPTER_EIP202_DEVICE_COUNT)
+        return;
+
+    LOG_INFO(
+      "\n\t\t\t EIP202_RDR_Processed_FillLevel_High_INT_ClearAndDisable \n");
+
+    EIP202_RDR_Processed_FillLevel_High_INT_ClearAndDisable (
+        RDR_IOArea + InterfaceId,
+        false);
+
+    LOG_INFO("\n\t\t\t EIP202_RDR_Processed_FillLevel_High_INT_Enable \n");
+
+    EIP202_RDR_Processed_FillLevel_High_INT_Enable(
+        RDR_IOArea + InterfaceId,
+        ADAPTER_EIP202_DESCRIPTORDONECOUNT,
+        ADAPTER_EIP202_DESCRIPTORDONETIMEOUT,
+        true);
+
+    Adapter_Interrupt_Enable(EIP202_Devices[InterfaceId].RDR_IRQ_ID,
+                             EIP202_Devices[InterfaceId].RDR_IRQ_Flags);
+
+    EIP202_Interrupts[InterfaceId] |= BIT_0;
+}
+
+
+/*----------------------------------------------------------------------------
+ * Adapter_PECDev_Disable_ResultIRQ
+ */
+void
+Adapter_PECDev_Disable_ResultIRQ(
+        const unsigned int InterfaceId)
+{
+    if (InterfaceId >= ADAPTER_EIP202_DEVICE_COUNT)
+        return;
+
+    LOG_INFO(
+       "\n\t\t\t EIP202_RDR_Processed_FillLevel_High_INT_ClearAndDisable \n");
+
+    EIP202_RDR_Processed_FillLevel_High_INT_ClearAndDisable (
+        RDR_IOArea + InterfaceId,
+        false);
+
+    Adapter_Interrupt_Disable(EIP202_Devices[InterfaceId].RDR_IRQ_ID,
+                              EIP202_Devices[InterfaceId].RDR_IRQ_Flags);
+
+    EIP202_Interrupts[InterfaceId] &= ~BIT_0;
+}
+
+
+/*----------------------------------------------------------------------------
+ * Adapter_PECDev_Enable_CommandIRQ
+ */
+void
+Adapter_PECDev_Enable_CommandIRQ(
+        const unsigned int InterfaceId)
+{
+    if (InterfaceId >= ADAPTER_EIP202_DEVICE_COUNT)
+        return;
+
+    LOG_INFO("\n\t\t\t EIP202_CDR_FillLevel_Low_INT_Enable \n");
+
+    EIP202_CDR_FillLevel_Low_INT_Enable(
+        CDR_IOArea + InterfaceId,
+        ADAPTER_EIP202_DESCRIPTORDONECOUNT,
+        ADAPTER_EIP202_DESCRIPTORDONETIMEOUT);
+
+    Adapter_Interrupt_Enable(EIP202_Devices[InterfaceId].CDR_IRQ_ID,
+                             EIP202_Devices[InterfaceId].CDR_IRQ_Flags);
+
+    EIP202_Interrupts[InterfaceId] |= BIT_1;
+}
+
+
+/*----------------------------------------------------------------------------
+ * Adapter_PECDev_Disable_CommandIRQ
+ */
+void
+Adapter_PECDev_Disable_CommandIRQ(
+        const unsigned int InterfaceId)
+{
+    if (InterfaceId >= ADAPTER_EIP202_DEVICE_COUNT)
+        return;
+
+    LOG_INFO("\n\t\t\t EIP202_CDR_FillLevel_Low_INT_ClearAndDisable \n");
+
+    EIP202_CDR_FillLevel_Low_INT_ClearAndDisable(
+        CDR_IOArea + InterfaceId);
+
+    Adapter_Interrupt_Disable(EIP202_Devices[InterfaceId].CDR_IRQ_ID,
+                              EIP202_Devices[InterfaceId].CDR_IRQ_Flags);
+
+    EIP202_Interrupts[InterfaceId] &= ~BIT_1;
+}
+
+
+/*----------------------------------------------------------------------------
+ * Adapter_PECDev_SetResultHandler
+ */
+void Adapter_PECDev_SetResultHandler(
+        const unsigned int InterfaceId,
+        Adapter_InterruptHandler_t HandlerFunction)
+{
+    if (InterfaceId >= ADAPTER_EIP202_DEVICE_COUNT)
+        return;
+
+    Adapter_Interrupt_SetHandler(EIP202_Devices[InterfaceId].RDR_IRQ_ID,
+                                 HandlerFunction);
+}
+
+
+/*----------------------------------------------------------------------------
+ * Adapter_PECDev_SetCommandHandler
+ */
+void Adapter_PECDev_SetCommandHandler(
+        const unsigned int InterfaceId,
+        Adapter_InterruptHandler_t HandlerFunction)
+{
+    if (InterfaceId >= ADAPTER_EIP202_DEVICE_COUNT)
+        return;
+
+    Adapter_Interrupt_SetHandler(EIP202_Devices[InterfaceId].CDR_IRQ_ID,
+                                 HandlerFunction);
+}
+#endif // ADAPTER_EIP202_INTERRUPTS_ENABLE
+
+
+/*----------------------------------------------------------------------------
+ * Adapter_PECDev_Scatter_Preload
+ */
+PEC_Status_t
+Adapter_PECDev_Scatter_Preload(
+        const unsigned int InterfaceId,
+        DMABuf_Handle_t * Handles_p,
+        const unsigned int HandlesCount)
+{
+    unsigned int i;
+    EIP202_RDR_Prepared_Control_t RDR_Control;
+    EIP202_Ring_Error_t res;
+    unsigned int Submitted,FilledRDR;
+    for (i = 0; i <  HandlesCount; i++)
+    {
+        DMABuf_Handle_t ParticleHandle = Handles_p[i];
+        DMAResource_Handle_t DMAHandle = Adapter_DMABuf_Handle2DMAResourceHandle(ParticleHandle);
+        DMAResource_Record_t * Rec_p = DMAResource_Handle2RecordPtr(DMAHandle);
+
+        RDR_Control.fFirstSegment           = true;
+#ifdef ADAPTER_EIP202_ENABLE_SCATTERGATHER
+        RDR_Control.fLastSegment            = false;
+#else
+        RDR_Control.fLastSegment            = true;
+        // When No scatter gather supported, packets must fit into single buffer.
+#endif
+        RDR_Control.PrepSegmentByteCount = Rec_p->Props.Size;
+        RDR_Control.ExpectedResultWordCount = 0;
+        EIP202_RDR_Prepared[InterfaceId][i].PrepControlWord =
+            EIP202_RDR_Write_Prepared_ControlWord(&RDR_Control);
+        Adapter_GetPhysAddr(ParticleHandle,
+                            &(EIP202_RDR_Prepared[InterfaceId][i].DstPacketAddr));
+    }
+    res = EIP202_RDR_Descriptor_Prepare(RDR_IOArea + InterfaceId,
+                                       EIP202_RDR_Prepared[InterfaceId],
+                                       HandlesCount,
+                                       &Submitted,
+                                       &FilledRDR);
+    if (res != EIP202_RING_NO_ERROR || Submitted != HandlesCount)
+    {
+        LOG_CRIT("Adapter_PECDev_Packet_Put: writing prepared descriptors"
+                 "error code %d count=%d expected=%d\n",
+                 res, Submitted, HandlesCount);
+        return PEC_ERROR_INTERNAL;
+    }
+
+    return PEC_STATUS_OK;
+}
+
+
+/*----------------------------------------------------------------------------
+ * Adapter_PECDev_Put_Dump
+ */
+void
+Adapter_PECDev_Put_Dump(
+        const unsigned int InterfaceId,
+        const unsigned int FirstSlotId,
+        const unsigned int LastSlotId,
+        const bool fDumpCDRAdmin,
+        const bool fDumpCDRCache)
+{
+    void * va;
+    unsigned int i, CDOffset;
+    uint32_t Word32;
+    EIP202_RingAdmin_t RingAdmin;
+    DMAResource_AddrPair_t Addr_Pair;
+
+    if (InterfaceId >= ADAPTER_EIP202_DEVICE_COUNT)
+        return;
+
+    if (FirstSlotId >= ADAPTER_EIP202_MAX_PACKETS ||
+        LastSlotId >= ADAPTER_EIP202_MAX_PACKETS)
+        return;
+
+    if (FirstSlotId > LastSlotId)
+        return;
+
+    AdapterLib_Ring_EIP202_CDR_Status_Report(InterfaceId);
+
+    ZEROINIT(RingAdmin);
+    EIP202_CDR_Dump(CDR_IOArea + InterfaceId, &RingAdmin);
+    CDOffset = RingAdmin.DescOffsWordCount;
+
+    ZEROINIT(Addr_Pair);
+    DMAResource_Translate(CDR_Handle[InterfaceId],
+                          DMARES_DOMAIN_HOST,
+                          &Addr_Pair);
+    va = Addr_Pair.Address_p;
+
+    if (fDumpCDRAdmin)
+    {
+        void * pa;
+
+        ZEROINIT(Addr_Pair);
+        DMAResource_Translate(CDR_Handle[InterfaceId],
+                              DMARES_DOMAIN_BUS,
+                              &Addr_Pair);
+        pa = Addr_Pair.Address_p;
+
+        LOG_CRIT("\n\tCDR admin data, all sizes in 32-bit words:\n"
+                 "\tSeparate:         %s\n"
+                 "\tRing size:        %d\n"
+                 "\tDescriptor size:  %d\n"
+                 "\tInput ring size:  %d\n"
+                 "\tInput ring tail:  %d\n"
+                 "\tOutput ring size: %d\n"
+                 "\tOutput ring head: %d\n"
+                 "\tRing phys addr:   %p\n"
+                 "\tRing host addr:   %p\n",
+                 RingAdmin.fSeparate ? "yes" : "no",
+                 RingAdmin.RingSizeWordCount,
+                 RingAdmin.DescOffsWordCount,
+                 RingAdmin.IN_Size,
+                 RingAdmin.IN_Tail,
+                 RingAdmin.OUT_Size,
+                 RingAdmin.OUT_Head,
+                 pa,
+                 va);
+    }
+
+    LOG_CRIT("\n\tCDR dump, first slot %d, last slot %d\n",
+             FirstSlotId,
+             LastSlotId);
+
+    for (i = FirstSlotId; i <= LastSlotId; i++)
+    {
+        unsigned int j;
+
+        LOG_CRIT("\tDescriptor %d:\n", i);
+        for (j = 0; j < CDOffset; j++)
+        {
+            Word32 = DMAResource_Read32(CDR_Handle[InterfaceId],
+                                        i * CDOffset + j);
+
+            LOG_CRIT("\tCD[%02d] word[%02d] 0x%08x\n",
+                     i,
+                     j,
+                     Word32);
+        }
+    }
+
+    if (!fDumpCDRCache)
+        return;
+
+    LOG_CRIT("\n\tCDR cache dump, size %d entries\n",
+             ADAPTER_EIP202_MAX_LOGICDESCR);
+
+    for (i = 0; i < ADAPTER_EIP202_MAX_LOGICDESCR; i++)
+    {
+        unsigned int j;
+
+        LOG_CRIT("\tDescriptor %d cache:\n", i);
+
+        Word32 = EIP202_CDR_Entries[InterfaceId][i].ControlWord;
+        LOG_CRIT("\tCDC[%02d] word[00] 0x%08x\n", i, Word32);
+
+        Word32 = EIP202_CDR_Entries[InterfaceId][i].SrcPacketAddr.Addr;
+        LOG_CRIT("\tCDC[%02d] word[02] 0x%08x\n", i, Word32);
+
+        Word32 = EIP202_CDR_Entries[InterfaceId][i].SrcPacketAddr.UpperAddr;
+        LOG_CRIT("\tCDC[%02d] word[03] 0x%08x\n", i, Word32);
+
+        Word32 = EIP202_CDR_Entries[InterfaceId][i].TokenDataAddr.Addr;
+        LOG_CRIT("\tCDC[%02d] word[04] 0x%08x\n", i, Word32);
+
+        Word32 = EIP202_CDR_Entries[InterfaceId][i].TokenDataAddr.UpperAddr;
+        LOG_CRIT("\tCDC[%02d] word[05] 0x%08x\n", i, Word32);
+
+        if (EIP202_CDR_Entries[InterfaceId][i].Token_p)
+            for (j = 0; j < IOToken_InWordCount_Get(); j++)
+            {
+                Word32 = EIP202_CDR_Entries[InterfaceId][i].Token_p[j];
+                LOG_CRIT("\tCDC[%02d] word[%02d] 0x%08x\n", i, 6 + j, Word32);
+            }
+    }
+
+    return;
+}
+
+
+/*----------------------------------------------------------------------------
+ * Adapter_PECDev_Get_Dump
+ */
+void
+Adapter_PECDev_Get_Dump(
+        const unsigned int InterfaceId,
+        const unsigned int FirstSlotId,
+        const unsigned int LastSlotId,
+        const bool fDumpRDRAdmin,
+        const bool fDumpRDRCache)
+{
+    void * va;
+    unsigned int i, RDOffset;
+    uint32_t Word32;
+    EIP202_RingAdmin_t RingAdmin;
+    DMAResource_AddrPair_t Addr_Pair;
+
+    if (InterfaceId >= ADAPTER_EIP202_DEVICE_COUNT)
+        return;
+
+    if (FirstSlotId >= ADAPTER_EIP202_MAX_PACKETS ||
+        LastSlotId >= ADAPTER_EIP202_MAX_PACKETS)
+        return;
+
+    if (FirstSlotId > LastSlotId)
+        return;
+
+    AdapterLib_Ring_EIP202_RDR_Status_Report(InterfaceId);
+
+    ZEROINIT(RingAdmin);
+    EIP202_RDR_Dump(RDR_IOArea + InterfaceId, &RingAdmin);
+    RDOffset = RingAdmin.DescOffsWordCount;
+
+    ZEROINIT(Addr_Pair);
+    DMAResource_Translate(RDR_Handle[InterfaceId],
+                          DMARES_DOMAIN_HOST,
+                          &Addr_Pair);
+    va = Addr_Pair.Address_p;
+
+    if (fDumpRDRAdmin)
+    {
+        void * pa;
+
+        ZEROINIT(Addr_Pair);
+        DMAResource_Translate(RDR_Handle[InterfaceId],
+                              DMARES_DOMAIN_BUS,
+                              &Addr_Pair);
+        pa = Addr_Pair.Address_p;
+
+        LOG_CRIT("\n\tRDR admin data, all sizes in 32-bit words:\n"
+                 "\tSeparate:         %s\n"
+                 "\tRing size:        %d\n"
+                 "\tDescriptor size:  %d\n"
+                 "\tInput ring size:  %d\n"
+                 "\tInput ring tail:  %d\n"
+                 "\tOutput ring size: %d\n"
+                 "\tOutput ring head: %d\n"
+                 "\tRing phys addr:   %p\n"
+                 "\tRing host addr:   %p\n",
+                 RingAdmin.fSeparate ? "yes" : "no",
+                 RingAdmin.RingSizeWordCount,
+                 RingAdmin.DescOffsWordCount,
+                 RingAdmin.IN_Size,
+                 RingAdmin.IN_Tail,
+                 RingAdmin.OUT_Size,
+                 RingAdmin.OUT_Head,
+                 pa,
+                 va);
+    }
+
+    LOG_CRIT("\n\tRDR dump, first slot %d, last slot %d\n",
+             FirstSlotId,
+             LastSlotId);
+
+    for (i = FirstSlotId; i <= LastSlotId; i++)
+    {
+        unsigned int j;
+
+        LOG_CRIT("\tDescriptor %d:\n", i);
+        for (j = 0; j < RDOffset; j++)
+        {
+            Word32 = DMAResource_Read32(RDR_Handle[InterfaceId],
+                                        i * RDOffset + j);
+
+            LOG_CRIT("\tRD[%02d] word[%02d] 0x%08x\n",
+                     i,
+                     j,
+                     Word32);
+        }
+    }
+
+    if (!fDumpRDRCache)
+        return;
+
+    LOG_CRIT("\n\tRDR cache dump, size %d entries\n",
+             ADAPTER_EIP202_MAX_LOGICDESCR);
+
+    for (i = 0; i < ADAPTER_EIP202_MAX_LOGICDESCR; i++)
+    {
+        unsigned int j;
+
+        LOG_CRIT("\tDescriptor %d cache:\n", i);
+
+        Word32 = EIP202_RDR_Entries[InterfaceId][i].ProcControlWord;
+        LOG_CRIT("\tRDC[%02d] word[00] 0x%08x\n", i, Word32);
+
+        Word32 = EIP202_RDR_Entries[InterfaceId][i].DstPacketAddr.Addr;
+        LOG_CRIT("\tRDC[%02d] word[02] 0x%08x\n", i, Word32);
+
+        Word32 = EIP202_RDR_Entries[InterfaceId][i].DstPacketAddr.UpperAddr;
+        LOG_CRIT("\tRDC[%02d] word[03] 0x%08x\n", i, Word32);
+
+        for (j = 0; j < IOToken_OutWordCount_Get(); j++)
+        {
+            Word32 = EIP202_RDR_Entries[InterfaceId][i].Token_p[j];
+            LOG_CRIT("\tRDC[%02d] word[%02d] 0x%08x\n", i, 4 + j, Word32);
+        }
+    }
+
+    return;
+}
+
+
+/* end of file adapter_ring_eip202.c */
diff --git a/package-21.02/kernel/crypto-eip/src/ddk/slad/adapter_sglist.c b/package-21.02/kernel/crypto-eip/src/ddk/slad/adapter_sglist.c
new file mode 100644
index 0000000..7ecf207
--- /dev/null
+++ b/package-21.02/kernel/crypto-eip/src/ddk/slad/adapter_sglist.c
@@ -0,0 +1,385 @@
+/* adapter_sglist.c
+ *
+ * Packet Engine Control (PEC) Scatter Gather list API implementation.
+ *
+ */
+
+/*****************************************************************************
+* Copyright (c) 2008-2022 by Rambus, Inc. and/or its subsidiaries.
+*
+* This program is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 2 of the License, or
+* any later version.
+*
+* This program is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with this program. If not, see <http://www.gnu.org/licenses/>.
+*****************************************************************************/
+
+
+/*----------------------------------------------------------------------------
+ * This module implements (provides) the following interface(s):
+ */
+
+#include "api_pec_sg.h"         // PEC_SG_* (the API we implement here)
+
+
+/*----------------------------------------------------------------------------
+ * This module uses (requires) the following interface(s):
+ */
+
+// Default Adapter PEC configuration
+#include "c_adapter_pec.h"
+
+// DMABuf API
+#include "api_dmabuf.h"         // DMABuf_*
+
+// Adapter DMABuf internal API
+#include "adapter_dmabuf.h"
+
+// Logging API
+#include "log.h"
+
+// Driver Framework DMAResource API
+#include "dmares_types.h"       // DMAResource_Handle_t
+#include "dmares_mgmt.h"        // DMAResource management functions
+#include "dmares_rw.h"          // DMAResource buffer access.
+#include "dmares_addr.h"        // DMAResource addr translation functions.
+#include "dmares_buf.h"         // DMAResource buffer allocations
+
+// Driver Framework C Run-Time Library API
+#include "clib.h"               // memcpy, memset
+
+// Driver Framework Basic Definitions API
+#include "basic_defs.h"         // bool, uint32_t
+
+
+/*----------------------------------------------------------------------------
+ * Definitions and macros
+ */
+
+#ifdef ADAPTER_PEC_ENABLE_SCATTERGATHER
+
+// our internal definition of a scatter/gather list
+// the DMA buffer for SGList store this (variable-length) structure
+typedef struct
+{
+    unsigned int ListCapacity;
+
+    struct
+    {
+        DMABuf_Handle_t Handle;
+        unsigned int ByteCount;  // set by PEC_SGList_Write and PEC_Packet_Get
+    } Entries[1];       // variable-size allocated!!!
+
+} PEC_SGList_t;
+
+
+/*----------------------------------------------------------------------------
+ * Adapter_Handle2SGList
+ *
+ * This function validates that the DMAResource handle is indeed an
+ * SGList handle
+ * and then returns the pointer to the PEC_SGList_t structure contained in
+ * the buffer related to this handle.
+ */
+static PEC_SGList_t *
+Adapter_Handle2SGListPtr(
+        DMABuf_Handle_t SGList_Handle)
+{
+    DMAResource_Handle_t * DMA_Handle =
+        Adapter_DMABuf_Handle2DMAResourceHandle(SGList_Handle);
+    DMAResource_Record_t * Rec_p;
+    if (DMAResource_IsValidHandle(DMA_Handle))
+        Rec_p = DMAResource_Handle2RecordPtr(DMA_Handle);
+    else
+        return NULL;
+
+    // ensure it is an SGList
+    if (Rec_p->sg.IsSGList != true)
+        return NULL;
+
+    return Adapter_DMAResource_HostAddr(
+        Adapter_DMABuf_Handle2DMAResourceHandle(SGList_Handle));
+
+}
+
+
+/*----------------------------------------------------------------------------
+ * Adapter_SGList_CalcAllocSize
+ *
+ * This function calculates the size of the buffer to be allocated to hold
+ * an PEC_SGList_t with a given capacity.
+ */
+static inline unsigned int
+Adapter_SGList_CalcAllocSize(
+        const unsigned int ListCapacity)
+{
+    PEC_SGList_t SG;
+    unsigned int S = sizeof(PEC_SGList_t);
+
+    S += (ListCapacity - 1) * sizeof(SG.Entries[1]);
+
+    return S;
+}
+#endif /* ADAPTER_PEC_ENABLE_SCATTERGATHER */
+
+
+/*----------------------------------------------------------------------------
+ * PEC_SGList_Create
+ *
+ * This function must be used to create a list that can hold references to
+ * packet buffer fragments. The returned handle can be used in PEC_Packet_Put
+ * instead of a normal (contiguous) buffers.
+ *
+ * ListCapacity (input)
+ *     The number of scatter and/or gather fragments that this list can hold.
+ *
+ * SGList_Handle_p (output)
+ *     Pointer to the output parameter that will be filled in with the handle
+ *     that represents the newly created SGList.
+ */
+PEC_Status_t
+PEC_SGList_Create(
+        const unsigned int ListCapacity,
+        DMABuf_Handle_t * const SGList_Handle_p)
+{
+#ifdef ADAPTER_PEC_ENABLE_SCATTERGATHER
+    DMAResource_AddrPair_t HostAddr;
+    int dmares;
+    DMAResource_Properties_t Props;
+
+    ZEROINIT(Props);
+
+    if (ListCapacity == 0 ||
+        SGList_Handle_p == NULL)
+    {
+        return PEC_ERROR_BAD_PARAMETER;
+    }
+
+    // initialize the output parameter
+    *SGList_Handle_p = DMABuf_NULLHandle;
+
+    Props.Size      = Adapter_SGList_CalcAllocSize(ListCapacity);
+    Props.Alignment = Adapter_DMAResource_Alignment_Get();
+
+    dmares = DMAResource_Alloc(Props, &HostAddr, &SGList_Handle_p->p);
+    if (dmares != 0)
+        return PEC_ERROR_INTERNAL;
+
+    // set the special flag in the DMA Resource record for SGLists
+    {
+        DMAResource_Handle_t DMAHandle;
+        DMAResource_Record_t * Rec_p;
+
+        DMAHandle = SGList_Handle_p->p;
+        Rec_p = DMAResource_Handle2RecordPtr(DMAHandle);
+
+        if (!Rec_p)
+        {
+            // corner case - avoid memory leak
+            DMAResource_Release(Adapter_DMABuf_Handle2DMAResourceHandle(
+                                    *SGList_Handle_p));
+            *SGList_Handle_p = DMABuf_NULLHandle;
+
+            return PEC_ERROR_INTERNAL;
+        }
+
+        Rec_p->sg.IsSGList = true;
+    }
+
+    // initialize the SGList
+    {
+        PEC_SGList_t * const p = HostAddr.Address_p;
+        memset(p, 0, Props.Size);
+        p->ListCapacity = ListCapacity;
+    }
+
+    return PEC_STATUS_OK;
+#else
+    IDENTIFIER_NOT_USED(ListCapacity);
+    IDENTIFIER_NOT_USED(SGList_Handle_p);
+
+    return PEC_ERROR_NOT_IMPLEMENTED;
+#endif /* ADAPTER_PEC_ENABLE_SCATTERGATHER */
+}
+
+
+/*----------------------------------------------------------------------------
+ * PEC_SGList_Destroy
+ *
+ * This function must be used to destroy a SGList that was previously created
+ * with PEC_SGList_Create. The potentially referred fragments in the list are
+ * not freed by the implementation!
+ *
+ * SGList_Handle (input)
+ *     The handle to the SGList as returned by PEC_SGList_Create.
+ *
+ * DMABuf_Release may be called instead of this function.
+ */
+PEC_Status_t
+PEC_SGList_Destroy(
+        DMABuf_Handle_t SGList_Handle)
+{
+#ifdef ADAPTER_PEC_ENABLE_SCATTERGATHER
+    int dmares;
+
+    dmares = DMAResource_Release(
+        Adapter_DMABuf_Handle2DMAResourceHandle(SGList_Handle));
+
+    if (dmares == 0)
+        return PEC_STATUS_OK;
+
+    return PEC_ERROR_BAD_HANDLE;
+#else
+    IDENTIFIER_NOT_USED(SGList_Handle.p);
+
+    return PEC_ERROR_NOT_IMPLEMENTED;
+#endif /* ADAPTER_PEC_ENABLE_SCATTERGATHER */
+}
+
+
+/*----------------------------------------------------------------------------
+ * PEC_SGList_Write
+ */
+PEC_Status_t
+PEC_SGList_Write(
+        DMABuf_Handle_t SGList_Handle,
+        const unsigned int Index,
+        DMABuf_Handle_t FragmentHandle,
+        const unsigned int FragmentByteCount)
+{
+#ifdef ADAPTER_PEC_ENABLE_SCATTERGATHER
+    PEC_SGList_t * SGList_p;
+
+    SGList_p = Adapter_Handle2SGListPtr(SGList_Handle);
+    if (SGList_p == NULL)
+        return PEC_ERROR_BAD_HANDLE;
+
+    if (Index >= SGList_p->ListCapacity)
+        return PEC_ERROR_BAD_PARAMETER;
+
+    SGList_p->Entries[Index].Handle = FragmentHandle;
+    SGList_p->Entries[Index].ByteCount = FragmentByteCount;
+
+    return PEC_STATUS_OK;
+#else
+    IDENTIFIER_NOT_USED(SGList_Handle.p);
+    IDENTIFIER_NOT_USED(Index);
+    IDENTIFIER_NOT_USED(FragmentHandle.p);
+    IDENTIFIER_NOT_USED(FragmentByteCount);
+
+    return PEC_ERROR_NOT_IMPLEMENTED;
+#endif /* ADAPTER_PEC_ENABLE_SCATTERGATHER */
+}
+
+
+/*----------------------------------------------------------------------------
+ * PEC_SGList_Read
+ */
+PEC_Status_t
+PEC_SGList_Read(
+        DMABuf_Handle_t SGList_Handle,
+        const unsigned int Index,
+        DMABuf_Handle_t * const FragmentHandle_p,
+        unsigned int * const FragmentSizeInBytes_p,
+        uint8_t ** const FragmentPtr_p)
+{
+#ifdef ADAPTER_PEC_ENABLE_SCATTERGATHER
+    PEC_SGList_t * SGList_p;
+
+    // initialize the output parameters
+    {
+        if (FragmentHandle_p)
+            *FragmentHandle_p = DMABuf_NULLHandle;
+
+        if (FragmentSizeInBytes_p)
+            *FragmentSizeInBytes_p = 0;
+
+        if (FragmentPtr_p)
+            *FragmentPtr_p = NULL;
+    }
+
+    SGList_p = Adapter_Handle2SGListPtr(SGList_Handle);
+    if (SGList_p == NULL)
+        return PEC_ERROR_BAD_HANDLE;
+
+    if (Index >= SGList_p->ListCapacity)
+        return PEC_ERROR_BAD_PARAMETER;
+
+    // fill in the output parameters
+    {
+        if (FragmentHandle_p)
+            *FragmentHandle_p = SGList_p->Entries[Index].Handle;
+
+        if (FragmentSizeInBytes_p)
+            *FragmentSizeInBytes_p = SGList_p->Entries[Index].ByteCount;
+
+        if (FragmentPtr_p)
+        {
+            // retrieve the host address from the DMA resource record
+            DMAResource_Handle_t DMAHandle;
+            DMAResource_Record_t * Rec_p;
+
+            DMAHandle = Adapter_DMABuf_Handle2DMAResourceHandle(
+                SGList_p->Entries[Index].Handle);
+            Rec_p = DMAResource_Handle2RecordPtr(DMAHandle);
+            if (Rec_p)
+            {
+                // it is a valid handle
+                *FragmentPtr_p = Adapter_DMAResource_HostAddr(DMAHandle);
+            }
+        }
+    }
+
+    return PEC_STATUS_OK;
+#else
+    IDENTIFIER_NOT_USED(SGList_Handle.p);
+    IDENTIFIER_NOT_USED(Index);
+    IDENTIFIER_NOT_USED(FragmentHandle_p);
+    IDENTIFIER_NOT_USED(FragmentSizeInBytes_p);
+    IDENTIFIER_NOT_USED(FragmentPtr_p);
+
+    return PEC_ERROR_NOT_IMPLEMENTED;
+#endif /* ADAPTER_PEC_ENABLE_SCATTERGATHER */
+}
+
+
+/*----------------------------------------------------------------------------
+ * PEC_SGList_GetCapacity
+ */
+PEC_Status_t
+PEC_SGList_GetCapacity(
+        DMABuf_Handle_t SGList_Handle,
+        unsigned int * const ListCapacity_p)
+{
+#ifdef ADAPTER_PEC_ENABLE_SCATTERGATHER
+    PEC_SGList_t * SGList_p;
+
+    if (ListCapacity_p == NULL)
+        return PEC_ERROR_BAD_PARAMETER;
+
+    // initialize the output parameter
+    *ListCapacity_p = 0;
+
+    SGList_p = Adapter_Handle2SGListPtr(SGList_Handle);
+    if (SGList_p != NULL)
+        *ListCapacity_p = SGList_p->ListCapacity;
+
+    return PEC_STATUS_OK;
+#else
+    IDENTIFIER_NOT_USED(SGList_Handle.p);
+    IDENTIFIER_NOT_USED(ListCapacity_p);
+
+    return PEC_ERROR_NOT_IMPLEMENTED;
+#endif /* ADAPTER_PEC_ENABLE_SCATTERGATHER */
+}
+
+
+
+/* end of file adapter_pec_sglist.c */
diff --git a/package-21.02/kernel/crypto-eip/src/ddk/slad/lkm/adapter_firmware.c b/package-21.02/kernel/crypto-eip/src/ddk/slad/lkm/adapter_firmware.c
new file mode 100644
index 0000000..4603741
--- /dev/null
+++ b/package-21.02/kernel/crypto-eip/src/ddk/slad/lkm/adapter_firmware.c
@@ -0,0 +1,139 @@
+/* adapter_firmware.c
+ *
+ * Kernel-space implementation of Interface for obtaining the firmware image.
+ * Read from file system using Linux firmware API.
+ */
+
+/*****************************************************************************
+* Copyright (c) 2016-2020 by Rambus, Inc. and/or its subsidiaries.
+*
+* This program is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 2 of the License, or
+* any later version.
+*
+* This program is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with this program. If not, see <http://www.gnu.org/licenses/>.
+*****************************************************************************/
+
+
+/*----------------------------------------------------------------------------
+ * This module implements (provides) the following interface(s):
+ */
+
+#include "adapter_firmware.h"
+
+/*----------------------------------------------------------------------------
+ * This module uses (requires) the following interface(s):
+ */
+#include "c_adapter_firmware.h"
+
+// Driver Framework Basic Defs API
+#include "basic_defs.h"
+
+#include <linux/firmware.h>
+
+#include "adapter_alloc.h"
+
+// Logging API
+#include "log.h"
+
+#include "device_mgmt.h"  // Device_GetReference()
+
+/*----------------------------------------------------------------------------
+ * Adapter_Firmware_NULL
+ *
+ */
+const Adapter_Firmware_t Adapter_Firmware_NULL = NULL;
+
+
+/*----------------------------------------------------------------------------
+ * Adapter_Firmware_Acquire
+ */
+Adapter_Firmware_t
+Adapter_Firmware_Acquire(
+    const char * Firmware_Name_p,
+    const uint32_t ** Firmware_p,
+    unsigned int  * Firmware_Word32Count)
+{
+    uint32_t * Firmware_Data_p;
+    const struct firmware  *firmware;
+    int rc;
+    unsigned int i;
+
+    LOG_CRIT("Adapter_Firmware_Acquire for %s\n",Firmware_Name_p);
+
+    // Initialize output parameters.
+    *Firmware_p = NULL;
+    *Firmware_Word32Count = 0;
+
+    // Request firmware via kernel API.
+    rc = request_firmware(&firmware,
+                          Firmware_Name_p,
+                          Device_GetReference(NULL, NULL));
+    if (rc < 0)
+    {
+        LOG_CRIT("Adapter_Firmware_Acquire request of %s failed, rc=%d\n",
+                 Firmware_Name_p, rc);
+        return NULL;
+    }
+
+    if (firmware->data == NULL ||
+        firmware->size == 0 ||
+        firmware->size >= 256*1024 ||
+        firmware->size % sizeof(uint32_t) != 0)
+    {
+        LOG_CRIT("Adapter_Firmware_Acquire: Invalid image size %d\n",
+                 (int)firmware->size);
+        release_firmware(firmware);
+        return NULL;
+    }
+
+    // Allocate buffer for data
+    Firmware_Data_p = Adapter_Alloc(firmware->size);
+    if (Firmware_Data_p == NULL)
+    {
+        LOG_CRIT("Adapter_Firmware_Acquire: Failed to allocate\n");
+        release_firmware(firmware);
+        return NULL;
+    }
+
+    // Convert bytes from file to array of 32-bit words.
+    {
+        const uint8_t *p = firmware->data;
+        for (i=0; i<firmware->size / sizeof(uint32_t); i++)
+        {
+            Firmware_Data_p[i] = p[0] | (p[1]<<8) | (p[2]<<16) | (p[3]<<24);
+            p += sizeof(uint32_t);
+        }
+    }
+
+    // Pass results to caller
+    *Firmware_p = Firmware_Data_p;
+    *Firmware_Word32Count = firmware->size / sizeof(uint32_t);
+
+    // Release firmware data structure.
+    release_firmware(firmware);
+
+    return (Adapter_Firmware_t)Firmware_Data_p;
+}
+
+/*----------------------------------------------------------------------------
+ * Adapter_Firmware_Release
+ */
+void
+Adapter_Firmware_Release(
+    Adapter_Firmware_t FirmwareHandle)
+{
+    LOG_CRIT("Adapter_Firmware_Release\n");
+    Adapter_Free((void*)FirmwareHandle);
+}
+
+
+
+/* end of file adapter_firmware.c */
diff --git a/package-21.02/kernel/crypto-eip/src/ddk/slad/lkm/adapter_getpid.c b/package-21.02/kernel/crypto-eip/src/ddk/slad/lkm/adapter_getpid.c
new file mode 100644
index 0000000..0465a50
--- /dev/null
+++ b/package-21.02/kernel/crypto-eip/src/ddk/slad/lkm/adapter_getpid.c
@@ -0,0 +1,42 @@
+/* adapter_getpid.c
+ *
+ * Linux kernel specific Adapter module
+ * responsible for adapter-wide pid management.
+ */
+
+/*****************************************************************************
+* Copyright (c) 2015-2020 by Rambus, Inc. and/or its subsidiaries.
+*
+* This program is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 2 of the License, or
+* any later version.
+*
+* This program is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with this program. If not, see <http://www.gnu.org/licenses/>.
+*****************************************************************************/
+
+// Adapter GetPid API
+#include "adapter_getpid.h"
+
+// Linux Kernel API
+#include <asm/current.h>       // process information
+#include <linux/sched.h>       // for "struct task_struct"
+
+
+/*----------------------------------------------------------------------------
+ * Adapter_GetPid
+ */
+int
+Adapter_GetPid(void)
+{
+    return (int)current->pid;
+}
+
+
+/* end of file adapter_getpid.c */
diff --git a/package-21.02/kernel/crypto-eip/src/ddk/slad/lkm/adapter_interrupts.c b/package-21.02/kernel/crypto-eip/src/ddk/slad/lkm/adapter_interrupts.c
new file mode 100644
index 0000000..5d8779c
--- /dev/null
+++ b/package-21.02/kernel/crypto-eip/src/ddk/slad/lkm/adapter_interrupts.c
@@ -0,0 +1,830 @@
+/* adapter_interrupts.c
+ *
+ * Adapter EIP-202 module responsible for interrupts.
+ *
+ */
+
+/*****************************************************************************
+* Copyright (c) 2008-2022 by Rambus, Inc. and/or its subsidiaries.
+*
+* This program is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 2 of the License, or
+* any later version.
+*
+* This program is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with this program. If not, see <http://www.gnu.org/licenses/>.
+*****************************************************************************/
+
+
+/*----------------------------------------------------------------------------
+ * This module implements (provides) the following interface(s):
+ */
+
+#include "adapter_interrupts.h"
+
+
+/*----------------------------------------------------------------------------
+ * This module uses (requires) the following interface(s):
+ */
+
+// Default Adapter configuration
+#include "c_adapter_eip202.h"      // ADAPTER_*INTERRUPT*
+
+// Driver Framework Basic Definitions API
+#include "basic_defs.h"            // bool, IDENTIFIER_NOT_USED
+
+// Driver Framework C-RunTime Library API
+#include "clib.h"                  // ZEROINIT
+
+// EIP-201 Advanced interrupt Controller (AIC)
+#include "eip201.h"
+
+// Logging API
+#include "log.h"
+
+// Driver Framework Device API
+#include "device_types.h"          // Device_Handle_t
+#include "device_mgmt.h"           // Device_Find, Device_GetReference
+
+// Linux Kernel API
+#include <linux/interrupt.h>       // request_irq, free_irq,
+                                   // DECLARE_TASKLET, tasklet_schedule,
+                                   // IRQ_DISABLED
+#include <linux/irq.h>             // IRQ_TYPE_LEVEL_HIGH
+#include <linux/irqreturn.h>       // irqreturn_t
+
+#ifdef ADAPTER_EIP202_USE_UMDEVXS_IRQ
+#include "umdevxs_interrupt.h"
+#endif
+
+/*----------------------------------------------------------------------------
+ * Definitions and macros
+ */
+
+#define MAX_OS_IRQS                     256
+
+#define ARRAY_ELEMCOUNT(_a)             (sizeof(_a) / sizeof(_a[0]))
+
+#define ADAPTERINT_REQUEST_IRQ_FLAGS    (IRQF_SHARED)
+
+// Data structure for each Advanced interrupt controller
+typedef struct
+{
+    Device_Handle_t Device;
+    char *name;    // Device name (can be found with Device_Find().
+    int irq_idx;   // if isIRQ, then index of device interrupt.
+        // If !isIRQ. then driver IRQ number to which AIC is connected.
+    int irq;       // System IRQ number
+    int BitIRQs[32]; // Mapping from source bits to internal driver IRQ numbers.
+    bool isIRQ; // true if AIC has dedicated system IRQ line, false is it
+                // is cascaded from another AIC.
+} Adapter_AIC_t;
+
+// Data structure per interrupt
+typedef struct
+{
+    uint32_t SourceBitMask;
+    char * name;
+    Adapter_AIC_t *AIC;
+    char *AICName;
+    struct tasklet_struct tasklet;
+    Adapter_InterruptHandler_t Handler;
+    uint32_t Counter;
+    void *extra;
+    bool fHaveTasklet;
+    EIP201_Config_t Config;
+} Adapter_Interrupt_t;
+
+
+/*----------------------------------------------------------------------------
+ * Local variables
+ */
+static bool Adapter_IRQ_Initialized = false;
+
+#define ADAPTER_EIP202_ADD_AIC(_name,_idx, isirq)  \
+    {NULL, _name, _idx, -1, {0, }, isirq}
+
+
+static Adapter_AIC_t Adapter_AICTable[] = { ADAPTER_EIP202_AICS };
+
+#define ADAPTER_EIP202_ADD_IRQ(_name,_phy,_aicname,_tasklet,_pol)    \
+    {(1<<(_phy)),#_name,NULL,_aicname,{},NULL,0,NULL,_tasklet, \
+                                              EIP201_CONFIG_##_pol}
+
+static Adapter_Interrupt_t Adapter_IRQTable[] = { ADAPTER_EIP202_IRQS };
+
+// Define maximum number of supported interrupts
+#define ADAPTER_MAX_INTERRUPTS  ARRAY_ELEMCOUNT(Adapter_IRQTable)
+
+static Adapter_AIC_t * IRQ_AIC_Mapping[MAX_OS_IRQS];
+
+
+/*----------------------------------------------------------------------------
+ * AdapterINT_GetActiveIntNr
+ *
+ * Returns 0..31 depending on the lowest '1' bit.
+ * Returns 32 when all bits are zero
+ *
+ * Using binary break-down algorithm.
+ */
+static inline int
+AdapterINT_GetActiveIntNr(
+        uint32_t Sources)
+{
+    unsigned int IntNr = 0;
+    unsigned int R16, R8, R4, R2;
+
+    if (Sources == 0)
+        return 32;
+
+    // if the lower 16 bits are empty, look at the upper 16 bits
+    R16 = Sources & 0xFFFF;
+    if (R16 == 0)
+    {
+        IntNr += 16;
+        R16 = Sources >> 16;
+    }
+
+    // if the lower 8 bits are empty, look at the high 8 bits
+    R8 = R16 & 0xFF;
+    if (R8 == 0)
+    {
+        IntNr += 8;
+        R8 = R16 >> 8;
+    }
+    R4 = R8 & 0xF;
+    if (R4 == 0)
+    {
+        IntNr += 4;
+        R4 = R8 >> 4;
+    }
+
+    R2 = R4 & 3;
+    if (R2 == 0)
+    {
+        IntNr += 2;
+        R2 = R4 >> 2;
+    }
+
+    // last two bits are trivial
+    // 00 => cannot happen
+    // 01 => +0
+    // 10 => +1
+    // 11 => +0
+    if (R2 == 2)
+        IntNr++;
+
+    return IntNr;
+}
+
+
+/*----------------------------------------------------------------------------
+ * AdapterINT_Report_InterruptCounters
+ */
+static void
+AdapterINT_Report_InterruptCounters(void)
+{
+    int i;
+    for (i=0; i<ARRAY_ELEMCOUNT(Adapter_IRQTable); i++)
+    {
+        if ( (1<<i) & ADAPTER_EIP202_INTERRUPTS_TRACEFILTER)
+        {
+            LOG_CRIT("AIC %s interrupt source %s mask %08x counter %d\n",
+                     Adapter_IRQTable[i].AICName,
+                     Adapter_IRQTable[i].name,
+                     Adapter_IRQTable[i].SourceBitMask,
+                     Adapter_IRQTable[i].Counter);
+        }
+    }
+}
+
+
+/*----------------------------------------------------------------------------
+ * Adapter_Interrupt_Enable
+ */
+int
+Adapter_Interrupt_Enable(
+        const int nIRQ,
+        const unsigned int Flags)
+{
+    int rc = -1;
+    IDENTIFIER_NOT_USED(Flags);
+
+    LOG_INFO("\n\t\t %s \n", __func__);
+
+    if (nIRQ < 0 || nIRQ >= ADAPTER_MAX_INTERRUPTS)
+    {
+            LOG_CRIT(
+                    "Adapter_Interrupt_Enable: "
+                    "Failed, IRQ %d not supported\n",
+                    nIRQ);
+    }
+    else
+    {
+        rc=EIP201_SourceMask_EnableSource(Adapter_IRQTable[nIRQ].AIC->Device,
+                                       Adapter_IRQTable[nIRQ].SourceBitMask);
+        LOG_INFO("\n\t\t\tAdapter_Interrupt_Enable "
+                 "IRQ %d %s %s mask=%08x\n",
+                 nIRQ,
+                 Adapter_IRQTable[nIRQ].AICName,
+                 Adapter_IRQTable[nIRQ].name,
+                 Adapter_IRQTable[nIRQ].SourceBitMask);
+   }
+
+    LOG_INFO("\n\t\t %s done \n", __func__);
+    return rc;
+}
+
+
+/*----------------------------------------------------------------------------
+ * Adapter_Interrupt_Disable
+ */
+int
+Adapter_Interrupt_Disable(
+        const int nIRQ,
+        const unsigned int Flags)
+{
+    int rc = -1;
+    IDENTIFIER_NOT_USED(Flags);
+
+    LOG_INFO("\n\t\t %s \n", __func__);
+
+    if (nIRQ < 0 || nIRQ >= ADAPTER_MAX_INTERRUPTS)
+    {
+            LOG_CRIT(
+                    "Adapter_Interrupt_Disable: "
+                    "Failed, IRQ %d not supported\n",
+                    nIRQ);
+    }
+    else
+    {
+        rc = EIP201_SourceMask_DisableSource(Adapter_IRQTable[nIRQ].AIC->Device,
+                                       Adapter_IRQTable[nIRQ].SourceBitMask);
+        LOG_INFO("\n\t\t\tAdapter_Interrupt_Disable "
+                 "IRQ %d %s %s mask=%08x\n",
+                 nIRQ,
+                 Adapter_IRQTable[nIRQ].AICName,
+                 Adapter_IRQTable[nIRQ].name,
+                 Adapter_IRQTable[nIRQ].SourceBitMask);
+    }
+
+    LOG_INFO("\n\t\t %s done \n", __func__);
+    return rc;
+}
+
+
+/*----------------------------------------------------------------------------
+ * Adapter_Interrupt_SetHandler
+ */
+int
+Adapter_Interrupt_SetHandler(
+        const int nIRQ,
+        Adapter_InterruptHandler_t HandlerFunction)
+{
+    if (nIRQ < 0 || nIRQ >= ADAPTER_MAX_INTERRUPTS)
+        return -1;
+
+    LOG_INFO(
+            "Adapter_Interrupt_SetHandler: "
+            "HandlerFnc=%p for IRQ %d\n",
+            HandlerFunction,
+            nIRQ);
+
+    Adapter_IRQTable[nIRQ].Handler = HandlerFunction;
+    return 0;
+}
+
+
+/*----------------------------------------------------------------------------
+ * AdapterINT_CommonTasklet
+ *
+ * This handler is scheduled in the top-halve interrupt handler when it
+ * decodes one of the CDR or RDR interrupt sources.
+ * The data parameter is the IRQ value (from adapter_interrupts.h) for that
+ * specific interrupt source.
+ */
+static void
+AdapterINT_CommonTasklet(
+        unsigned long data)
+{
+    const unsigned int IntNr = (unsigned int)data;
+    Adapter_InterruptHandler_t H;
+
+    LOG_INFO("\n\t\t%s \n", __func__);
+
+    LOG_INFO("Tasklet invoked intnr=%d\n",IntNr);
+
+    // verify we have a handler
+    H = Adapter_IRQTable[IntNr].Handler;
+
+    if (H)
+    {
+        // invoke the handler
+        H(IntNr, 0);
+    }
+    else
+    {
+        LOG_CRIT(
+            "AdapterINT_CommonTasklet: "
+            "Error, disabling IRQ %d with missing handler\n",
+            IntNr);
+
+        Adapter_Interrupt_Disable(IntNr, 0);
+    }
+
+    LOG_INFO("\n\t\t%s done\n", __func__);
+}
+
+
+/*----------------------------------------------------------------------------
+ * AdapterINT_AICHandler
+ *
+ * Handle all interrupts connected to the specified AIC.
+ *
+ * If this AIC is connected directly to a system IRQ line, this is
+ * called directly from the Top Half Handler.
+ *
+ * If this AIC is connected via an IRQ line of another AIC, this is
+ * called from the handler function of that interrupt.
+ *
+ * Return: 0 for success, -1 for failure.
+ */
+static int
+AdapterINT_AICHandler(Adapter_AIC_t *AIC)
+{
+    EIP201_SourceBitmap_t Sources;
+    int IntNr, irq, rc = 0;
+
+    LOG_INFO("\n\t\t%s \n", __func__);
+
+    if (AIC == NULL)
+        return -1;
+
+    if (AIC->Device == NULL)
+    {
+        LOG_INFO("%s: skipping spurious interrupt for AIC %s, IRQ %d\n",
+                 __func__,
+                 AIC->name,
+                 AIC->irq);
+        goto exit; // no error
+    }
+
+    Sources = EIP201_SourceStatus_ReadAllEnabled(AIC->Device);
+    if (Sources == 0)
+    {
+        rc = -1;
+        goto exit; // error
+    }
+
+    EIP201_Acknowledge(AIC->Device, Sources);
+
+    LOG_INFO("%s: AIC %s, IRQ %d, sources=%x\n",
+             __func__,
+             AIC->name,
+             AIC->irq,
+             Sources);
+
+    while (Sources)
+    {
+        IntNr = AdapterINT_GetActiveIntNr(Sources);
+
+        /* Get number of first bit set */
+        Sources &= ~(1<<IntNr);
+
+        /* Clear this in sources */
+        irq = AIC->BitIRQs[IntNr];
+
+        LOG_INFO("%s: Handle IRQ %d for AIC %s\n", __func__, irq, AIC->name);
+
+        if (irq < 0 || irq >= ADAPTER_MAX_INTERRUPTS)
+        {
+            LOG_CRIT("%s: %s IRQ not defined for bit %d, disabling source\n",
+                     __func__,
+                     AIC->name,
+                     IntNr);
+            EIP201_SourceMask_DisableSource(AIC->Device, (1<<IntNr));
+        }
+
+        Adapter_IRQTable[irq].Counter++;
+
+        if ( (1<<irq) & ADAPTER_EIP202_INTERRUPTS_TRACEFILTER)
+            LOG_CRIT("%s: encountered interrupt %d, bit %d for AIC %s\n",
+                     __func__,
+                     irq,
+                     IntNr,
+                     AIC->name);
+
+        if(Adapter_IRQTable[irq].fHaveTasklet)
+        {
+            LOG_INFO("%s: Start tasklet\n", __func__);
+            /* IRQ is handled via tasklet */
+            tasklet_schedule(&Adapter_IRQTable[irq].tasklet);
+            Adapter_Interrupt_Disable(irq, 0);
+        }
+        else
+        {
+            Adapter_InterruptHandler_t H = Adapter_IRQTable[irq].Handler;
+            LOG_INFO("%s: Run normal handler\n", __func__);
+            /* Handler is called directly */
+            if (H)
+            {
+                H(irq, 0);
+            }
+            else
+            {
+                LOG_CRIT(
+                    "%s : Error, disabling IRQ %d with missing handler\n",
+                    __func__,
+                    irq);
+
+                Adapter_Interrupt_Disable(irq, 0);
+            }
+        }
+    } // while
+
+exit:
+    LOG_INFO("\n\t\t%s done\n", __func__);
+    return rc;
+}
+
+
+/*----------------------------------------------------------------------------
+ * AdapterINT_TopHalfHandler
+ *
+ * This is the interrupt handler function call by the kernel when our hooked
+ * interrupt is active.
+ *
+ * Call the handler for the associated AIC.
+ */
+static irqreturn_t
+AdapterINT_TopHalfHandler(
+        int irq,
+        void * dev_id)
+{
+    irqreturn_t Int_Rc = IRQ_NONE;
+    LOG_INFO("\n\t\t%s \n", __func__);
+
+    if (irq < 0 || irq >= MAX_OS_IRQS || IRQ_AIC_Mapping[irq]==NULL)
+    {
+        LOG_CRIT("%s: No AIC defined for IRQ %d\n",__func__,irq);
+        goto error;
+    }
+
+    if ( AdapterINT_AICHandler(IRQ_AIC_Mapping[irq]) < 0)
+    {
+        goto error;
+    }
+
+    Int_Rc = IRQ_HANDLED;
+
+error:
+    LOG_INFO("\n\t\t%s done\n", __func__);
+
+    IDENTIFIER_NOT_USED(dev_id);
+    return Int_Rc;
+}
+
+
+/*----------------------------------------------------------------------------
+ * AdapterINT_ChainedAIC
+ *
+ * Handler function for IRQ that services an entire AIC.
+ */
+static void
+AdapterINT_ChainedAIC(const int irq, const unsigned int flags)
+{
+    IDENTIFIER_NOT_USED(flags);
+    AdapterINT_AICHandler(Adapter_IRQTable[irq].extra);
+}
+
+
+/*----------------------------------------------------------------------------
+ * AdapterINT_SetInternalLinkage
+ *
+ * Create AIC References in Adapter_IRQTable.
+ * Fill in BitIRQs references in Adapter_AICTable.
+ * Perform some consistency checks.
+ *
+ * Return 0 on success, -1 on failure.
+ */
+static int
+AdapterINT_SetInternalLinkage(void)
+{
+    int i,j;
+    int IntNr;
+
+    for (i=0; i<ARRAY_ELEMCOUNT(Adapter_IRQTable); i++)
+    {
+        Adapter_IRQTable[i].AIC = NULL;
+    }
+
+    for (i=0; i<ARRAY_ELEMCOUNT(Adapter_AICTable); i++)
+    {
+        for (j=0; j<32; j++)
+        {
+            Adapter_AICTable[i].BitIRQs[j] = -1;
+        }
+        for (j=0; j<ARRAY_ELEMCOUNT(Adapter_IRQTable); j++)
+        {
+            if (strcmp(Adapter_AICTable[i].name, Adapter_IRQTable[j].AICName)
+                == 0)
+            {
+                if (Adapter_IRQTable[j].AIC)
+                {
+                    LOG_CRIT("%s: AIC link set more than once\n",__func__);
+                }
+                Adapter_IRQTable[j].AIC = Adapter_AICTable + i;
+                IntNr = AdapterINT_GetActiveIntNr(
+                    Adapter_IRQTable[j].SourceBitMask);
+                if (IntNr < 0 || IntNr >= 32)
+                {
+                    LOG_CRIT("%s: IRQ %d source bit %d out of range\n",
+                             __func__,j,IntNr);
+                    return -1;
+                }
+                else if (Adapter_AICTable[i].BitIRQs[IntNr] >= 0)
+                {
+                    LOG_CRIT(
+                        "%s: AIC %s IRQ %d source bit %d already defined\n",
+                        __func__,
+                        Adapter_AICTable[i].name,
+                        j,
+                        IntNr);
+                    return -1;
+                }
+                else
+                {
+                    Adapter_AICTable[i].BitIRQs[IntNr] = j;
+                }
+            }
+        }
+    }
+    for (i=0; i<ARRAY_ELEMCOUNT(Adapter_IRQTable); i++)
+    {
+        if (Adapter_IRQTable[i].AIC == NULL)
+        {
+            LOG_CRIT("%s: AIC pointer of IRQ %d is null\n",__func__,i);
+            return -1;
+        }
+    }
+
+    return 0;
+}
+
+
+/*----------------------------------------------------------------------------
+ * AdapterINT_AIC_Init
+ *
+ */
+static bool
+AdapterINT_AIC_Init(void)
+{
+    EIP201_Status_t res;
+    unsigned int i;
+
+    // Initialize all configured EIP-201 AIC devices
+    for (i = 0; i < ARRAY_ELEMCOUNT(Adapter_AICTable); i++)
+    {
+        LOG_INFO("%s: Initialize AIC %s\n",__func__,Adapter_AICTable[i].name);
+
+        Adapter_AICTable[i].Device = Device_Find(Adapter_AICTable[i].name);
+        if (Adapter_AICTable[i].Device == NULL)
+        {
+            LOG_CRIT("%s: Device_Find() failed for %s\n",
+                     __func__,
+                     Adapter_AICTable[i].name);
+            return false; // error
+        }
+
+        res = EIP201_Initialize(Adapter_AICTable[i].Device, NULL, 0);
+        if (res != EIP201_STATUS_SUCCESS)
+        {
+            LOG_CRIT("%s: EIP201_Initialize() failed, error %d\n", __func__, res);
+            return false; // error
+        }
+    }
+
+    return true; // success
+}
+
+
+/*----------------------------------------------------------------------------
+ * AdapterINT_AIC_Enable
+ *
+ */
+static void
+AdapterINT_AIC_Enable(void)
+{
+    unsigned int i;
+
+    for (i = 0; i < ARRAY_ELEMCOUNT(Adapter_AICTable); i++)
+        if (!Adapter_AICTable[i].isIRQ)
+            Adapter_Interrupt_Enable(Adapter_AICTable[i].irq_idx, 0);
+}
+
+
+/*----------------------------------------------------------------------------
+ * Adapter_Interrupts_Init
+ *
+ */
+int
+Adapter_Interrupts_Init(
+        const int nIRQ)
+{
+    int i;
+    int IntNr = nIRQ;
+
+    LOG_INFO("\n\t\t %s \n", __func__);
+
+    if (AdapterINT_SetInternalLinkage() < 0)
+    {
+        LOG_CRIT("Interrupt AIC and IRQ tables are inconsistent\n");
+        return -1;
+    }
+
+    // Initialize the AIC devices
+    if (!AdapterINT_AIC_Init())
+        return -1;
+
+    // Initialize the Adapter_IRQTable and tasklets.
+    for (i=0; i<ARRAY_ELEMCOUNT(Adapter_IRQTable); i++)
+    {
+        Adapter_IRQTable[i].Handler = NULL;
+        Adapter_IRQTable[i].extra = NULL;
+        Adapter_IRQTable[i].Counter = 0;
+        if (Adapter_IRQTable[i].fHaveTasklet)
+            tasklet_init(&Adapter_IRQTable[i].tasklet,
+                         AdapterINT_CommonTasklet,
+                         (long)i);
+        EIP201_Config_Change(Adapter_IRQTable[i].AIC->Device,
+                             Adapter_IRQTable[i].SourceBitMask,
+                             Adapter_IRQTable[i].Config);
+        // Clear any pending egde-sensitive interrupts.
+        EIP201_Acknowledge(Adapter_IRQTable[i].AIC->Device,
+                           Adapter_IRQTable[i].SourceBitMask);
+    }
+
+    // Request the IRQs for each AIC or register to IRQ of other AIC.
+    for (i=0; i<ARRAY_ELEMCOUNT(Adapter_AICTable); i++)
+    {
+        if (Adapter_AICTable[i].isIRQ)
+        {
+            int res;
+
+            LOG_INFO("\n\t\t %s: Request IRQ for AIC %s\n",
+                     __func__,Adapter_AICTable[i].name);
+
+#ifdef ADAPTER_EIP202_USE_UMDEVXS_IRQ
+            res = UMDevXS_Interrupt_Request(AdapterINT_TopHalfHandler,
+                                            Adapter_AICTable[i].irq_idx);
+            IntNr = res;
+#else
+            {
+                struct device * Device_p;
+                // Get device reference for this resource
+                Device_p = Device_GetReference(NULL, NULL);
+                res = request_irq(IntNr,
+                                  AdapterINT_TopHalfHandler,
+                                  ADAPTERINT_REQUEST_IRQ_FLAGS,
+                                  ADAPTER_EIP202_DRIVER_NAME,
+                                  Device_p);
+            }
+#endif
+            if (res < 0)
+            {
+                LOG_CRIT("%s: Request IRQ error %d\n", __func__, res);
+                return res;
+            }
+            else
+            {
+                Adapter_AICTable[i].irq = IntNr;
+                IRQ_AIC_Mapping[IntNr] = Adapter_AICTable + i;
+                LOG_INFO("%s: Successfully hooked IRQ %d\n", __func__, IntNr);
+            }
+        }
+        else
+        {
+            IntNr = Adapter_AICTable[i].irq_idx;
+            LOG_INFO("%s: Hook up AIC %s to chained IRQ %d\n",
+                     __func__,
+                     Adapter_AICTable[i].name,
+                     IntNr);
+            if (IntNr < 0 || IntNr >= ADAPTER_MAX_INTERRUPTS)
+            {
+                LOG_CRIT("%s: IRQ %d out of range\n", __func__,IntNr);
+            }
+            Adapter_IRQTable[IntNr].extra =  Adapter_AICTable + i;
+            Adapter_Interrupt_SetHandler(IntNr, AdapterINT_ChainedAIC);
+        }
+    }
+
+    // Enable AIC
+    AdapterINT_AIC_Enable();
+
+    LOG_INFO("\n\t\t %s done\n", __func__);
+    Adapter_IRQ_Initialized = true;
+
+    return 0;
+}
+
+
+/*----------------------------------------------------------------------------
+ * Adapter_Interrupts_UnInit
+ */
+int
+Adapter_Interrupts_UnInit(const int nIRQ)
+{
+    unsigned int i;
+    IDENTIFIER_NOT_USED(nIRQ);
+
+    LOG_INFO("\n\t\t %s \n", __func__);
+    if (!Adapter_IRQ_Initialized)
+        return -1;
+
+    // disable all interrupts
+    for (i = 0; i < ARRAY_ELEMCOUNT(Adapter_AICTable); i++)
+    {
+        if (Adapter_AICTable[i].Device)
+        {
+            EIP201_SourceMask_DisableSource(Adapter_AICTable[i].Device,
+                                            EIP201_SOURCE_ALL);
+            Adapter_AICTable[i].Device = NULL;
+        }
+
+        if(Adapter_AICTable[i].isIRQ && Adapter_AICTable[i].irq > 0)
+        {
+#ifdef ADAPTER_EIP202_USE_UMDEVXS_IRQ
+            UMDevXS_Interrupt_Request(NULL,Adapter_AICTable[i].irq_idx);
+#else
+            // Get device reference for this resource
+            struct device * Device_p = Device_GetReference(NULL, NULL);
+
+            LOG_INFO("%s: Free IRQ %d for AIC %s\n",
+                     __func__,
+                     Adapter_AICTable[i].irq,
+                     Adapter_AICTable[i].name);
+
+            // unhook the interrupt
+            free_irq(Adapter_AICTable[i].irq, Device_p);
+
+            LOG_INFO("%s: Successfully freed IRQ %d for AIC %s\n",
+                     __func__,
+                     Adapter_AICTable[i].irq,
+                     Adapter_AICTable[i].name);
+#endif
+        }
+    }
+
+    // Kill all tasklets
+    for (i = 0; i < ARRAY_ELEMCOUNT(Adapter_IRQTable); i++)
+        if (Adapter_IRQTable[i].fHaveTasklet)
+            tasklet_kill(&Adapter_IRQTable[i].tasklet);
+
+    AdapterINT_Report_InterruptCounters();
+
+    ZEROINIT(IRQ_AIC_Mapping);
+
+    Adapter_IRQ_Initialized = false;
+
+    LOG_INFO("\n\t\t %s done\n", __func__);
+
+    return 0;
+}
+
+
+#ifdef ADAPTER_PEC_RPM_EIP202_DEVICE0_ID
+/*----------------------------------------------------------------------------
+ * Adapter_Interrupts_Resume
+ */
+int
+Adapter_Interrupts_Resume(void)
+{
+    LOG_INFO("\n\t\t %s \n", __func__);
+
+    if (!Adapter_IRQ_Initialized)
+    {
+        LOG_CRIT("%s: failed, not initialized\n", __func__);
+        return -1;
+    }
+
+    // Resume AIC devices
+    if (!AdapterINT_AIC_Init())
+        return -2; // error
+
+    // Re-enable AIC interrupts
+    AdapterINT_AIC_Enable();
+
+    LOG_INFO("\n\t\t %s done\n", __func__);
+
+    return 0; // success
+}
+#endif
+
+
+/* end of file adapter_interrupts.c */
diff --git a/package-21.02/kernel/crypto-eip/src/ddk/slad/lkm/adapter_lock.c b/package-21.02/kernel/crypto-eip/src/ddk/slad/lkm/adapter_lock.c
new file mode 100644
index 0000000..38b663f
--- /dev/null
+++ b/package-21.02/kernel/crypto-eip/src/ddk/slad/lkm/adapter_lock.c
@@ -0,0 +1,118 @@
+/* adapter_lock.c
+ *
+ * Adapter concurrency (locking) management
+ * Linux kernel-space implementation
+ *
+ */
+
+/*****************************************************************************
+* Copyright (c) 2013-2020 by Rambus, Inc. and/or its subsidiaries.
+*
+* This program is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 2 of the License, or
+* any later version.
+*
+* This program is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with this program. If not, see <http://www.gnu.org/licenses/>.
+*****************************************************************************/
+
+/*----------------------------------------------------------------------------
+ * This module implements (provides) the following interface(s):
+ */
+
+// Adapter locking API
+#include "adapter_lock.h"
+
+
+/*----------------------------------------------------------------------------
+ * This module uses (requires) the following interface(s):
+ */
+
+// Driver Framework Basic Definitions API
+#include "basic_defs.h"         // IDENTIFIER_NOT_USED
+
+// Adapter Lock Internal API
+#include "adapter_lock_internal.h"
+
+// Adapter Memory Allocation API
+#include "adapter_alloc.h"
+
+// Logging API
+#undef LOG_SEVERITY_MAX
+#define LOG_SEVERITY_MAX    LOG_SEVERITY_WARN
+#include "log.h"
+
+// Linux Kernel API
+#include <linux/spinlock.h>     // spinlock_*
+
+
+/*----------------------------------------------------------------------------
+ * Definitions and macros
+ */
+
+
+/*----------------------------------------------------------------------------
+ * Adapter_Lock_Alloc
+ */
+Adapter_Lock_t
+Adapter_Lock_Alloc(void)
+{
+    spinlock_t * Lock_p;
+
+    size_t LockSize=sizeof(spinlock_t);
+    if (LockSize==0)
+        LockSize=4;
+
+    Lock_p = Adapter_Alloc(LockSize);
+    if (Lock_p == NULL)
+        return Adapter_Lock_NULL;
+
+    Log_FormattedMessage("%s: Lock = spinlock\n", __func__);
+
+    spin_lock_init(Lock_p);
+
+    return Lock_p;
+}
+
+
+/*----------------------------------------------------------------------------
+ * Adapter_Lock_Free
+ */
+void
+Adapter_Lock_Free(Adapter_Lock_t Lock)
+{
+    Adapter_Free((void*)Lock);
+}
+
+
+/*----------------------------------------------------------------------------
+ * Adapter_Lock_Acquire
+ */
+void
+Adapter_Lock_Acquire(
+        Adapter_Lock_t Lock,
+        unsigned long * Flags)
+{
+    spin_lock_irqsave((spinlock_t *)Lock, *Flags);
+}
+
+
+/*----------------------------------------------------------------------------
+ * Adapter_Lock_Release
+ */
+void
+Adapter_Lock_Release(
+        Adapter_Lock_t Lock,
+        unsigned long * Flags)
+{
+    spin_unlock_irqrestore((spinlock_t *)Lock, *Flags);
+}
+
+
+/* end of file adapter_lock.c */
diff --git a/package-21.02/kernel/crypto-eip/src/ddk/slad/lkm/adapter_sleep.c b/package-21.02/kernel/crypto-eip/src/ddk/slad/lkm/adapter_sleep.c
new file mode 100644
index 0000000..88e4be0
--- /dev/null
+++ b/package-21.02/kernel/crypto-eip/src/ddk/slad/lkm/adapter_sleep.c
@@ -0,0 +1,45 @@
+/* adapter_sleep.c
+ *
+ * Linux kernel specific Adapter module
+ * responsible for adapter-wide time management.
+ */
+
+/*****************************************************************************
+* Copyright (c) 2008-2020 by Rambus, Inc. and/or its subsidiaries.
+*
+* This program is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 2 of the License, or
+* any later version.
+*
+* This program is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with this program. If not, see <http://www.gnu.org/licenses/>.
+*****************************************************************************/
+
+// Adapter Sleep API
+#include "adapter_sleep.h"
+
+// Driver Framework Basic Defs API
+#include "basic_defs.h"
+
+// Linux Kernel API
+#include <linux/delay.h>        // msleep, no-busy-waiting implementation
+
+
+/*----------------------------------------------------------------------------
+ * Adapter_SleepMS
+ */
+void
+Adapter_SleepMS(
+        const unsigned int Duration_ms)
+{
+    msleep(Duration_ms);
+}
+
+
+/* end of file adapter_sleep.c */