1/* SPDX-License-Identifier: BSD-3-Clause */
2/* Copyright(c) 2007-2022 Intel Corporation */
3/**
4 *****************************************************************************
5 * @file dc_header_footer.c
6 *
7 * @ingroup Dc_DataCompression
8 *
9 * @description
10 *      Implementation of the Data Compression header and footer operations.
11 *
12 *****************************************************************************/
13
14/*
15 *******************************************************************************
16 * Include public/global header files
17 *******************************************************************************
18 */
19#include "cpa.h"
20#include "cpa_dc.h"
21#include "icp_adf_init.h"
22
23/*
24 *******************************************************************************
25 * Include private header files
26 *******************************************************************************
27 */
28#include "dc_header_footer.h"
29#include "dc_session.h"
30#include "dc_datapath.h"
31
32CpaStatus
33cpaDcGenerateHeader(CpaDcSessionHandle pSessionHandle,
34		    CpaFlatBuffer *pDestBuff,
35		    Cpa32U *count)
36{
37	dc_session_desc_t *pSessionDesc = NULL;
38
39	LAC_CHECK_NULL_PARAM(pSessionHandle);
40	LAC_CHECK_NULL_PARAM(pDestBuff);
41	LAC_CHECK_NULL_PARAM(pDestBuff->pData);
42	LAC_CHECK_NULL_PARAM(count);
43
44	pSessionDesc = DC_SESSION_DESC_FROM_CTX_GET(pSessionHandle);
45
46	if (NULL == pSessionDesc) {
47		QAT_UTILS_LOG("Session handle not as expected\n");
48		return CPA_STATUS_INVALID_PARAM;
49	}
50
51	if (CPA_DC_DIR_DECOMPRESS == pSessionDesc->sessDirection) {
52		QAT_UTILS_LOG("Invalid session direction\n");
53		return CPA_STATUS_INVALID_PARAM;
54	}
55
56	if (CPA_DC_DEFLATE == pSessionDesc->compType) {
57		/* Adding a Gzip header */
58		if (CPA_DC_CRC32 == pSessionDesc->checksumType) {
59			Cpa8U *pDest = pDestBuff->pData;
60
61			if (pDestBuff->dataLenInBytes < DC_GZIP_HEADER_SIZE) {
62				QAT_UTILS_LOG(
63				    "The dataLenInBytes of the dest buffer is too small.\n");
64				return CPA_STATUS_INVALID_PARAM;
65			}
66
67			pDest[0] = DC_GZIP_ID1; /* ID1 */
68			pDest[1] = DC_GZIP_ID2; /* ID2 */
69			pDest[2] =
70			    0x08; /* CM = 8 denotes "deflate" compression */
71			pDest[3] = 0x00; /* FLG = 0 denotes "No extra fields" */
72			pDest[4] = 0x00;
73			pDest[5] = 0x00;
74			pDest[6] = 0x00;
75			pDest[7] = 0x00; /* MTIME = 0x00 means time stamp not
76					    available */
77
78			/* XFL = 4 - compressor used fastest compression, */
79			/* XFL = 2 - compressor used maximum compression. */
80			pDest[8] = 0;
81			if (CPA_DC_L1 == pSessionDesc->compLevel)
82				pDest[8] = DC_GZIP_FAST_COMP;
83			else if (CPA_DC_L4 >= pSessionDesc->compLevel)
84				pDest[8] = DC_GZIP_MAX_COMP;
85
86			pDest[9] =
87			    DC_GZIP_FILESYSTYPE; /* OS = 0 means FAT filesystem
88				  (MS-DOS, OS/2, NT/Win32), 3 - Unix */
89
90			/* Set to the number of bytes added to the buffer */
91			*count = DC_GZIP_HEADER_SIZE;
92		}
93
94		/* Adding a Zlib header */
95		else if (CPA_DC_ADLER32 == pSessionDesc->checksumType) {
96			Cpa8U *pDest = pDestBuff->pData;
97			Cpa16U header = 0, level = 0;
98
99			if (pDestBuff->dataLenInBytes < DC_ZLIB_HEADER_SIZE) {
100				QAT_UTILS_LOG(
101				    "The dataLenInBytes of the dest buffer is too small.\n");
102				return CPA_STATUS_INVALID_PARAM;
103			}
104
105			/*  CMF = CM | CMINFO.
106			    CM = 8 denotes "deflate" compression,
107			    CMINFO = 7 indicates a 32K window size */
108			/* Depending on the device, at compression levels above
109			   L1, the
110			   window size can be 8 or 16K bytes.
111			   The file will decompress ok if a greater window size
112			   is specified
113			   in the header. */
114			header =
115			    (DC_ZLIB_CM_DEFLATE +
116			     (DC_32K_WINDOW_SIZE << DC_ZLIB_WINDOWSIZE_OFFSET))
117			    << LAC_NUM_BITS_IN_BYTE;
118
119			switch (pSessionDesc->compLevel) {
120			case CPA_DC_L1:
121				level = DC_ZLIB_LEVEL_0;
122				break;
123			case CPA_DC_L2:
124				level = DC_ZLIB_LEVEL_1;
125				break;
126			case CPA_DC_L3:
127				level = DC_ZLIB_LEVEL_2;
128				break;
129			default:
130				level = DC_ZLIB_LEVEL_3;
131			}
132
133			/* Bits 6 - 7: FLEVEL, compression level */
134			header |= level << DC_ZLIB_FLEVEL_OFFSET;
135
136			/* The header has to be a multiple of 31 */
137			header += DC_ZLIB_HEADER_OFFSET -
138			    (header % DC_ZLIB_HEADER_OFFSET);
139
140			pDest[0] = (Cpa8U)(header >> LAC_NUM_BITS_IN_BYTE);
141			pDest[1] = (Cpa8U)header;
142
143			/* Set to the number of bytes added to the buffer */
144			*count = DC_ZLIB_HEADER_SIZE;
145		}
146
147		/* If deflate but no checksum required */
148		else {
149			*count = 0;
150		}
151	} else {
152		/* There is no header for other compressed data */
153		*count = 0;
154	}
155	return CPA_STATUS_SUCCESS;
156}
157
158CpaStatus
159cpaDcGenerateFooter(CpaDcSessionHandle pSessionHandle,
160		    CpaFlatBuffer *pDestBuff,
161		    CpaDcRqResults *pRes)
162{
163	dc_session_desc_t *pSessionDesc = NULL;
164
165	LAC_CHECK_NULL_PARAM(pSessionHandle);
166	LAC_CHECK_NULL_PARAM(pDestBuff);
167	LAC_CHECK_NULL_PARAM(pDestBuff->pData);
168	LAC_CHECK_NULL_PARAM(pRes);
169
170	pSessionDesc = DC_SESSION_DESC_FROM_CTX_GET(pSessionHandle);
171
172	if (NULL == pSessionDesc) {
173		QAT_UTILS_LOG("Session handle not as expected\n");
174		return CPA_STATUS_INVALID_PARAM;
175	}
176
177	if (CPA_DC_DIR_DECOMPRESS == pSessionDesc->sessDirection) {
178		QAT_UTILS_LOG("Invalid session direction\n");
179		return CPA_STATUS_INVALID_PARAM;
180	}
181
182	if (CPA_DC_DEFLATE == pSessionDesc->compType) {
183		if (CPA_DC_CRC32 == pSessionDesc->checksumType) {
184			Cpa8U *pDest = pDestBuff->pData;
185			Cpa32U crc32 = pRes->checksum;
186			Cpa64U totalLenBeforeCompress =
187			    pSessionDesc->cumulativeConsumedBytes;
188
189			if (pDestBuff->dataLenInBytes < DC_GZIP_FOOTER_SIZE) {
190				QAT_UTILS_LOG(
191				    "The dataLenInBytes of the dest buffer is too small.\n");
192				return CPA_STATUS_INVALID_PARAM;
193			}
194
195			/* Crc32 of the uncompressed data */
196			pDest[0] = (Cpa8U)crc32;
197			pDest[1] = (Cpa8U)(crc32 >> LAC_NUM_BITS_IN_BYTE);
198			pDest[2] = (Cpa8U)(crc32 >> 2 * LAC_NUM_BITS_IN_BYTE);
199			pDest[3] = (Cpa8U)(crc32 >> 3 * LAC_NUM_BITS_IN_BYTE);
200
201			/* Length of the uncompressed data */
202			pDest[4] = (Cpa8U)totalLenBeforeCompress;
203			pDest[5] = (Cpa8U)(totalLenBeforeCompress >>
204					   LAC_NUM_BITS_IN_BYTE);
205			pDest[6] = (Cpa8U)(totalLenBeforeCompress >>
206					   2 * LAC_NUM_BITS_IN_BYTE);
207			pDest[7] = (Cpa8U)(totalLenBeforeCompress >>
208					   3 * LAC_NUM_BITS_IN_BYTE);
209
210			/* Increment produced by the number of bytes added to
211			 * the buffer */
212			pRes->produced += DC_GZIP_FOOTER_SIZE;
213		} else if (CPA_DC_ADLER32 == pSessionDesc->checksumType) {
214			Cpa8U *pDest = pDestBuff->pData;
215			Cpa32U adler32 = pRes->checksum;
216
217			if (pDestBuff->dataLenInBytes < DC_ZLIB_FOOTER_SIZE) {
218				QAT_UTILS_LOG(
219				    "The dataLenInBytes of the dest buffer is too small.\n");
220				return CPA_STATUS_INVALID_PARAM;
221			}
222
223			/* Adler32 of the uncompressed data */
224			pDest[0] = (Cpa8U)(adler32 >> 3 * LAC_NUM_BITS_IN_BYTE);
225			pDest[1] = (Cpa8U)(adler32 >> 2 * LAC_NUM_BITS_IN_BYTE);
226			pDest[2] = (Cpa8U)(adler32 >> LAC_NUM_BITS_IN_BYTE);
227			pDest[3] = (Cpa8U)adler32;
228
229			/* Increment produced by the number of bytes added to
230			 * the buffer */
231			pRes->produced += DC_ZLIB_FOOTER_SIZE;
232		}
233	}
234
235	return CPA_STATUS_SUCCESS;
236}
237