1 // SPDX-License-Identifier: Zlib
3 #include "../zlib_deflate/defutil.h"
4 #include "dfltcc_util.h"
5 #include "dfltcc_deflate.h"
7 #include <linux/export.h>
8 #include <linux/zutil.h>
10 #define GET_DFLTCC_DEFLATE_STATE(state) ((struct dfltcc_deflate_state *)GET_DFLTCC_STATE(state))
15 int dfltcc_can_deflate(
19 deflate_state
*state
= (deflate_state
*)strm
->state
;
20 struct dfltcc_deflate_state
*dfltcc_state
= GET_DFLTCC_DEFLATE_STATE(state
);
22 /* Check for kernel dfltcc command line parameter */
23 if (zlib_dfltcc_support
== ZLIB_DFLTCC_DISABLED
||
24 zlib_dfltcc_support
== ZLIB_DFLTCC_INFLATE_ONLY
)
27 /* Unsupported compression settings */
28 if (!dfltcc_are_params_ok(state
->level
, state
->w_bits
, state
->strategy
,
29 dfltcc_state
->level_mask
))
32 /* Unsupported hardware */
33 if (!is_bit_set(dfltcc_state
->common
.af
.fns
, DFLTCC_GDHT
) ||
34 !is_bit_set(dfltcc_state
->common
.af
.fns
, DFLTCC_CMPR
) ||
35 !is_bit_set(dfltcc_state
->common
.af
.fmts
, DFLTCC_FMT0
))
40 EXPORT_SYMBOL(dfltcc_can_deflate
);
42 void dfltcc_reset_deflate_state(z_streamp strm
) {
43 deflate_state
*state
= (deflate_state
*)strm
->state
;
44 struct dfltcc_deflate_state
*dfltcc_state
= GET_DFLTCC_DEFLATE_STATE(state
);
46 dfltcc_reset_state(&dfltcc_state
->common
);
48 /* Initialize tuning parameters */
49 if (zlib_dfltcc_support
== ZLIB_DFLTCC_FULL_DEBUG
)
50 dfltcc_state
->level_mask
= DFLTCC_LEVEL_MASK_DEBUG
;
52 dfltcc_state
->level_mask
= DFLTCC_LEVEL_MASK
;
53 dfltcc_state
->block_size
= DFLTCC_BLOCK_SIZE
;
54 dfltcc_state
->block_threshold
= DFLTCC_FIRST_FHT_BLOCK_SIZE
;
55 dfltcc_state
->dht_threshold
= DFLTCC_DHT_MIN_SAMPLE_SIZE
;
57 EXPORT_SYMBOL(dfltcc_reset_deflate_state
);
59 static void dfltcc_gdht(
63 deflate_state
*state
= (deflate_state
*)strm
->state
;
64 struct dfltcc_param_v0
*param
= &GET_DFLTCC_STATE(state
)->param
;
65 size_t avail_in
= strm
->avail_in
;
69 &strm
->next_in
, &avail_in
, NULL
);
72 static dfltcc_cc
dfltcc_cmpr(
76 deflate_state
*state
= (deflate_state
*)strm
->state
;
77 struct dfltcc_param_v0
*param
= &GET_DFLTCC_STATE(state
)->param
;
78 size_t avail_in
= strm
->avail_in
;
79 size_t avail_out
= strm
->avail_out
;
82 cc
= dfltcc(DFLTCC_CMPR
| HBT_CIRCULAR
,
83 param
, &strm
->next_out
, &avail_out
,
84 &strm
->next_in
, &avail_in
, state
->window
);
85 strm
->total_in
+= (strm
->avail_in
- avail_in
);
86 strm
->total_out
+= (strm
->avail_out
- avail_out
);
87 strm
->avail_in
= avail_in
;
88 strm
->avail_out
= avail_out
;
92 static void send_eobs(
94 const struct dfltcc_param_v0
*param
97 deflate_state
*state
= (deflate_state
*)strm
->state
;
101 bi_reverse(param
->eobs
>> (15 - param
->eobl
), param
->eobl
),
104 if (state
->pending
!= 0) {
105 /* The remaining data is located in pending_out[0:pending]. If someone
106 * calls put_byte() - this might happen in deflate() - the byte will be
107 * placed into pending_buf[pending], which is incorrect. Move the
108 * remaining data to the beginning of pending_buf so that put_byte() is
111 memmove(state
->pending_buf
, state
->pending_out
, state
->pending
);
112 state
->pending_out
= state
->pending_buf
;
115 state
->compressed_len
+= param
->eobl
;
125 deflate_state
*state
= (deflate_state
*)strm
->state
;
126 struct dfltcc_deflate_state
*dfltcc_state
= GET_DFLTCC_DEFLATE_STATE(state
);
127 struct dfltcc_param_v0
*param
= &dfltcc_state
->common
.param
;
128 uInt masked_avail_in
;
130 int need_empty_block
;
134 if (!dfltcc_can_deflate(strm
)) {
136 if (flush
== Z_FULL_FLUSH
)
144 no_flush
= flush
== Z_NO_FLUSH
;
146 /* No input data. Return, except when Continuation Flag is set, which means
147 * that DFLTCC has buffered some output in the parameter block and needs to
148 * be called again in order to flush it.
150 if (strm
->avail_in
== 0 && !param
->cf
) {
151 /* A block is still open, and the hardware does not support closing
152 * blocks without adding data. Thus, close it manually.
154 if (!no_flush
&& param
->bcf
) {
155 send_eobs(strm
, param
);
158 /* Let one of deflate_* functions write a trailing empty block. */
159 if (flush
== Z_FINISH
)
162 if (flush
== Z_FULL_FLUSH
)
164 /* Trigger block post-processing if necessary. */
165 *result
= no_flush
? need_more
: block_done
;
169 /* There is an open non-BFINAL block, we are not going to close it just
170 * yet, we have compressed more than DFLTCC_BLOCK_SIZE bytes and we see
171 * more than DFLTCC_DHT_MIN_SAMPLE_SIZE bytes. Open a new block with a new
172 * DHT in order to adapt to a possibly changed input data distribution.
174 if (param
->bcf
&& no_flush
&&
175 strm
->total_in
> dfltcc_state
->block_threshold
&&
176 strm
->avail_in
>= dfltcc_state
->dht_threshold
) {
178 /* We need to flush the DFLTCC buffer before writing the
179 * End-of-block Symbol. Mask the input data and proceed as usual.
181 masked_avail_in
+= strm
->avail_in
;
185 /* DFLTCC buffer is empty, so we can manually write the
186 * End-of-block Symbol right away.
188 send_eobs(strm
, param
);
190 dfltcc_state
->block_threshold
=
191 strm
->total_in
+ dfltcc_state
->block_size
;
195 /* No space for compressed data. If we proceed, dfltcc_cmpr() will return
196 * DFLTCC_CC_OP1_TOO_SHORT without buffering header bits, but we will still
197 * set BCF=1, which is wrong. Avoid complications and return early.
199 if (strm
->avail_out
== 0) {
204 /* The caller gave us too much data. Pass only one block worth of
205 * uncompressed data to DFLTCC and mask the rest, so that on the next
206 * iteration we start a new block.
208 if (no_flush
&& strm
->avail_in
> dfltcc_state
->block_size
) {
209 masked_avail_in
+= (strm
->avail_in
- dfltcc_state
->block_size
);
210 strm
->avail_in
= dfltcc_state
->block_size
;
213 /* When we have an open non-BFINAL deflate block and caller indicates that
214 * the stream is ending, we need to close an open deflate block and open a
217 need_empty_block
= flush
== Z_FINISH
&& param
->bcf
&& !param
->bhf
;
219 /* Translate stream to parameter block */
220 param
->cvt
= CVT_ADLER32
;
222 /* We need to close a block. Always do this in software - when there is
223 * no input data, the hardware will not hohor BCC. */
225 if (flush
== Z_FINISH
&& !param
->bcf
)
226 /* We are about to open a BFINAL block, set Block Header Final bit
227 * until the stream ends.
230 /* DFLTCC-CMPR will write to next_out, so make sure that buffers with
231 * higher precedence are empty.
233 Assert(state
->pending
== 0, "There must be no pending bytes");
234 Assert(state
->bi_valid
< 8, "There must be less than 8 pending bits");
235 param
->sbb
= (unsigned int)state
->bi_valid
;
237 *strm
->next_out
= (Byte
)state
->bi_buf
;
238 /* Honor history and check value */
240 param
->cv
= strm
->adler
;
242 /* When opening a block, choose a Huffman-Table Type */
244 if (strm
->total_in
== 0 && dfltcc_state
->block_threshold
> 0) {
245 param
->htt
= HTT_FIXED
;
248 param
->htt
= HTT_DYNAMIC
;
255 cc
= dfltcc_cmpr(strm
);
256 if (strm
->avail_in
< 4096 && masked_avail_in
> 0)
257 /* We are about to call DFLTCC with a small input buffer, which is
258 * inefficient. Since there is masked data, there will be at least
259 * one more DFLTCC call, so skip the current one and make the next
260 * one handle more data.
263 } while (cc
== DFLTCC_CC_AGAIN
);
265 /* Translate parameter block to stream */
266 strm
->msg
= oesc_msg(dfltcc_state
->common
.msg
, param
->oesc
);
267 state
->bi_valid
= param
->sbb
;
268 if (state
->bi_valid
== 0)
269 state
->bi_buf
= 0; /* Avoid accessing next_out */
271 state
->bi_buf
= *strm
->next_out
& ((1 << state
->bi_valid
) - 1);
272 strm
->adler
= param
->cv
;
274 /* Unmask the input data */
275 strm
->avail_in
+= masked_avail_in
;
278 /* If we encounter an error, it means there is a bug in DFLTCC call */
279 Assert(cc
!= DFLTCC_CC_OP2_CORRUPT
|| param
->oesc
== 0, "BUG");
281 /* Update Block-Continuation Flag. It will be used to check whether to call
282 * GDHT the next time.
284 if (cc
== DFLTCC_CC_OK
) {
286 send_eobs(strm
, param
);
288 dfltcc_state
->block_threshold
=
289 strm
->total_in
+ dfltcc_state
->block_size
;
292 if (flush
== Z_FINISH
) {
293 if (need_empty_block
)
294 /* Make the current deflate() call also close the stream */
298 *result
= finish_done
;
301 if (flush
== Z_FULL_FLUSH
)
302 param
->hl
= 0; /* Clear history */
303 *result
= flush
== Z_NO_FLUSH
? need_more
: block_done
;
309 if (strm
->avail_in
!= 0 && strm
->avail_out
!= 0)
310 goto again
; /* deflate() must use all input or all output */
313 EXPORT_SYMBOL(dfltcc_deflate
);