1aa5b395bSMikhail Zaslonko // SPDX-License-Identifier: Zlib
2aa5b395bSMikhail Zaslonko
3aa5b395bSMikhail Zaslonko #include "../zlib_deflate/defutil.h"
4aa5b395bSMikhail Zaslonko #include "dfltcc_util.h"
59fec9f8eSMikhail Zaslonko #include "dfltcc_deflate.h"
6c65e6815SMikhail Zaslonko #include <asm/setup.h>
7605cc30dSRandy Dunlap #include <linux/export.h>
8aa5b395bSMikhail Zaslonko #include <linux/zutil.h>
9aa5b395bSMikhail Zaslonko
109fec9f8eSMikhail Zaslonko #define GET_DFLTCC_DEFLATE_STATE(state) ((struct dfltcc_deflate_state *)GET_DFLTCC_STATE(state))
119fec9f8eSMikhail Zaslonko
12aa5b395bSMikhail Zaslonko /*
13aa5b395bSMikhail Zaslonko * Compress.
14aa5b395bSMikhail Zaslonko */
dfltcc_can_deflate(z_streamp strm)15aa5b395bSMikhail Zaslonko int dfltcc_can_deflate(
16aa5b395bSMikhail Zaslonko z_streamp strm
17aa5b395bSMikhail Zaslonko )
18aa5b395bSMikhail Zaslonko {
19aa5b395bSMikhail Zaslonko deflate_state *state = (deflate_state *)strm->state;
209fec9f8eSMikhail Zaslonko struct dfltcc_deflate_state *dfltcc_state = GET_DFLTCC_DEFLATE_STATE(state);
21aa5b395bSMikhail Zaslonko
22c65e6815SMikhail Zaslonko /* Check for kernel dfltcc command line parameter */
23c65e6815SMikhail Zaslonko if (zlib_dfltcc_support == ZLIB_DFLTCC_DISABLED ||
24c65e6815SMikhail Zaslonko zlib_dfltcc_support == ZLIB_DFLTCC_INFLATE_ONLY)
25c65e6815SMikhail Zaslonko return 0;
26c65e6815SMikhail Zaslonko
27aa5b395bSMikhail Zaslonko /* Unsupported compression settings */
28aa5b395bSMikhail Zaslonko if (!dfltcc_are_params_ok(state->level, state->w_bits, state->strategy,
29aa5b395bSMikhail Zaslonko dfltcc_state->level_mask))
30aa5b395bSMikhail Zaslonko return 0;
31aa5b395bSMikhail Zaslonko
32aa5b395bSMikhail Zaslonko /* Unsupported hardware */
339fec9f8eSMikhail Zaslonko if (!is_bit_set(dfltcc_state->common.af.fns, DFLTCC_GDHT) ||
349fec9f8eSMikhail Zaslonko !is_bit_set(dfltcc_state->common.af.fns, DFLTCC_CMPR) ||
359fec9f8eSMikhail Zaslonko !is_bit_set(dfltcc_state->common.af.fmts, DFLTCC_FMT0))
36aa5b395bSMikhail Zaslonko return 0;
37aa5b395bSMikhail Zaslonko
38aa5b395bSMikhail Zaslonko return 1;
39aa5b395bSMikhail Zaslonko }
40605cc30dSRandy Dunlap EXPORT_SYMBOL(dfltcc_can_deflate);
41aa5b395bSMikhail Zaslonko
dfltcc_reset_deflate_state(z_streamp strm)429fec9f8eSMikhail Zaslonko void dfltcc_reset_deflate_state(z_streamp strm) {
439fec9f8eSMikhail Zaslonko deflate_state *state = (deflate_state *)strm->state;
449fec9f8eSMikhail Zaslonko struct dfltcc_deflate_state *dfltcc_state = GET_DFLTCC_DEFLATE_STATE(state);
459fec9f8eSMikhail Zaslonko
469fec9f8eSMikhail Zaslonko dfltcc_reset_state(&dfltcc_state->common);
479fec9f8eSMikhail Zaslonko
489fec9f8eSMikhail Zaslonko /* Initialize tuning parameters */
499fec9f8eSMikhail Zaslonko if (zlib_dfltcc_support == ZLIB_DFLTCC_FULL_DEBUG)
509fec9f8eSMikhail Zaslonko dfltcc_state->level_mask = DFLTCC_LEVEL_MASK_DEBUG;
519fec9f8eSMikhail Zaslonko else
529fec9f8eSMikhail Zaslonko dfltcc_state->level_mask = DFLTCC_LEVEL_MASK;
539fec9f8eSMikhail Zaslonko dfltcc_state->block_size = DFLTCC_BLOCK_SIZE;
549fec9f8eSMikhail Zaslonko dfltcc_state->block_threshold = DFLTCC_FIRST_FHT_BLOCK_SIZE;
559fec9f8eSMikhail Zaslonko dfltcc_state->dht_threshold = DFLTCC_DHT_MIN_SAMPLE_SIZE;
569fec9f8eSMikhail Zaslonko }
579fec9f8eSMikhail Zaslonko EXPORT_SYMBOL(dfltcc_reset_deflate_state);
589fec9f8eSMikhail Zaslonko
dfltcc_gdht(z_streamp strm)59aa5b395bSMikhail Zaslonko static void dfltcc_gdht(
60aa5b395bSMikhail Zaslonko z_streamp strm
61aa5b395bSMikhail Zaslonko )
62aa5b395bSMikhail Zaslonko {
63aa5b395bSMikhail Zaslonko deflate_state *state = (deflate_state *)strm->state;
64aa5b395bSMikhail Zaslonko struct dfltcc_param_v0 *param = &GET_DFLTCC_STATE(state)->param;
65*e89bd9e7STom Rix size_t avail_in = strm->avail_in;
66aa5b395bSMikhail Zaslonko
67aa5b395bSMikhail Zaslonko dfltcc(DFLTCC_GDHT,
68aa5b395bSMikhail Zaslonko param, NULL, NULL,
69aa5b395bSMikhail Zaslonko &strm->next_in, &avail_in, NULL);
70aa5b395bSMikhail Zaslonko }
71aa5b395bSMikhail Zaslonko
dfltcc_cmpr(z_streamp strm)72aa5b395bSMikhail Zaslonko static dfltcc_cc dfltcc_cmpr(
73aa5b395bSMikhail Zaslonko z_streamp strm
74aa5b395bSMikhail Zaslonko )
75aa5b395bSMikhail Zaslonko {
76aa5b395bSMikhail Zaslonko deflate_state *state = (deflate_state *)strm->state;
77aa5b395bSMikhail Zaslonko struct dfltcc_param_v0 *param = &GET_DFLTCC_STATE(state)->param;
78aa5b395bSMikhail Zaslonko size_t avail_in = strm->avail_in;
79aa5b395bSMikhail Zaslonko size_t avail_out = strm->avail_out;
80aa5b395bSMikhail Zaslonko dfltcc_cc cc;
81aa5b395bSMikhail Zaslonko
82aa5b395bSMikhail Zaslonko cc = dfltcc(DFLTCC_CMPR | HBT_CIRCULAR,
83aa5b395bSMikhail Zaslonko param, &strm->next_out, &avail_out,
84aa5b395bSMikhail Zaslonko &strm->next_in, &avail_in, state->window);
85aa5b395bSMikhail Zaslonko strm->total_in += (strm->avail_in - avail_in);
86aa5b395bSMikhail Zaslonko strm->total_out += (strm->avail_out - avail_out);
87aa5b395bSMikhail Zaslonko strm->avail_in = avail_in;
88aa5b395bSMikhail Zaslonko strm->avail_out = avail_out;
89aa5b395bSMikhail Zaslonko return cc;
90aa5b395bSMikhail Zaslonko }
91aa5b395bSMikhail Zaslonko
send_eobs(z_streamp strm,const struct dfltcc_param_v0 * param)92aa5b395bSMikhail Zaslonko static void send_eobs(
93aa5b395bSMikhail Zaslonko z_streamp strm,
94aa5b395bSMikhail Zaslonko const struct dfltcc_param_v0 *param
95aa5b395bSMikhail Zaslonko )
96aa5b395bSMikhail Zaslonko {
97aa5b395bSMikhail Zaslonko deflate_state *state = (deflate_state *)strm->state;
98aa5b395bSMikhail Zaslonko
99aa5b395bSMikhail Zaslonko zlib_tr_send_bits(
100aa5b395bSMikhail Zaslonko state,
101aa5b395bSMikhail Zaslonko bi_reverse(param->eobs >> (15 - param->eobl), param->eobl),
102aa5b395bSMikhail Zaslonko param->eobl);
103aa5b395bSMikhail Zaslonko flush_pending(strm);
104aa5b395bSMikhail Zaslonko if (state->pending != 0) {
105aa5b395bSMikhail Zaslonko /* The remaining data is located in pending_out[0:pending]. If someone
106aa5b395bSMikhail Zaslonko * calls put_byte() - this might happen in deflate() - the byte will be
107aa5b395bSMikhail Zaslonko * placed into pending_buf[pending], which is incorrect. Move the
108aa5b395bSMikhail Zaslonko * remaining data to the beginning of pending_buf so that put_byte() is
109aa5b395bSMikhail Zaslonko * usable again.
110aa5b395bSMikhail Zaslonko */
111aa5b395bSMikhail Zaslonko memmove(state->pending_buf, state->pending_out, state->pending);
112aa5b395bSMikhail Zaslonko state->pending_out = state->pending_buf;
113aa5b395bSMikhail Zaslonko }
114aa5b395bSMikhail Zaslonko #ifdef ZLIB_DEBUG
115aa5b395bSMikhail Zaslonko state->compressed_len += param->eobl;
116aa5b395bSMikhail Zaslonko #endif
117aa5b395bSMikhail Zaslonko }
118aa5b395bSMikhail Zaslonko
dfltcc_deflate(z_streamp strm,int flush,block_state * result)119aa5b395bSMikhail Zaslonko int dfltcc_deflate(
120aa5b395bSMikhail Zaslonko z_streamp strm,
121aa5b395bSMikhail Zaslonko int flush,
122aa5b395bSMikhail Zaslonko block_state *result
123aa5b395bSMikhail Zaslonko )
124aa5b395bSMikhail Zaslonko {
125aa5b395bSMikhail Zaslonko deflate_state *state = (deflate_state *)strm->state;
1269fec9f8eSMikhail Zaslonko struct dfltcc_deflate_state *dfltcc_state = GET_DFLTCC_DEFLATE_STATE(state);
1279fec9f8eSMikhail Zaslonko struct dfltcc_param_v0 *param = &dfltcc_state->common.param;
128aa5b395bSMikhail Zaslonko uInt masked_avail_in;
129aa5b395bSMikhail Zaslonko dfltcc_cc cc;
130aa5b395bSMikhail Zaslonko int need_empty_block;
131aa5b395bSMikhail Zaslonko int soft_bcc;
132aa5b395bSMikhail Zaslonko int no_flush;
133aa5b395bSMikhail Zaslonko
1349a549338SMikhail Zaslonko if (!dfltcc_can_deflate(strm)) {
1359a549338SMikhail Zaslonko /* Clear history. */
1369a549338SMikhail Zaslonko if (flush == Z_FULL_FLUSH)
1379a549338SMikhail Zaslonko param->hl = 0;
138aa5b395bSMikhail Zaslonko return 0;
1399a549338SMikhail Zaslonko }
140aa5b395bSMikhail Zaslonko
141aa5b395bSMikhail Zaslonko again:
142aa5b395bSMikhail Zaslonko masked_avail_in = 0;
143aa5b395bSMikhail Zaslonko soft_bcc = 0;
144aa5b395bSMikhail Zaslonko no_flush = flush == Z_NO_FLUSH;
145aa5b395bSMikhail Zaslonko
1469a549338SMikhail Zaslonko /* No input data. Return, except when Continuation Flag is set, which means
1479a549338SMikhail Zaslonko * that DFLTCC has buffered some output in the parameter block and needs to
1489a549338SMikhail Zaslonko * be called again in order to flush it.
149aa5b395bSMikhail Zaslonko */
1509a549338SMikhail Zaslonko if (strm->avail_in == 0 && !param->cf) {
151aa5b395bSMikhail Zaslonko /* A block is still open, and the hardware does not support closing
152aa5b395bSMikhail Zaslonko * blocks without adding data. Thus, close it manually.
153aa5b395bSMikhail Zaslonko */
1549a549338SMikhail Zaslonko if (!no_flush && param->bcf) {
155aa5b395bSMikhail Zaslonko send_eobs(strm, param);
156aa5b395bSMikhail Zaslonko param->bcf = 0;
157aa5b395bSMikhail Zaslonko }
1589a549338SMikhail Zaslonko /* Let one of deflate_* functions write a trailing empty block. */
1599a549338SMikhail Zaslonko if (flush == Z_FINISH)
160aa5b395bSMikhail Zaslonko return 0;
1619a549338SMikhail Zaslonko /* Clear history. */
1629a549338SMikhail Zaslonko if (flush == Z_FULL_FLUSH)
1639a549338SMikhail Zaslonko param->hl = 0;
1640dbae465SMikhail Zaslonko /* Trigger block post-processing if necessary. */
1650dbae465SMikhail Zaslonko *result = no_flush ? need_more : block_done;
166aa5b395bSMikhail Zaslonko return 1;
167aa5b395bSMikhail Zaslonko }
168aa5b395bSMikhail Zaslonko
169aa5b395bSMikhail Zaslonko /* There is an open non-BFINAL block, we are not going to close it just
170aa5b395bSMikhail Zaslonko * yet, we have compressed more than DFLTCC_BLOCK_SIZE bytes and we see
171aa5b395bSMikhail Zaslonko * more than DFLTCC_DHT_MIN_SAMPLE_SIZE bytes. Open a new block with a new
172aa5b395bSMikhail Zaslonko * DHT in order to adapt to a possibly changed input data distribution.
173aa5b395bSMikhail Zaslonko */
174aa5b395bSMikhail Zaslonko if (param->bcf && no_flush &&
175aa5b395bSMikhail Zaslonko strm->total_in > dfltcc_state->block_threshold &&
176aa5b395bSMikhail Zaslonko strm->avail_in >= dfltcc_state->dht_threshold) {
177aa5b395bSMikhail Zaslonko if (param->cf) {
178aa5b395bSMikhail Zaslonko /* We need to flush the DFLTCC buffer before writing the
179aa5b395bSMikhail Zaslonko * End-of-block Symbol. Mask the input data and proceed as usual.
180aa5b395bSMikhail Zaslonko */
181aa5b395bSMikhail Zaslonko masked_avail_in += strm->avail_in;
182aa5b395bSMikhail Zaslonko strm->avail_in = 0;
183aa5b395bSMikhail Zaslonko no_flush = 0;
184aa5b395bSMikhail Zaslonko } else {
185aa5b395bSMikhail Zaslonko /* DFLTCC buffer is empty, so we can manually write the
186aa5b395bSMikhail Zaslonko * End-of-block Symbol right away.
187aa5b395bSMikhail Zaslonko */
188aa5b395bSMikhail Zaslonko send_eobs(strm, param);
189aa5b395bSMikhail Zaslonko param->bcf = 0;
190aa5b395bSMikhail Zaslonko dfltcc_state->block_threshold =
191aa5b395bSMikhail Zaslonko strm->total_in + dfltcc_state->block_size;
192cbf12540SMikhail Zaslonko }
193cbf12540SMikhail Zaslonko }
194cbf12540SMikhail Zaslonko
195cbf12540SMikhail Zaslonko /* No space for compressed data. If we proceed, dfltcc_cmpr() will return
196cbf12540SMikhail Zaslonko * DFLTCC_CC_OP1_TOO_SHORT without buffering header bits, but we will still
197cbf12540SMikhail Zaslonko * set BCF=1, which is wrong. Avoid complications and return early.
198cbf12540SMikhail Zaslonko */
199aa5b395bSMikhail Zaslonko if (strm->avail_out == 0) {
200aa5b395bSMikhail Zaslonko *result = need_more;
201aa5b395bSMikhail Zaslonko return 1;
202aa5b395bSMikhail Zaslonko }
203aa5b395bSMikhail Zaslonko
204aa5b395bSMikhail Zaslonko /* The caller gave us too much data. Pass only one block worth of
205aa5b395bSMikhail Zaslonko * uncompressed data to DFLTCC and mask the rest, so that on the next
206aa5b395bSMikhail Zaslonko * iteration we start a new block.
207aa5b395bSMikhail Zaslonko */
208aa5b395bSMikhail Zaslonko if (no_flush && strm->avail_in > dfltcc_state->block_size) {
209aa5b395bSMikhail Zaslonko masked_avail_in += (strm->avail_in - dfltcc_state->block_size);
210aa5b395bSMikhail Zaslonko strm->avail_in = dfltcc_state->block_size;
211aa5b395bSMikhail Zaslonko }
212aa5b395bSMikhail Zaslonko
213aa5b395bSMikhail Zaslonko /* When we have an open non-BFINAL deflate block and caller indicates that
214aa5b395bSMikhail Zaslonko * the stream is ending, we need to close an open deflate block and open a
215aa5b395bSMikhail Zaslonko * BFINAL one.
216aa5b395bSMikhail Zaslonko */
217aa5b395bSMikhail Zaslonko need_empty_block = flush == Z_FINISH && param->bcf && !param->bhf;
218aa5b395bSMikhail Zaslonko
219aa5b395bSMikhail Zaslonko /* Translate stream to parameter block */
220aa5b395bSMikhail Zaslonko param->cvt = CVT_ADLER32;
221aa5b395bSMikhail Zaslonko if (!no_flush)
222aa5b395bSMikhail Zaslonko /* We need to close a block. Always do this in software - when there is
2239a549338SMikhail Zaslonko * no input data, the hardware will not hohor BCC. */
224aa5b395bSMikhail Zaslonko soft_bcc = 1;
225aa5b395bSMikhail Zaslonko if (flush == Z_FINISH && !param->bcf)
226aa5b395bSMikhail Zaslonko /* We are about to open a BFINAL block, set Block Header Final bit
227aa5b395bSMikhail Zaslonko * until the stream ends.
228aa5b395bSMikhail Zaslonko */
229aa5b395bSMikhail Zaslonko param->bhf = 1;
230aa5b395bSMikhail Zaslonko /* DFLTCC-CMPR will write to next_out, so make sure that buffers with
231aa5b395bSMikhail Zaslonko * higher precedence are empty.
232aa5b395bSMikhail Zaslonko */
233aa5b395bSMikhail Zaslonko Assert(state->pending == 0, "There must be no pending bytes");
234aa5b395bSMikhail Zaslonko Assert(state->bi_valid < 8, "There must be less than 8 pending bits");
235aa5b395bSMikhail Zaslonko param->sbb = (unsigned int)state->bi_valid;
236aa5b395bSMikhail Zaslonko if (param->sbb > 0)
237aa5b395bSMikhail Zaslonko *strm->next_out = (Byte)state->bi_buf;
2389a549338SMikhail Zaslonko /* Honor history and check value */
2399a549338SMikhail Zaslonko param->nt = 0;
240aa5b395bSMikhail Zaslonko param->cv = strm->adler;
241aa5b395bSMikhail Zaslonko
242aa5b395bSMikhail Zaslonko /* When opening a block, choose a Huffman-Table Type */
243aa5b395bSMikhail Zaslonko if (!param->bcf) {
244aa5b395bSMikhail Zaslonko if (strm->total_in == 0 && dfltcc_state->block_threshold > 0) {
245aa5b395bSMikhail Zaslonko param->htt = HTT_FIXED;
246aa5b395bSMikhail Zaslonko }
247aa5b395bSMikhail Zaslonko else {
248aa5b395bSMikhail Zaslonko param->htt = HTT_DYNAMIC;
249aa5b395bSMikhail Zaslonko dfltcc_gdht(strm);
250aa5b395bSMikhail Zaslonko }
251aa5b395bSMikhail Zaslonko }
252aa5b395bSMikhail Zaslonko
253aa5b395bSMikhail Zaslonko /* Deflate */
254aa5b395bSMikhail Zaslonko do {
255aa5b395bSMikhail Zaslonko cc = dfltcc_cmpr(strm);
256aa5b395bSMikhail Zaslonko if (strm->avail_in < 4096 && masked_avail_in > 0)
257aa5b395bSMikhail Zaslonko /* We are about to call DFLTCC with a small input buffer, which is
258aa5b395bSMikhail Zaslonko * inefficient. Since there is masked data, there will be at least
259aa5b395bSMikhail Zaslonko * one more DFLTCC call, so skip the current one and make the next
260aa5b395bSMikhail Zaslonko * one handle more data.
261aa5b395bSMikhail Zaslonko */
262aa5b395bSMikhail Zaslonko break;
263aa5b395bSMikhail Zaslonko } while (cc == DFLTCC_CC_AGAIN);
264aa5b395bSMikhail Zaslonko
265aa5b395bSMikhail Zaslonko /* Translate parameter block to stream */
2669fec9f8eSMikhail Zaslonko strm->msg = oesc_msg(dfltcc_state->common.msg, param->oesc);
267aa5b395bSMikhail Zaslonko state->bi_valid = param->sbb;
268aa5b395bSMikhail Zaslonko if (state->bi_valid == 0)
269aa5b395bSMikhail Zaslonko state->bi_buf = 0; /* Avoid accessing next_out */
270aa5b395bSMikhail Zaslonko else
271aa5b395bSMikhail Zaslonko state->bi_buf = *strm->next_out & ((1 << state->bi_valid) - 1);
272aa5b395bSMikhail Zaslonko strm->adler = param->cv;
273aa5b395bSMikhail Zaslonko
274aa5b395bSMikhail Zaslonko /* Unmask the input data */
275aa5b395bSMikhail Zaslonko strm->avail_in += masked_avail_in;
276aa5b395bSMikhail Zaslonko masked_avail_in = 0;
277aa5b395bSMikhail Zaslonko
278aa5b395bSMikhail Zaslonko /* If we encounter an error, it means there is a bug in DFLTCC call */
279aa5b395bSMikhail Zaslonko Assert(cc != DFLTCC_CC_OP2_CORRUPT || param->oesc == 0, "BUG");
280aa5b395bSMikhail Zaslonko
281aa5b395bSMikhail Zaslonko /* Update Block-Continuation Flag. It will be used to check whether to call
282aa5b395bSMikhail Zaslonko * GDHT the next time.
283aa5b395bSMikhail Zaslonko */
284aa5b395bSMikhail Zaslonko if (cc == DFLTCC_CC_OK) {
285aa5b395bSMikhail Zaslonko if (soft_bcc) {
286aa5b395bSMikhail Zaslonko send_eobs(strm, param);
287aa5b395bSMikhail Zaslonko param->bcf = 0;
288aa5b395bSMikhail Zaslonko dfltcc_state->block_threshold =
289aa5b395bSMikhail Zaslonko strm->total_in + dfltcc_state->block_size;
290aa5b395bSMikhail Zaslonko } else
291aa5b395bSMikhail Zaslonko param->bcf = 1;
292aa5b395bSMikhail Zaslonko if (flush == Z_FINISH) {
293aa5b395bSMikhail Zaslonko if (need_empty_block)
294aa5b395bSMikhail Zaslonko /* Make the current deflate() call also close the stream */
295aa5b395bSMikhail Zaslonko return 0;
296aa5b395bSMikhail Zaslonko else {
297aa5b395bSMikhail Zaslonko bi_windup(state);
298aa5b395bSMikhail Zaslonko *result = finish_done;
299aa5b395bSMikhail Zaslonko }
300aa5b395bSMikhail Zaslonko } else {
301aa5b395bSMikhail Zaslonko if (flush == Z_FULL_FLUSH)
302aa5b395bSMikhail Zaslonko param->hl = 0; /* Clear history */
303aa5b395bSMikhail Zaslonko *result = flush == Z_NO_FLUSH ? need_more : block_done;
304aa5b395bSMikhail Zaslonko }
305aa5b395bSMikhail Zaslonko } else {
306aa5b395bSMikhail Zaslonko param->bcf = 1;
307aa5b395bSMikhail Zaslonko *result = need_more;
308aa5b395bSMikhail Zaslonko }
309aa5b395bSMikhail Zaslonko if (strm->avail_in != 0 && strm->avail_out != 0)
310aa5b395bSMikhail Zaslonko goto again; /* deflate() must use all input or all output */
311aa5b395bSMikhail Zaslonko return 1;
312aa5b395bSMikhail Zaslonko }
313605cc30dSRandy Dunlap EXPORT_SYMBOL(dfltcc_deflate);
314