dfltcc_deflate.c (9273B)
1// SPDX-License-Identifier: Zlib 2 3#include "../zlib_deflate/defutil.h" 4#include "dfltcc_util.h" 5#include "dfltcc.h" 6#include <asm/setup.h> 7#include <linux/export.h> 8#include <linux/zutil.h> 9 10/* 11 * Compress. 12 */ 13int dfltcc_can_deflate( 14 z_streamp strm 15) 16{ 17 deflate_state *state = (deflate_state *)strm->state; 18 struct dfltcc_state *dfltcc_state = GET_DFLTCC_STATE(state); 19 20 /* Check for kernel dfltcc command line parameter */ 21 if (zlib_dfltcc_support == ZLIB_DFLTCC_DISABLED || 22 zlib_dfltcc_support == ZLIB_DFLTCC_INFLATE_ONLY) 23 return 0; 24 25 /* Unsupported compression settings */ 26 if (!dfltcc_are_params_ok(state->level, state->w_bits, state->strategy, 27 dfltcc_state->level_mask)) 28 return 0; 29 30 /* Unsupported hardware */ 31 if (!is_bit_set(dfltcc_state->af.fns, DFLTCC_GDHT) || 32 !is_bit_set(dfltcc_state->af.fns, DFLTCC_CMPR) || 33 !is_bit_set(dfltcc_state->af.fmts, DFLTCC_FMT0)) 34 return 0; 35 36 return 1; 37} 38EXPORT_SYMBOL(dfltcc_can_deflate); 39 40static void dfltcc_gdht( 41 z_streamp strm 42) 43{ 44 deflate_state *state = (deflate_state *)strm->state; 45 struct dfltcc_param_v0 *param = &GET_DFLTCC_STATE(state)->param; 46 size_t avail_in = avail_in = strm->avail_in; 47 48 dfltcc(DFLTCC_GDHT, 49 param, NULL, NULL, 50 &strm->next_in, &avail_in, NULL); 51} 52 53static dfltcc_cc dfltcc_cmpr( 54 z_streamp strm 55) 56{ 57 deflate_state *state = (deflate_state *)strm->state; 58 struct dfltcc_param_v0 *param = &GET_DFLTCC_STATE(state)->param; 59 size_t avail_in = strm->avail_in; 60 size_t avail_out = strm->avail_out; 61 dfltcc_cc cc; 62 63 cc = dfltcc(DFLTCC_CMPR | HBT_CIRCULAR, 64 param, &strm->next_out, &avail_out, 65 &strm->next_in, &avail_in, state->window); 66 strm->total_in += (strm->avail_in - avail_in); 67 strm->total_out += (strm->avail_out - avail_out); 68 strm->avail_in = avail_in; 69 strm->avail_out = avail_out; 70 return cc; 71} 72 73static void send_eobs( 74 z_streamp strm, 75 const struct dfltcc_param_v0 *param 76) 77{ 78 deflate_state *state = (deflate_state *)strm->state; 79 80 zlib_tr_send_bits( 81 state, 82 bi_reverse(param->eobs >> (15 - param->eobl), param->eobl), 83 param->eobl); 84 flush_pending(strm); 85 if (state->pending != 0) { 86 /* The remaining data is located in pending_out[0:pending]. If someone 87 * calls put_byte() - this might happen in deflate() - the byte will be 88 * placed into pending_buf[pending], which is incorrect. Move the 89 * remaining data to the beginning of pending_buf so that put_byte() is 90 * usable again. 91 */ 92 memmove(state->pending_buf, state->pending_out, state->pending); 93 state->pending_out = state->pending_buf; 94 } 95#ifdef ZLIB_DEBUG 96 state->compressed_len += param->eobl; 97#endif 98} 99 100int dfltcc_deflate( 101 z_streamp strm, 102 int flush, 103 block_state *result 104) 105{ 106 deflate_state *state = (deflate_state *)strm->state; 107 struct dfltcc_state *dfltcc_state = GET_DFLTCC_STATE(state); 108 struct dfltcc_param_v0 *param = &dfltcc_state->param; 109 uInt masked_avail_in; 110 dfltcc_cc cc; 111 int need_empty_block; 112 int soft_bcc; 113 int no_flush; 114 115 if (!dfltcc_can_deflate(strm)) 116 return 0; 117 118again: 119 masked_avail_in = 0; 120 soft_bcc = 0; 121 no_flush = flush == Z_NO_FLUSH; 122 123 /* Trailing empty block. Switch to software, except when Continuation Flag 124 * is set, which means that DFLTCC has buffered some output in the 125 * parameter block and needs to be called again in order to flush it. 126 */ 127 if (flush == Z_FINISH && strm->avail_in == 0 && !param->cf) { 128 if (param->bcf) { 129 /* A block is still open, and the hardware does not support closing 130 * blocks without adding data. Thus, close it manually. 131 */ 132 send_eobs(strm, param); 133 param->bcf = 0; 134 } 135 return 0; 136 } 137 138 if (strm->avail_in == 0 && !param->cf) { 139 *result = need_more; 140 return 1; 141 } 142 143 /* There is an open non-BFINAL block, we are not going to close it just 144 * yet, we have compressed more than DFLTCC_BLOCK_SIZE bytes and we see 145 * more than DFLTCC_DHT_MIN_SAMPLE_SIZE bytes. Open a new block with a new 146 * DHT in order to adapt to a possibly changed input data distribution. 147 */ 148 if (param->bcf && no_flush && 149 strm->total_in > dfltcc_state->block_threshold && 150 strm->avail_in >= dfltcc_state->dht_threshold) { 151 if (param->cf) { 152 /* We need to flush the DFLTCC buffer before writing the 153 * End-of-block Symbol. Mask the input data and proceed as usual. 154 */ 155 masked_avail_in += strm->avail_in; 156 strm->avail_in = 0; 157 no_flush = 0; 158 } else { 159 /* DFLTCC buffer is empty, so we can manually write the 160 * End-of-block Symbol right away. 161 */ 162 send_eobs(strm, param); 163 param->bcf = 0; 164 dfltcc_state->block_threshold = 165 strm->total_in + dfltcc_state->block_size; 166 if (strm->avail_out == 0) { 167 *result = need_more; 168 return 1; 169 } 170 } 171 } 172 173 /* The caller gave us too much data. Pass only one block worth of 174 * uncompressed data to DFLTCC and mask the rest, so that on the next 175 * iteration we start a new block. 176 */ 177 if (no_flush && strm->avail_in > dfltcc_state->block_size) { 178 masked_avail_in += (strm->avail_in - dfltcc_state->block_size); 179 strm->avail_in = dfltcc_state->block_size; 180 } 181 182 /* When we have an open non-BFINAL deflate block and caller indicates that 183 * the stream is ending, we need to close an open deflate block and open a 184 * BFINAL one. 185 */ 186 need_empty_block = flush == Z_FINISH && param->bcf && !param->bhf; 187 188 /* Translate stream to parameter block */ 189 param->cvt = CVT_ADLER32; 190 if (!no_flush) 191 /* We need to close a block. Always do this in software - when there is 192 * no input data, the hardware will not nohor BCC. */ 193 soft_bcc = 1; 194 if (flush == Z_FINISH && !param->bcf) 195 /* We are about to open a BFINAL block, set Block Header Final bit 196 * until the stream ends. 197 */ 198 param->bhf = 1; 199 /* DFLTCC-CMPR will write to next_out, so make sure that buffers with 200 * higher precedence are empty. 201 */ 202 Assert(state->pending == 0, "There must be no pending bytes"); 203 Assert(state->bi_valid < 8, "There must be less than 8 pending bits"); 204 param->sbb = (unsigned int)state->bi_valid; 205 if (param->sbb > 0) 206 *strm->next_out = (Byte)state->bi_buf; 207 if (param->hl) 208 param->nt = 0; /* Honor history */ 209 param->cv = strm->adler; 210 211 /* When opening a block, choose a Huffman-Table Type */ 212 if (!param->bcf) { 213 if (strm->total_in == 0 && dfltcc_state->block_threshold > 0) { 214 param->htt = HTT_FIXED; 215 } 216 else { 217 param->htt = HTT_DYNAMIC; 218 dfltcc_gdht(strm); 219 } 220 } 221 222 /* Deflate */ 223 do { 224 cc = dfltcc_cmpr(strm); 225 if (strm->avail_in < 4096 && masked_avail_in > 0) 226 /* We are about to call DFLTCC with a small input buffer, which is 227 * inefficient. Since there is masked data, there will be at least 228 * one more DFLTCC call, so skip the current one and make the next 229 * one handle more data. 230 */ 231 break; 232 } while (cc == DFLTCC_CC_AGAIN); 233 234 /* Translate parameter block to stream */ 235 strm->msg = oesc_msg(dfltcc_state->msg, param->oesc); 236 state->bi_valid = param->sbb; 237 if (state->bi_valid == 0) 238 state->bi_buf = 0; /* Avoid accessing next_out */ 239 else 240 state->bi_buf = *strm->next_out & ((1 << state->bi_valid) - 1); 241 strm->adler = param->cv; 242 243 /* Unmask the input data */ 244 strm->avail_in += masked_avail_in; 245 masked_avail_in = 0; 246 247 /* If we encounter an error, it means there is a bug in DFLTCC call */ 248 Assert(cc != DFLTCC_CC_OP2_CORRUPT || param->oesc == 0, "BUG"); 249 250 /* Update Block-Continuation Flag. It will be used to check whether to call 251 * GDHT the next time. 252 */ 253 if (cc == DFLTCC_CC_OK) { 254 if (soft_bcc) { 255 send_eobs(strm, param); 256 param->bcf = 0; 257 dfltcc_state->block_threshold = 258 strm->total_in + dfltcc_state->block_size; 259 } else 260 param->bcf = 1; 261 if (flush == Z_FINISH) { 262 if (need_empty_block) 263 /* Make the current deflate() call also close the stream */ 264 return 0; 265 else { 266 bi_windup(state); 267 *result = finish_done; 268 } 269 } else { 270 if (flush == Z_FULL_FLUSH) 271 param->hl = 0; /* Clear history */ 272 *result = flush == Z_NO_FLUSH ? need_more : block_done; 273 } 274 } else { 275 param->bcf = 1; 276 *result = need_more; 277 } 278 if (strm->avail_in != 0 && strm->avail_out != 0) 279 goto again; /* deflate() must use all input or all output */ 280 return 1; 281} 282EXPORT_SYMBOL(dfltcc_deflate);