1841fb73aSRaphael Moreira Zinsly // SPDX-License-Identifier: GPL-2.0-or-later
2841fb73aSRaphael Moreira Zinsly
3841fb73aSRaphael Moreira Zinsly /* P9 gunzip sample code for demonstrating the P9 NX hardware
4841fb73aSRaphael Moreira Zinsly * interface. Not intended for productive uses or for performance or
5841fb73aSRaphael Moreira Zinsly * compression ratio measurements. Note also that /dev/crypto/gzip,
6841fb73aSRaphael Moreira Zinsly * VAS and skiboot support are required
7841fb73aSRaphael Moreira Zinsly *
8841fb73aSRaphael Moreira Zinsly * Copyright 2020 IBM Corp.
9841fb73aSRaphael Moreira Zinsly *
10841fb73aSRaphael Moreira Zinsly * Author: Bulent Abali <abali@us.ibm.com>
11841fb73aSRaphael Moreira Zinsly *
12841fb73aSRaphael Moreira Zinsly * https://github.com/libnxz/power-gzip for zlib api and other utils
13841fb73aSRaphael Moreira Zinsly * Definitions of acronyms used here. See
14841fb73aSRaphael Moreira Zinsly * P9 NX Gzip Accelerator User's Manual for details:
15841fb73aSRaphael Moreira Zinsly * https://github.com/libnxz/power-gzip/blob/develop/doc/power_nx_gzip_um.pdf
16841fb73aSRaphael Moreira Zinsly *
17841fb73aSRaphael Moreira Zinsly * adler/crc: 32 bit checksums appended to stream tail
18841fb73aSRaphael Moreira Zinsly * ce: completion extension
19841fb73aSRaphael Moreira Zinsly * cpb: coprocessor parameter block (metadata)
20841fb73aSRaphael Moreira Zinsly * crb: coprocessor request block (command)
21841fb73aSRaphael Moreira Zinsly * csb: coprocessor status block (status)
22841fb73aSRaphael Moreira Zinsly * dht: dynamic huffman table
23841fb73aSRaphael Moreira Zinsly * dde: data descriptor element (address, length)
24841fb73aSRaphael Moreira Zinsly * ddl: list of ddes
25841fb73aSRaphael Moreira Zinsly * dh/fh: dynamic and fixed huffman types
26841fb73aSRaphael Moreira Zinsly * fc: coprocessor function code
27841fb73aSRaphael Moreira Zinsly * histlen: history/dictionary length
28841fb73aSRaphael Moreira Zinsly * history: sliding window of up to 32KB of data
29841fb73aSRaphael Moreira Zinsly * lzcount: Deflate LZ symbol counts
30841fb73aSRaphael Moreira Zinsly * rembytecnt: remaining byte count
31841fb73aSRaphael Moreira Zinsly * sfbt: source final block type; last block's type during decomp
32841fb73aSRaphael Moreira Zinsly * spbc: source processed byte count
33841fb73aSRaphael Moreira Zinsly * subc: source unprocessed bit count
34841fb73aSRaphael Moreira Zinsly * tebc: target ending bit count; valid bits in the last byte
35841fb73aSRaphael Moreira Zinsly * tpbc: target processed byte count
36841fb73aSRaphael Moreira Zinsly * vas: virtual accelerator switch; the user mode interface
37841fb73aSRaphael Moreira Zinsly */
38841fb73aSRaphael Moreira Zinsly
39841fb73aSRaphael Moreira Zinsly #define _ISOC11_SOURCE // For aligned_alloc()
40841fb73aSRaphael Moreira Zinsly #define _DEFAULT_SOURCE // For endian.h
41841fb73aSRaphael Moreira Zinsly
42841fb73aSRaphael Moreira Zinsly #include <stdio.h>
43841fb73aSRaphael Moreira Zinsly #include <stdlib.h>
44841fb73aSRaphael Moreira Zinsly #include <string.h>
45841fb73aSRaphael Moreira Zinsly #include <unistd.h>
46841fb73aSRaphael Moreira Zinsly #include <stdint.h>
47841fb73aSRaphael Moreira Zinsly #include <sys/types.h>
48841fb73aSRaphael Moreira Zinsly #include <sys/stat.h>
49841fb73aSRaphael Moreira Zinsly #include <sys/time.h>
50841fb73aSRaphael Moreira Zinsly #include <sys/fcntl.h>
51841fb73aSRaphael Moreira Zinsly #include <sys/mman.h>
52841fb73aSRaphael Moreira Zinsly #include <endian.h>
53841fb73aSRaphael Moreira Zinsly #include <bits/endian.h>
54841fb73aSRaphael Moreira Zinsly #include <sys/ioctl.h>
55841fb73aSRaphael Moreira Zinsly #include <assert.h>
56841fb73aSRaphael Moreira Zinsly #include <errno.h>
57841fb73aSRaphael Moreira Zinsly #include <signal.h>
58841fb73aSRaphael Moreira Zinsly #include "nxu.h"
59841fb73aSRaphael Moreira Zinsly #include "nx.h"
60841fb73aSRaphael Moreira Zinsly #include "crb.h"
61841fb73aSRaphael Moreira Zinsly
62841fb73aSRaphael Moreira Zinsly int nx_dbg;
63841fb73aSRaphael Moreira Zinsly FILE *nx_gzip_log;
64841fb73aSRaphael Moreira Zinsly
65841fb73aSRaphael Moreira Zinsly #define NX_MIN(X, Y) (((X) < (Y))?(X):(Y))
66841fb73aSRaphael Moreira Zinsly #define NX_MAX(X, Y) (((X) > (Y))?(X):(Y))
67841fb73aSRaphael Moreira Zinsly
68841fb73aSRaphael Moreira Zinsly #define GETINPC(X) fgetc(X)
69841fb73aSRaphael Moreira Zinsly #define FNAME_MAX 1024
70841fb73aSRaphael Moreira Zinsly
71841fb73aSRaphael Moreira Zinsly /* fifo queue management */
72841fb73aSRaphael Moreira Zinsly #define fifo_used_bytes(used) (used)
73841fb73aSRaphael Moreira Zinsly #define fifo_free_bytes(used, len) ((len)-(used))
74841fb73aSRaphael Moreira Zinsly /* amount of free bytes in the first and last parts */
75841fb73aSRaphael Moreira Zinsly #define fifo_free_first_bytes(cur, used, len) ((((cur)+(used)) <= (len)) \
76841fb73aSRaphael Moreira Zinsly ? (len)-((cur)+(used)) : 0)
77841fb73aSRaphael Moreira Zinsly #define fifo_free_last_bytes(cur, used, len) ((((cur)+(used)) <= (len)) \
78841fb73aSRaphael Moreira Zinsly ? (cur) : (len)-(used))
79841fb73aSRaphael Moreira Zinsly /* amount of used bytes in the first and last parts */
80841fb73aSRaphael Moreira Zinsly #define fifo_used_first_bytes(cur, used, len) ((((cur)+(used)) <= (len)) \
81841fb73aSRaphael Moreira Zinsly ? (used) : (len)-(cur))
82841fb73aSRaphael Moreira Zinsly #define fifo_used_last_bytes(cur, used, len) ((((cur)+(used)) <= (len)) \
83841fb73aSRaphael Moreira Zinsly ? 0 : ((used)+(cur))-(len))
84841fb73aSRaphael Moreira Zinsly /* first and last free parts start here */
85841fb73aSRaphael Moreira Zinsly #define fifo_free_first_offset(cur, used) ((cur)+(used))
86841fb73aSRaphael Moreira Zinsly #define fifo_free_last_offset(cur, used, len) \
87841fb73aSRaphael Moreira Zinsly fifo_used_last_bytes(cur, used, len)
88841fb73aSRaphael Moreira Zinsly /* first and last used parts start here */
89841fb73aSRaphael Moreira Zinsly #define fifo_used_first_offset(cur) (cur)
90841fb73aSRaphael Moreira Zinsly #define fifo_used_last_offset(cur) (0)
91841fb73aSRaphael Moreira Zinsly
92841fb73aSRaphael Moreira Zinsly const int fifo_in_len = 1<<24;
93841fb73aSRaphael Moreira Zinsly const int fifo_out_len = 1<<24;
94841fb73aSRaphael Moreira Zinsly const int page_sz = 1<<16;
95841fb73aSRaphael Moreira Zinsly const int line_sz = 1<<7;
96841fb73aSRaphael Moreira Zinsly const int window_max = 1<<15;
97841fb73aSRaphael Moreira Zinsly
98841fb73aSRaphael Moreira Zinsly /*
99841fb73aSRaphael Moreira Zinsly * Adds an (address, len) pair to the list of ddes (ddl) and updates
100841fb73aSRaphael Moreira Zinsly * the base dde. ddl[0] is the only dde in a direct dde which
101841fb73aSRaphael Moreira Zinsly * contains a single (addr,len) pair. For more pairs, ddl[0] becomes
102841fb73aSRaphael Moreira Zinsly * the indirect (base) dde that points to a list of direct ddes.
103841fb73aSRaphael Moreira Zinsly * See Section 6.4 of the NX-gzip user manual for DDE description.
104841fb73aSRaphael Moreira Zinsly * Addr=NULL, len=0 clears the ddl[0]. Returns the total number of
105841fb73aSRaphael Moreira Zinsly * bytes in ddl. Caller is responsible for allocting the array of
106841fb73aSRaphael Moreira Zinsly * nx_dde_t *ddl. If N addresses are required in the scatter-gather
107841fb73aSRaphael Moreira Zinsly * list, the ddl array must have N+1 entries minimum.
108841fb73aSRaphael Moreira Zinsly */
nx_append_dde(struct nx_dde_t * ddl,void * addr,uint32_t len)109841fb73aSRaphael Moreira Zinsly static inline uint32_t nx_append_dde(struct nx_dde_t *ddl, void *addr,
110841fb73aSRaphael Moreira Zinsly uint32_t len)
111841fb73aSRaphael Moreira Zinsly {
112841fb73aSRaphael Moreira Zinsly uint32_t ddecnt;
113841fb73aSRaphael Moreira Zinsly uint32_t bytes;
114841fb73aSRaphael Moreira Zinsly
115841fb73aSRaphael Moreira Zinsly if (addr == NULL && len == 0) {
116841fb73aSRaphael Moreira Zinsly clearp_dde(ddl);
117841fb73aSRaphael Moreira Zinsly return 0;
118841fb73aSRaphael Moreira Zinsly }
119841fb73aSRaphael Moreira Zinsly
120841fb73aSRaphael Moreira Zinsly NXPRT(fprintf(stderr, "%d: %s addr %p len %x\n", __LINE__, addr,
121841fb73aSRaphael Moreira Zinsly __func__, len));
122841fb73aSRaphael Moreira Zinsly
123841fb73aSRaphael Moreira Zinsly /* Number of ddes in the dde list ; == 0 when it is a direct dde */
124841fb73aSRaphael Moreira Zinsly ddecnt = getpnn(ddl, dde_count);
125841fb73aSRaphael Moreira Zinsly bytes = getp32(ddl, ddebc);
126841fb73aSRaphael Moreira Zinsly
127841fb73aSRaphael Moreira Zinsly if (ddecnt == 0 && bytes == 0) {
128841fb73aSRaphael Moreira Zinsly /* First dde is unused; make it a direct dde */
129841fb73aSRaphael Moreira Zinsly bytes = len;
130841fb73aSRaphael Moreira Zinsly putp32(ddl, ddebc, bytes);
131841fb73aSRaphael Moreira Zinsly putp64(ddl, ddead, (uint64_t) addr);
132841fb73aSRaphael Moreira Zinsly } else if (ddecnt == 0) {
133841fb73aSRaphael Moreira Zinsly /* Converting direct to indirect dde
134841fb73aSRaphael Moreira Zinsly * ddl[0] becomes head dde of ddl
135841fb73aSRaphael Moreira Zinsly * copy direct to indirect first.
136841fb73aSRaphael Moreira Zinsly */
137841fb73aSRaphael Moreira Zinsly ddl[1] = ddl[0];
138841fb73aSRaphael Moreira Zinsly
139841fb73aSRaphael Moreira Zinsly /* Add the new dde next */
140841fb73aSRaphael Moreira Zinsly clear_dde(ddl[2]);
141841fb73aSRaphael Moreira Zinsly put32(ddl[2], ddebc, len);
142841fb73aSRaphael Moreira Zinsly put64(ddl[2], ddead, (uint64_t) addr);
143841fb73aSRaphael Moreira Zinsly
144841fb73aSRaphael Moreira Zinsly /* Ddl head points to 2 direct ddes */
145841fb73aSRaphael Moreira Zinsly ddecnt = 2;
146841fb73aSRaphael Moreira Zinsly putpnn(ddl, dde_count, ddecnt);
147841fb73aSRaphael Moreira Zinsly bytes = bytes + len;
148841fb73aSRaphael Moreira Zinsly putp32(ddl, ddebc, bytes);
149841fb73aSRaphael Moreira Zinsly /* Pointer to the first direct dde */
150841fb73aSRaphael Moreira Zinsly putp64(ddl, ddead, (uint64_t) &ddl[1]);
151841fb73aSRaphael Moreira Zinsly } else {
152841fb73aSRaphael Moreira Zinsly /* Append a dde to an existing indirect ddl */
153841fb73aSRaphael Moreira Zinsly ++ddecnt;
154841fb73aSRaphael Moreira Zinsly clear_dde(ddl[ddecnt]);
155841fb73aSRaphael Moreira Zinsly put64(ddl[ddecnt], ddead, (uint64_t) addr);
156841fb73aSRaphael Moreira Zinsly put32(ddl[ddecnt], ddebc, len);
157841fb73aSRaphael Moreira Zinsly
158841fb73aSRaphael Moreira Zinsly putpnn(ddl, dde_count, ddecnt);
159841fb73aSRaphael Moreira Zinsly bytes = bytes + len;
160841fb73aSRaphael Moreira Zinsly putp32(ddl, ddebc, bytes); /* byte sum of all dde */
161841fb73aSRaphael Moreira Zinsly }
162841fb73aSRaphael Moreira Zinsly return bytes;
163841fb73aSRaphael Moreira Zinsly }
164841fb73aSRaphael Moreira Zinsly
165841fb73aSRaphael Moreira Zinsly /*
166841fb73aSRaphael Moreira Zinsly * Touch specified number of pages represented in number bytes
167841fb73aSRaphael Moreira Zinsly * beginning from the first buffer in a dde list.
168841fb73aSRaphael Moreira Zinsly * Do not touch the pages past buf_sz-th byte's page.
169841fb73aSRaphael Moreira Zinsly *
170841fb73aSRaphael Moreira Zinsly * Set buf_sz = 0 to touch all pages described by the ddep.
171841fb73aSRaphael Moreira Zinsly */
nx_touch_pages_dde(struct nx_dde_t * ddep,long buf_sz,long page_sz,int wr)172841fb73aSRaphael Moreira Zinsly static int nx_touch_pages_dde(struct nx_dde_t *ddep, long buf_sz, long page_sz,
173841fb73aSRaphael Moreira Zinsly int wr)
174841fb73aSRaphael Moreira Zinsly {
175841fb73aSRaphael Moreira Zinsly uint32_t indirect_count;
176841fb73aSRaphael Moreira Zinsly uint32_t buf_len;
177841fb73aSRaphael Moreira Zinsly long total;
178841fb73aSRaphael Moreira Zinsly uint64_t buf_addr;
179841fb73aSRaphael Moreira Zinsly struct nx_dde_t *dde_list;
180841fb73aSRaphael Moreira Zinsly int i;
181841fb73aSRaphael Moreira Zinsly
182841fb73aSRaphael Moreira Zinsly assert(!!ddep);
183841fb73aSRaphael Moreira Zinsly
184841fb73aSRaphael Moreira Zinsly indirect_count = getpnn(ddep, dde_count);
185841fb73aSRaphael Moreira Zinsly
186841fb73aSRaphael Moreira Zinsly NXPRT(fprintf(stderr, "%s dde_count %d request len ", __func__,
187841fb73aSRaphael Moreira Zinsly indirect_count));
188841fb73aSRaphael Moreira Zinsly NXPRT(fprintf(stderr, "0x%lx\n", buf_sz));
189841fb73aSRaphael Moreira Zinsly
190841fb73aSRaphael Moreira Zinsly if (indirect_count == 0) {
191841fb73aSRaphael Moreira Zinsly /* Direct dde */
192841fb73aSRaphael Moreira Zinsly buf_len = getp32(ddep, ddebc);
193841fb73aSRaphael Moreira Zinsly buf_addr = getp64(ddep, ddead);
194841fb73aSRaphael Moreira Zinsly
195841fb73aSRaphael Moreira Zinsly NXPRT(fprintf(stderr, "touch direct ddebc 0x%x ddead %p\n",
196841fb73aSRaphael Moreira Zinsly buf_len, (void *)buf_addr));
197841fb73aSRaphael Moreira Zinsly
198841fb73aSRaphael Moreira Zinsly if (buf_sz == 0)
199841fb73aSRaphael Moreira Zinsly nxu_touch_pages((void *)buf_addr, buf_len, page_sz, wr);
200841fb73aSRaphael Moreira Zinsly else
201841fb73aSRaphael Moreira Zinsly nxu_touch_pages((void *)buf_addr, NX_MIN(buf_len,
202841fb73aSRaphael Moreira Zinsly buf_sz), page_sz, wr);
203841fb73aSRaphael Moreira Zinsly
204841fb73aSRaphael Moreira Zinsly return ERR_NX_OK;
205841fb73aSRaphael Moreira Zinsly }
206841fb73aSRaphael Moreira Zinsly
207841fb73aSRaphael Moreira Zinsly /* Indirect dde */
208841fb73aSRaphael Moreira Zinsly if (indirect_count > MAX_DDE_COUNT)
209841fb73aSRaphael Moreira Zinsly return ERR_NX_EXCESSIVE_DDE;
210841fb73aSRaphael Moreira Zinsly
211841fb73aSRaphael Moreira Zinsly /* First address of the list */
212841fb73aSRaphael Moreira Zinsly dde_list = (struct nx_dde_t *) getp64(ddep, ddead);
213841fb73aSRaphael Moreira Zinsly
214841fb73aSRaphael Moreira Zinsly if (buf_sz == 0)
215841fb73aSRaphael Moreira Zinsly buf_sz = getp32(ddep, ddebc);
216841fb73aSRaphael Moreira Zinsly
217841fb73aSRaphael Moreira Zinsly total = 0;
218841fb73aSRaphael Moreira Zinsly for (i = 0; i < indirect_count; i++) {
219841fb73aSRaphael Moreira Zinsly buf_len = get32(dde_list[i], ddebc);
220841fb73aSRaphael Moreira Zinsly buf_addr = get64(dde_list[i], ddead);
221841fb73aSRaphael Moreira Zinsly total += buf_len;
222841fb73aSRaphael Moreira Zinsly
223841fb73aSRaphael Moreira Zinsly NXPRT(fprintf(stderr, "touch loop len 0x%x ddead %p total ",
224841fb73aSRaphael Moreira Zinsly buf_len, (void *)buf_addr));
225841fb73aSRaphael Moreira Zinsly NXPRT(fprintf(stderr, "0x%lx\n", total));
226841fb73aSRaphael Moreira Zinsly
227841fb73aSRaphael Moreira Zinsly /* Touching fewer pages than encoded in the ddebc */
228841fb73aSRaphael Moreira Zinsly if (total > buf_sz) {
229841fb73aSRaphael Moreira Zinsly buf_len = NX_MIN(buf_len, total - buf_sz);
230841fb73aSRaphael Moreira Zinsly nxu_touch_pages((void *)buf_addr, buf_len, page_sz, wr);
231841fb73aSRaphael Moreira Zinsly NXPRT(fprintf(stderr, "touch loop break len 0x%x ",
232841fb73aSRaphael Moreira Zinsly buf_len));
233841fb73aSRaphael Moreira Zinsly NXPRT(fprintf(stderr, "ddead %p\n", (void *)buf_addr));
234841fb73aSRaphael Moreira Zinsly break;
235841fb73aSRaphael Moreira Zinsly }
236841fb73aSRaphael Moreira Zinsly nxu_touch_pages((void *)buf_addr, buf_len, page_sz, wr);
237841fb73aSRaphael Moreira Zinsly }
238841fb73aSRaphael Moreira Zinsly return ERR_NX_OK;
239841fb73aSRaphael Moreira Zinsly }
240841fb73aSRaphael Moreira Zinsly
241841fb73aSRaphael Moreira Zinsly /*
242841fb73aSRaphael Moreira Zinsly * Src and dst buffers are supplied in scatter gather lists.
243841fb73aSRaphael Moreira Zinsly * NX function code and other parameters supplied in cmdp.
244841fb73aSRaphael Moreira Zinsly */
nx_submit_job(struct nx_dde_t * src,struct nx_dde_t * dst,struct nx_gzip_crb_cpb_t * cmdp,void * handle)245841fb73aSRaphael Moreira Zinsly static int nx_submit_job(struct nx_dde_t *src, struct nx_dde_t *dst,
246841fb73aSRaphael Moreira Zinsly struct nx_gzip_crb_cpb_t *cmdp, void *handle)
247841fb73aSRaphael Moreira Zinsly {
248841fb73aSRaphael Moreira Zinsly uint64_t csbaddr;
249841fb73aSRaphael Moreira Zinsly
250841fb73aSRaphael Moreira Zinsly memset((void *)&cmdp->crb.csb, 0, sizeof(cmdp->crb.csb));
251841fb73aSRaphael Moreira Zinsly
252841fb73aSRaphael Moreira Zinsly cmdp->crb.source_dde = *src;
253841fb73aSRaphael Moreira Zinsly cmdp->crb.target_dde = *dst;
254841fb73aSRaphael Moreira Zinsly
255841fb73aSRaphael Moreira Zinsly /* Status, output byte count in tpbc */
256841fb73aSRaphael Moreira Zinsly csbaddr = ((uint64_t) &cmdp->crb.csb) & csb_address_mask;
257841fb73aSRaphael Moreira Zinsly put64(cmdp->crb, csb_address, csbaddr);
258841fb73aSRaphael Moreira Zinsly
259841fb73aSRaphael Moreira Zinsly /* NX reports input bytes in spbc; cleared */
260841fb73aSRaphael Moreira Zinsly cmdp->cpb.out_spbc_comp_wrap = 0;
261841fb73aSRaphael Moreira Zinsly cmdp->cpb.out_spbc_comp_with_count = 0;
262841fb73aSRaphael Moreira Zinsly cmdp->cpb.out_spbc_decomp = 0;
263841fb73aSRaphael Moreira Zinsly
264841fb73aSRaphael Moreira Zinsly /* Clear output */
265841fb73aSRaphael Moreira Zinsly put32(cmdp->cpb, out_crc, INIT_CRC);
266841fb73aSRaphael Moreira Zinsly put32(cmdp->cpb, out_adler, INIT_ADLER);
267841fb73aSRaphael Moreira Zinsly
268841fb73aSRaphael Moreira Zinsly /* Submit the crb, the job descriptor, to the accelerator. */
269841fb73aSRaphael Moreira Zinsly return nxu_submit_job(cmdp, handle);
270841fb73aSRaphael Moreira Zinsly }
271841fb73aSRaphael Moreira Zinsly
decompress_file(int argc,char ** argv,void * devhandle)272841fb73aSRaphael Moreira Zinsly int decompress_file(int argc, char **argv, void *devhandle)
273841fb73aSRaphael Moreira Zinsly {
274841fb73aSRaphael Moreira Zinsly FILE *inpf = NULL;
275841fb73aSRaphael Moreira Zinsly FILE *outf = NULL;
276841fb73aSRaphael Moreira Zinsly
277841fb73aSRaphael Moreira Zinsly int c, expect, i, cc, rc = 0;
278841fb73aSRaphael Moreira Zinsly char gzfname[FNAME_MAX];
279841fb73aSRaphael Moreira Zinsly
280841fb73aSRaphael Moreira Zinsly /* Queuing, file ops, byte counting */
281841fb73aSRaphael Moreira Zinsly char *fifo_in, *fifo_out;
282841fb73aSRaphael Moreira Zinsly int used_in, cur_in, used_out, cur_out, read_sz, n;
283841fb73aSRaphael Moreira Zinsly int first_free, last_free, first_used, last_used;
284841fb73aSRaphael Moreira Zinsly int first_offset, last_offset;
285841fb73aSRaphael Moreira Zinsly int write_sz, free_space, source_sz;
286841fb73aSRaphael Moreira Zinsly int source_sz_estimate, target_sz_estimate;
287841fb73aSRaphael Moreira Zinsly uint64_t last_comp_ratio = 0; /* 1000 max */
288841fb73aSRaphael Moreira Zinsly uint64_t total_out = 0;
289841fb73aSRaphael Moreira Zinsly int is_final, is_eof;
290841fb73aSRaphael Moreira Zinsly
291841fb73aSRaphael Moreira Zinsly /* nx hardware */
292841fb73aSRaphael Moreira Zinsly int sfbt, subc, spbc, tpbc, nx_ce, fc, resuming = 0;
293841fb73aSRaphael Moreira Zinsly int history_len = 0;
294841fb73aSRaphael Moreira Zinsly struct nx_gzip_crb_cpb_t cmd, *cmdp;
295841fb73aSRaphael Moreira Zinsly struct nx_dde_t *ddl_in;
296841fb73aSRaphael Moreira Zinsly struct nx_dde_t dde_in[6] __aligned(128);
297841fb73aSRaphael Moreira Zinsly struct nx_dde_t *ddl_out;
298841fb73aSRaphael Moreira Zinsly struct nx_dde_t dde_out[6] __aligned(128);
299841fb73aSRaphael Moreira Zinsly int pgfault_retries;
300841fb73aSRaphael Moreira Zinsly
301841fb73aSRaphael Moreira Zinsly /* when using mmap'ed files */
302841fb73aSRaphael Moreira Zinsly off_t input_file_offset;
303841fb73aSRaphael Moreira Zinsly
304841fb73aSRaphael Moreira Zinsly if (argc > 2) {
305841fb73aSRaphael Moreira Zinsly fprintf(stderr, "usage: %s <fname> or stdin\n", argv[0]);
306841fb73aSRaphael Moreira Zinsly fprintf(stderr, " writes to stdout or <fname>.nx.gunzip\n");
307841fb73aSRaphael Moreira Zinsly return -1;
308841fb73aSRaphael Moreira Zinsly }
309841fb73aSRaphael Moreira Zinsly
310841fb73aSRaphael Moreira Zinsly if (argc == 1) {
311841fb73aSRaphael Moreira Zinsly inpf = stdin;
312841fb73aSRaphael Moreira Zinsly outf = stdout;
313841fb73aSRaphael Moreira Zinsly } else if (argc == 2) {
314841fb73aSRaphael Moreira Zinsly char w[1024];
315841fb73aSRaphael Moreira Zinsly char *wp;
316841fb73aSRaphael Moreira Zinsly
317841fb73aSRaphael Moreira Zinsly inpf = fopen(argv[1], "r");
318841fb73aSRaphael Moreira Zinsly if (inpf == NULL) {
319841fb73aSRaphael Moreira Zinsly perror(argv[1]);
320841fb73aSRaphael Moreira Zinsly return -1;
321841fb73aSRaphael Moreira Zinsly }
322841fb73aSRaphael Moreira Zinsly
323841fb73aSRaphael Moreira Zinsly /* Make a new file name to write to. Ignoring '.gz' */
324841fb73aSRaphael Moreira Zinsly wp = (NULL != (wp = strrchr(argv[1], '/'))) ? (wp+1) : argv[1];
325841fb73aSRaphael Moreira Zinsly strcpy(w, wp);
326841fb73aSRaphael Moreira Zinsly strcat(w, ".nx.gunzip");
327841fb73aSRaphael Moreira Zinsly
328841fb73aSRaphael Moreira Zinsly outf = fopen(w, "w");
329841fb73aSRaphael Moreira Zinsly if (outf == NULL) {
330841fb73aSRaphael Moreira Zinsly perror(w);
331841fb73aSRaphael Moreira Zinsly return -1;
332841fb73aSRaphael Moreira Zinsly }
333841fb73aSRaphael Moreira Zinsly }
334841fb73aSRaphael Moreira Zinsly
335841fb73aSRaphael Moreira Zinsly /* Decode the gzip header */
336841fb73aSRaphael Moreira Zinsly c = GETINPC(inpf); expect = 0x1f; /* ID1 */
337841fb73aSRaphael Moreira Zinsly if (c != expect)
338841fb73aSRaphael Moreira Zinsly goto err1;
339841fb73aSRaphael Moreira Zinsly
340841fb73aSRaphael Moreira Zinsly c = GETINPC(inpf); expect = 0x8b; /* ID2 */
341841fb73aSRaphael Moreira Zinsly if (c != expect)
342841fb73aSRaphael Moreira Zinsly goto err1;
343841fb73aSRaphael Moreira Zinsly
344841fb73aSRaphael Moreira Zinsly c = GETINPC(inpf); expect = 0x08; /* CM */
345841fb73aSRaphael Moreira Zinsly if (c != expect)
346841fb73aSRaphael Moreira Zinsly goto err1;
347841fb73aSRaphael Moreira Zinsly
348841fb73aSRaphael Moreira Zinsly int flg = GETINPC(inpf); /* FLG */
349841fb73aSRaphael Moreira Zinsly
350841fb73aSRaphael Moreira Zinsly if (flg & 0xE0 || flg & 0x4 || flg == EOF)
351841fb73aSRaphael Moreira Zinsly goto err2;
352841fb73aSRaphael Moreira Zinsly
353841fb73aSRaphael Moreira Zinsly fprintf(stderr, "gzHeader FLG %x\n", flg);
354841fb73aSRaphael Moreira Zinsly
355841fb73aSRaphael Moreira Zinsly /* Read 6 bytes; ignoring the MTIME, XFL, OS fields in this
356841fb73aSRaphael Moreira Zinsly * sample code.
357841fb73aSRaphael Moreira Zinsly */
358841fb73aSRaphael Moreira Zinsly for (i = 0; i < 6; i++) {
359841fb73aSRaphael Moreira Zinsly char tmp[10];
360841fb73aSRaphael Moreira Zinsly
361841fb73aSRaphael Moreira Zinsly tmp[i] = GETINPC(inpf);
362841fb73aSRaphael Moreira Zinsly if (tmp[i] == EOF)
363841fb73aSRaphael Moreira Zinsly goto err3;
364841fb73aSRaphael Moreira Zinsly fprintf(stderr, "%02x ", tmp[i]);
365841fb73aSRaphael Moreira Zinsly if (i == 5)
366841fb73aSRaphael Moreira Zinsly fprintf(stderr, "\n");
367841fb73aSRaphael Moreira Zinsly }
368841fb73aSRaphael Moreira Zinsly fprintf(stderr, "gzHeader MTIME, XFL, OS ignored\n");
369841fb73aSRaphael Moreira Zinsly
370841fb73aSRaphael Moreira Zinsly /* FNAME */
371841fb73aSRaphael Moreira Zinsly if (flg & 0x8) {
372841fb73aSRaphael Moreira Zinsly int k = 0;
373841fb73aSRaphael Moreira Zinsly
374841fb73aSRaphael Moreira Zinsly do {
375841fb73aSRaphael Moreira Zinsly c = GETINPC(inpf);
376841fb73aSRaphael Moreira Zinsly if (c == EOF || k >= FNAME_MAX)
377841fb73aSRaphael Moreira Zinsly goto err3;
378841fb73aSRaphael Moreira Zinsly gzfname[k++] = c;
379841fb73aSRaphael Moreira Zinsly } while (c);
380841fb73aSRaphael Moreira Zinsly fprintf(stderr, "gzHeader FNAME: %s\n", gzfname);
381841fb73aSRaphael Moreira Zinsly }
382841fb73aSRaphael Moreira Zinsly
383841fb73aSRaphael Moreira Zinsly /* FHCRC */
384841fb73aSRaphael Moreira Zinsly if (flg & 0x2) {
385841fb73aSRaphael Moreira Zinsly c = GETINPC(inpf);
386841fb73aSRaphael Moreira Zinsly if (c == EOF)
387841fb73aSRaphael Moreira Zinsly goto err3;
388841fb73aSRaphael Moreira Zinsly c = GETINPC(inpf);
389841fb73aSRaphael Moreira Zinsly if (c == EOF)
390841fb73aSRaphael Moreira Zinsly goto err3;
391841fb73aSRaphael Moreira Zinsly fprintf(stderr, "gzHeader FHCRC: ignored\n");
392841fb73aSRaphael Moreira Zinsly }
393841fb73aSRaphael Moreira Zinsly
394841fb73aSRaphael Moreira Zinsly used_in = cur_in = used_out = cur_out = 0;
395841fb73aSRaphael Moreira Zinsly is_final = is_eof = 0;
396841fb73aSRaphael Moreira Zinsly
397841fb73aSRaphael Moreira Zinsly /* Allocate one page larger to prevent page faults due to NX
398841fb73aSRaphael Moreira Zinsly * overfetching.
399841fb73aSRaphael Moreira Zinsly * Either do this (char*)(uintptr_t)aligned_alloc or use
400841fb73aSRaphael Moreira Zinsly * -std=c11 flag to make the int-to-pointer warning go away.
401841fb73aSRaphael Moreira Zinsly */
402841fb73aSRaphael Moreira Zinsly assert((fifo_in = (char *)(uintptr_t)aligned_alloc(line_sz,
403841fb73aSRaphael Moreira Zinsly fifo_in_len + page_sz)) != NULL);
404841fb73aSRaphael Moreira Zinsly assert((fifo_out = (char *)(uintptr_t)aligned_alloc(line_sz,
405841fb73aSRaphael Moreira Zinsly fifo_out_len + page_sz + line_sz)) != NULL);
406841fb73aSRaphael Moreira Zinsly /* Leave unused space due to history rounding rules */
407841fb73aSRaphael Moreira Zinsly fifo_out = fifo_out + line_sz;
408841fb73aSRaphael Moreira Zinsly nxu_touch_pages(fifo_out, fifo_out_len, page_sz, 1);
409841fb73aSRaphael Moreira Zinsly
410841fb73aSRaphael Moreira Zinsly ddl_in = &dde_in[0];
411841fb73aSRaphael Moreira Zinsly ddl_out = &dde_out[0];
412841fb73aSRaphael Moreira Zinsly cmdp = &cmd;
413841fb73aSRaphael Moreira Zinsly memset(&cmdp->crb, 0, sizeof(cmdp->crb));
414841fb73aSRaphael Moreira Zinsly
415841fb73aSRaphael Moreira Zinsly read_state:
416841fb73aSRaphael Moreira Zinsly
417841fb73aSRaphael Moreira Zinsly /* Read from .gz file */
418841fb73aSRaphael Moreira Zinsly
419841fb73aSRaphael Moreira Zinsly NXPRT(fprintf(stderr, "read_state:\n"));
420841fb73aSRaphael Moreira Zinsly
421841fb73aSRaphael Moreira Zinsly if (is_eof != 0)
422841fb73aSRaphael Moreira Zinsly goto write_state;
423841fb73aSRaphael Moreira Zinsly
424841fb73aSRaphael Moreira Zinsly /* We read in to fifo_in in two steps: first: read in to from
425841fb73aSRaphael Moreira Zinsly * cur_in to the end of the buffer. last: if free space wrapped
426841fb73aSRaphael Moreira Zinsly * around, read from fifo_in offset 0 to offset cur_in.
427841fb73aSRaphael Moreira Zinsly */
428841fb73aSRaphael Moreira Zinsly
429841fb73aSRaphael Moreira Zinsly /* Reset fifo head to reduce unnecessary wrap arounds */
430841fb73aSRaphael Moreira Zinsly cur_in = (used_in == 0) ? 0 : cur_in;
431841fb73aSRaphael Moreira Zinsly
432841fb73aSRaphael Moreira Zinsly /* Free space total is reduced by a gap */
433841fb73aSRaphael Moreira Zinsly free_space = NX_MAX(0, fifo_free_bytes(used_in, fifo_in_len)
434841fb73aSRaphael Moreira Zinsly - line_sz);
435841fb73aSRaphael Moreira Zinsly
436841fb73aSRaphael Moreira Zinsly /* Free space may wrap around as first and last */
437841fb73aSRaphael Moreira Zinsly first_free = fifo_free_first_bytes(cur_in, used_in, fifo_in_len);
438841fb73aSRaphael Moreira Zinsly last_free = fifo_free_last_bytes(cur_in, used_in, fifo_in_len);
439841fb73aSRaphael Moreira Zinsly
440841fb73aSRaphael Moreira Zinsly /* Start offsets of the free memory */
441841fb73aSRaphael Moreira Zinsly first_offset = fifo_free_first_offset(cur_in, used_in);
442841fb73aSRaphael Moreira Zinsly last_offset = fifo_free_last_offset(cur_in, used_in, fifo_in_len);
443841fb73aSRaphael Moreira Zinsly
444841fb73aSRaphael Moreira Zinsly /* Reduce read_sz because of the line_sz gap */
445841fb73aSRaphael Moreira Zinsly read_sz = NX_MIN(free_space, first_free);
446841fb73aSRaphael Moreira Zinsly n = 0;
447841fb73aSRaphael Moreira Zinsly if (read_sz > 0) {
448841fb73aSRaphael Moreira Zinsly /* Read in to offset cur_in + used_in */
449841fb73aSRaphael Moreira Zinsly n = fread(fifo_in + first_offset, 1, read_sz, inpf);
450841fb73aSRaphael Moreira Zinsly used_in = used_in + n;
451841fb73aSRaphael Moreira Zinsly free_space = free_space - n;
452841fb73aSRaphael Moreira Zinsly assert(n <= read_sz);
453841fb73aSRaphael Moreira Zinsly if (n != read_sz) {
454841fb73aSRaphael Moreira Zinsly /* Either EOF or error; exit the read loop */
455841fb73aSRaphael Moreira Zinsly is_eof = 1;
456841fb73aSRaphael Moreira Zinsly goto write_state;
457841fb73aSRaphael Moreira Zinsly }
458841fb73aSRaphael Moreira Zinsly }
459841fb73aSRaphael Moreira Zinsly
460841fb73aSRaphael Moreira Zinsly /* If free space wrapped around */
461841fb73aSRaphael Moreira Zinsly if (last_free > 0) {
462841fb73aSRaphael Moreira Zinsly /* Reduce read_sz because of the line_sz gap */
463841fb73aSRaphael Moreira Zinsly read_sz = NX_MIN(free_space, last_free);
464841fb73aSRaphael Moreira Zinsly n = 0;
465841fb73aSRaphael Moreira Zinsly if (read_sz > 0) {
466841fb73aSRaphael Moreira Zinsly n = fread(fifo_in + last_offset, 1, read_sz, inpf);
467841fb73aSRaphael Moreira Zinsly used_in = used_in + n; /* Increase used space */
468841fb73aSRaphael Moreira Zinsly free_space = free_space - n; /* Decrease free space */
469841fb73aSRaphael Moreira Zinsly assert(n <= read_sz);
470841fb73aSRaphael Moreira Zinsly if (n != read_sz) {
471841fb73aSRaphael Moreira Zinsly /* Either EOF or error; exit the read loop */
472841fb73aSRaphael Moreira Zinsly is_eof = 1;
473841fb73aSRaphael Moreira Zinsly goto write_state;
474841fb73aSRaphael Moreira Zinsly }
475841fb73aSRaphael Moreira Zinsly }
476841fb73aSRaphael Moreira Zinsly }
477841fb73aSRaphael Moreira Zinsly
478841fb73aSRaphael Moreira Zinsly /* At this point we have used_in bytes in fifo_in with the
479841fb73aSRaphael Moreira Zinsly * data head starting at cur_in and possibly wrapping around.
480841fb73aSRaphael Moreira Zinsly */
481841fb73aSRaphael Moreira Zinsly
482841fb73aSRaphael Moreira Zinsly write_state:
483841fb73aSRaphael Moreira Zinsly
484841fb73aSRaphael Moreira Zinsly /* Write decompressed data to output file */
485841fb73aSRaphael Moreira Zinsly
486841fb73aSRaphael Moreira Zinsly NXPRT(fprintf(stderr, "write_state:\n"));
487841fb73aSRaphael Moreira Zinsly
488841fb73aSRaphael Moreira Zinsly if (used_out == 0)
489841fb73aSRaphael Moreira Zinsly goto decomp_state;
490841fb73aSRaphael Moreira Zinsly
491841fb73aSRaphael Moreira Zinsly /* If fifo_out has data waiting, write it out to the file to
492841fb73aSRaphael Moreira Zinsly * make free target space for the accelerator used bytes in
493841fb73aSRaphael Moreira Zinsly * the first and last parts of fifo_out.
494841fb73aSRaphael Moreira Zinsly */
495841fb73aSRaphael Moreira Zinsly
496841fb73aSRaphael Moreira Zinsly first_used = fifo_used_first_bytes(cur_out, used_out, fifo_out_len);
497841fb73aSRaphael Moreira Zinsly last_used = fifo_used_last_bytes(cur_out, used_out, fifo_out_len);
498841fb73aSRaphael Moreira Zinsly
499841fb73aSRaphael Moreira Zinsly write_sz = first_used;
500841fb73aSRaphael Moreira Zinsly
501841fb73aSRaphael Moreira Zinsly n = 0;
502841fb73aSRaphael Moreira Zinsly if (write_sz > 0) {
503841fb73aSRaphael Moreira Zinsly n = fwrite(fifo_out + cur_out, 1, write_sz, outf);
504841fb73aSRaphael Moreira Zinsly used_out = used_out - n;
505841fb73aSRaphael Moreira Zinsly /* Move head of the fifo */
506841fb73aSRaphael Moreira Zinsly cur_out = (cur_out + n) % fifo_out_len;
507841fb73aSRaphael Moreira Zinsly assert(n <= write_sz);
508841fb73aSRaphael Moreira Zinsly if (n != write_sz) {
509841fb73aSRaphael Moreira Zinsly fprintf(stderr, "error: write\n");
510841fb73aSRaphael Moreira Zinsly rc = -1;
511841fb73aSRaphael Moreira Zinsly goto err5;
512841fb73aSRaphael Moreira Zinsly }
513841fb73aSRaphael Moreira Zinsly }
514841fb73aSRaphael Moreira Zinsly
515841fb73aSRaphael Moreira Zinsly if (last_used > 0) { /* If more data available in the last part */
516841fb73aSRaphael Moreira Zinsly write_sz = last_used; /* Keep it here for later */
517841fb73aSRaphael Moreira Zinsly n = 0;
518841fb73aSRaphael Moreira Zinsly if (write_sz > 0) {
519841fb73aSRaphael Moreira Zinsly n = fwrite(fifo_out, 1, write_sz, outf);
520841fb73aSRaphael Moreira Zinsly used_out = used_out - n;
521841fb73aSRaphael Moreira Zinsly cur_out = (cur_out + n) % fifo_out_len;
522841fb73aSRaphael Moreira Zinsly assert(n <= write_sz);
523841fb73aSRaphael Moreira Zinsly if (n != write_sz) {
524841fb73aSRaphael Moreira Zinsly fprintf(stderr, "error: write\n");
525841fb73aSRaphael Moreira Zinsly rc = -1;
526841fb73aSRaphael Moreira Zinsly goto err5;
527841fb73aSRaphael Moreira Zinsly }
528841fb73aSRaphael Moreira Zinsly }
529841fb73aSRaphael Moreira Zinsly }
530841fb73aSRaphael Moreira Zinsly
531841fb73aSRaphael Moreira Zinsly decomp_state:
532841fb73aSRaphael Moreira Zinsly
533841fb73aSRaphael Moreira Zinsly /* NX decompresses input data */
534841fb73aSRaphael Moreira Zinsly
535841fb73aSRaphael Moreira Zinsly NXPRT(fprintf(stderr, "decomp_state:\n"));
536841fb73aSRaphael Moreira Zinsly
537841fb73aSRaphael Moreira Zinsly if (is_final)
538841fb73aSRaphael Moreira Zinsly goto finish_state;
539841fb73aSRaphael Moreira Zinsly
540841fb73aSRaphael Moreira Zinsly /* Address/len lists */
541841fb73aSRaphael Moreira Zinsly clearp_dde(ddl_in);
542841fb73aSRaphael Moreira Zinsly clearp_dde(ddl_out);
543841fb73aSRaphael Moreira Zinsly
544841fb73aSRaphael Moreira Zinsly /* FC, CRC, HistLen, Table 6-6 */
545841fb73aSRaphael Moreira Zinsly if (resuming) {
546841fb73aSRaphael Moreira Zinsly /* Resuming a partially decompressed input.
547841fb73aSRaphael Moreira Zinsly * The key to resume is supplying the 32KB
548841fb73aSRaphael Moreira Zinsly * dictionary (history) to NX, which is basically
549841fb73aSRaphael Moreira Zinsly * the last 32KB of output produced.
550841fb73aSRaphael Moreira Zinsly */
551841fb73aSRaphael Moreira Zinsly fc = GZIP_FC_DECOMPRESS_RESUME;
552841fb73aSRaphael Moreira Zinsly
553841fb73aSRaphael Moreira Zinsly cmdp->cpb.in_crc = cmdp->cpb.out_crc;
554841fb73aSRaphael Moreira Zinsly cmdp->cpb.in_adler = cmdp->cpb.out_adler;
555841fb73aSRaphael Moreira Zinsly
556841fb73aSRaphael Moreira Zinsly /* Round up the history size to quadword. Section 2.10 */
557841fb73aSRaphael Moreira Zinsly history_len = (history_len + 15) / 16;
558841fb73aSRaphael Moreira Zinsly putnn(cmdp->cpb, in_histlen, history_len);
559841fb73aSRaphael Moreira Zinsly history_len = history_len * 16; /* bytes */
560841fb73aSRaphael Moreira Zinsly
561841fb73aSRaphael Moreira Zinsly if (history_len > 0) {
562841fb73aSRaphael Moreira Zinsly /* Chain in the history buffer to the DDE list */
563841fb73aSRaphael Moreira Zinsly if (cur_out >= history_len) {
564841fb73aSRaphael Moreira Zinsly nx_append_dde(ddl_in, fifo_out
565841fb73aSRaphael Moreira Zinsly + (cur_out - history_len),
566841fb73aSRaphael Moreira Zinsly history_len);
567841fb73aSRaphael Moreira Zinsly } else {
568841fb73aSRaphael Moreira Zinsly nx_append_dde(ddl_in, fifo_out
569841fb73aSRaphael Moreira Zinsly + ((fifo_out_len + cur_out)
570841fb73aSRaphael Moreira Zinsly - history_len),
571841fb73aSRaphael Moreira Zinsly history_len - cur_out);
572841fb73aSRaphael Moreira Zinsly /* Up to 32KB history wraps around fifo_out */
573841fb73aSRaphael Moreira Zinsly nx_append_dde(ddl_in, fifo_out, cur_out);
574841fb73aSRaphael Moreira Zinsly }
575841fb73aSRaphael Moreira Zinsly
576841fb73aSRaphael Moreira Zinsly }
577841fb73aSRaphael Moreira Zinsly } else {
578841fb73aSRaphael Moreira Zinsly /* First decompress job */
579841fb73aSRaphael Moreira Zinsly fc = GZIP_FC_DECOMPRESS;
580841fb73aSRaphael Moreira Zinsly
581841fb73aSRaphael Moreira Zinsly history_len = 0;
582841fb73aSRaphael Moreira Zinsly /* Writing 0 clears out subc as well */
583841fb73aSRaphael Moreira Zinsly cmdp->cpb.in_histlen = 0;
584841fb73aSRaphael Moreira Zinsly total_out = 0;
585841fb73aSRaphael Moreira Zinsly
586841fb73aSRaphael Moreira Zinsly put32(cmdp->cpb, in_crc, INIT_CRC);
587841fb73aSRaphael Moreira Zinsly put32(cmdp->cpb, in_adler, INIT_ADLER);
588841fb73aSRaphael Moreira Zinsly put32(cmdp->cpb, out_crc, INIT_CRC);
589841fb73aSRaphael Moreira Zinsly put32(cmdp->cpb, out_adler, INIT_ADLER);
590841fb73aSRaphael Moreira Zinsly
591841fb73aSRaphael Moreira Zinsly /* Assuming 10% compression ratio initially; use the
592841fb73aSRaphael Moreira Zinsly * most recently measured compression ratio as a
593841fb73aSRaphael Moreira Zinsly * heuristic to estimate the input and output
594841fb73aSRaphael Moreira Zinsly * sizes. If we give too much input, the target buffer
595841fb73aSRaphael Moreira Zinsly * overflows and NX cycles are wasted, and then we
596841fb73aSRaphael Moreira Zinsly * must retry with smaller input size. 1000 is 100%.
597841fb73aSRaphael Moreira Zinsly */
598841fb73aSRaphael Moreira Zinsly last_comp_ratio = 100UL;
599841fb73aSRaphael Moreira Zinsly }
600841fb73aSRaphael Moreira Zinsly cmdp->crb.gzip_fc = 0;
601841fb73aSRaphael Moreira Zinsly putnn(cmdp->crb, gzip_fc, fc);
602841fb73aSRaphael Moreira Zinsly
603841fb73aSRaphael Moreira Zinsly /*
604841fb73aSRaphael Moreira Zinsly * NX source buffers
605841fb73aSRaphael Moreira Zinsly */
606841fb73aSRaphael Moreira Zinsly first_used = fifo_used_first_bytes(cur_in, used_in, fifo_in_len);
607841fb73aSRaphael Moreira Zinsly last_used = fifo_used_last_bytes(cur_in, used_in, fifo_in_len);
608841fb73aSRaphael Moreira Zinsly
609841fb73aSRaphael Moreira Zinsly if (first_used > 0)
610841fb73aSRaphael Moreira Zinsly nx_append_dde(ddl_in, fifo_in + cur_in, first_used);
611841fb73aSRaphael Moreira Zinsly
612841fb73aSRaphael Moreira Zinsly if (last_used > 0)
613841fb73aSRaphael Moreira Zinsly nx_append_dde(ddl_in, fifo_in, last_used);
614841fb73aSRaphael Moreira Zinsly
615841fb73aSRaphael Moreira Zinsly /*
616841fb73aSRaphael Moreira Zinsly * NX target buffers
617841fb73aSRaphael Moreira Zinsly */
618841fb73aSRaphael Moreira Zinsly first_free = fifo_free_first_bytes(cur_out, used_out, fifo_out_len);
619841fb73aSRaphael Moreira Zinsly last_free = fifo_free_last_bytes(cur_out, used_out, fifo_out_len);
620841fb73aSRaphael Moreira Zinsly
621841fb73aSRaphael Moreira Zinsly /* Reduce output free space amount not to overwrite the history */
622841fb73aSRaphael Moreira Zinsly int target_max = NX_MAX(0, fifo_free_bytes(used_out, fifo_out_len)
623841fb73aSRaphael Moreira Zinsly - (1<<16));
624841fb73aSRaphael Moreira Zinsly
625841fb73aSRaphael Moreira Zinsly NXPRT(fprintf(stderr, "target_max %d (0x%x)\n", target_max,
626841fb73aSRaphael Moreira Zinsly target_max));
627841fb73aSRaphael Moreira Zinsly
628841fb73aSRaphael Moreira Zinsly first_free = NX_MIN(target_max, first_free);
629841fb73aSRaphael Moreira Zinsly if (first_free > 0) {
630841fb73aSRaphael Moreira Zinsly first_offset = fifo_free_first_offset(cur_out, used_out);
631841fb73aSRaphael Moreira Zinsly nx_append_dde(ddl_out, fifo_out + first_offset, first_free);
632841fb73aSRaphael Moreira Zinsly }
633841fb73aSRaphael Moreira Zinsly
634841fb73aSRaphael Moreira Zinsly if (last_free > 0) {
635841fb73aSRaphael Moreira Zinsly last_free = NX_MIN(target_max - first_free, last_free);
636841fb73aSRaphael Moreira Zinsly if (last_free > 0) {
637841fb73aSRaphael Moreira Zinsly last_offset = fifo_free_last_offset(cur_out, used_out,
638841fb73aSRaphael Moreira Zinsly fifo_out_len);
639841fb73aSRaphael Moreira Zinsly nx_append_dde(ddl_out, fifo_out + last_offset,
640841fb73aSRaphael Moreira Zinsly last_free);
641841fb73aSRaphael Moreira Zinsly }
642841fb73aSRaphael Moreira Zinsly }
643841fb73aSRaphael Moreira Zinsly
644841fb73aSRaphael Moreira Zinsly /* Target buffer size is used to limit the source data size
645841fb73aSRaphael Moreira Zinsly * based on previous measurements of compression ratio.
646841fb73aSRaphael Moreira Zinsly */
647841fb73aSRaphael Moreira Zinsly
648841fb73aSRaphael Moreira Zinsly /* source_sz includes history */
649841fb73aSRaphael Moreira Zinsly source_sz = getp32(ddl_in, ddebc);
650841fb73aSRaphael Moreira Zinsly assert(source_sz > history_len);
651841fb73aSRaphael Moreira Zinsly source_sz = source_sz - history_len;
652841fb73aSRaphael Moreira Zinsly
653841fb73aSRaphael Moreira Zinsly /* Estimating how much source is needed to 3/4 fill a
654841fb73aSRaphael Moreira Zinsly * target_max size target buffer. If we overshoot, then NX
655841fb73aSRaphael Moreira Zinsly * must repeat the job with smaller input and we waste
656841fb73aSRaphael Moreira Zinsly * bandwidth. If we undershoot then we use more NX calls than
657841fb73aSRaphael Moreira Zinsly * necessary.
658841fb73aSRaphael Moreira Zinsly */
659841fb73aSRaphael Moreira Zinsly
660841fb73aSRaphael Moreira Zinsly source_sz_estimate = ((uint64_t)target_max * last_comp_ratio * 3UL)
661841fb73aSRaphael Moreira Zinsly / 4000;
662841fb73aSRaphael Moreira Zinsly
663841fb73aSRaphael Moreira Zinsly if (source_sz_estimate < source_sz) {
664841fb73aSRaphael Moreira Zinsly /* Target might be small, therefore limiting the
665841fb73aSRaphael Moreira Zinsly * source data.
666841fb73aSRaphael Moreira Zinsly */
667841fb73aSRaphael Moreira Zinsly source_sz = source_sz_estimate;
668841fb73aSRaphael Moreira Zinsly target_sz_estimate = target_max;
669841fb73aSRaphael Moreira Zinsly } else {
670841fb73aSRaphael Moreira Zinsly /* Source file might be small, therefore limiting target
671841fb73aSRaphael Moreira Zinsly * touch pages to a smaller value to save processor cycles.
672841fb73aSRaphael Moreira Zinsly */
673841fb73aSRaphael Moreira Zinsly target_sz_estimate = ((uint64_t)source_sz * 1000UL)
674841fb73aSRaphael Moreira Zinsly / (last_comp_ratio + 1);
675841fb73aSRaphael Moreira Zinsly target_sz_estimate = NX_MIN(2 * target_sz_estimate,
676841fb73aSRaphael Moreira Zinsly target_max);
677841fb73aSRaphael Moreira Zinsly }
678841fb73aSRaphael Moreira Zinsly
679841fb73aSRaphael Moreira Zinsly source_sz = source_sz + history_len;
680841fb73aSRaphael Moreira Zinsly
681841fb73aSRaphael Moreira Zinsly /* Some NX condition codes require submitting the NX job again.
682841fb73aSRaphael Moreira Zinsly * Kernel doesn't handle NX page faults. Expects user code to
683841fb73aSRaphael Moreira Zinsly * touch pages.
684841fb73aSRaphael Moreira Zinsly */
685841fb73aSRaphael Moreira Zinsly pgfault_retries = NX_MAX_FAULTS;
686841fb73aSRaphael Moreira Zinsly
687841fb73aSRaphael Moreira Zinsly restart_nx:
688841fb73aSRaphael Moreira Zinsly
689841fb73aSRaphael Moreira Zinsly putp32(ddl_in, ddebc, source_sz);
690841fb73aSRaphael Moreira Zinsly
691841fb73aSRaphael Moreira Zinsly /* Fault in pages */
692841fb73aSRaphael Moreira Zinsly nxu_touch_pages(cmdp, sizeof(struct nx_gzip_crb_cpb_t), page_sz, 1);
693841fb73aSRaphael Moreira Zinsly nx_touch_pages_dde(ddl_in, 0, page_sz, 0);
694841fb73aSRaphael Moreira Zinsly nx_touch_pages_dde(ddl_out, target_sz_estimate, page_sz, 1);
695841fb73aSRaphael Moreira Zinsly
696841fb73aSRaphael Moreira Zinsly /* Send job to NX */
697841fb73aSRaphael Moreira Zinsly cc = nx_submit_job(ddl_in, ddl_out, cmdp, devhandle);
698841fb73aSRaphael Moreira Zinsly
699841fb73aSRaphael Moreira Zinsly switch (cc) {
700841fb73aSRaphael Moreira Zinsly
701f0479c4bSHaren Myneni case ERR_NX_AT_FAULT:
702841fb73aSRaphael Moreira Zinsly
703841fb73aSRaphael Moreira Zinsly /* We touched the pages ahead of time. In the most common case
704841fb73aSRaphael Moreira Zinsly * we shouldn't be here. But may be some pages were paged out.
705841fb73aSRaphael Moreira Zinsly * Kernel should have placed the faulting address to fsaddr.
706841fb73aSRaphael Moreira Zinsly */
707f0479c4bSHaren Myneni NXPRT(fprintf(stderr, "ERR_NX_AT_FAULT %p\n",
708841fb73aSRaphael Moreira Zinsly (void *)cmdp->crb.csb.fsaddr));
709841fb73aSRaphael Moreira Zinsly
710841fb73aSRaphael Moreira Zinsly if (pgfault_retries == NX_MAX_FAULTS) {
711841fb73aSRaphael Moreira Zinsly /* Try once with exact number of pages */
712841fb73aSRaphael Moreira Zinsly --pgfault_retries;
713841fb73aSRaphael Moreira Zinsly goto restart_nx;
714841fb73aSRaphael Moreira Zinsly } else if (pgfault_retries > 0) {
715841fb73aSRaphael Moreira Zinsly /* If still faulting try fewer input pages
716841fb73aSRaphael Moreira Zinsly * assuming memory outage
717841fb73aSRaphael Moreira Zinsly */
718841fb73aSRaphael Moreira Zinsly if (source_sz > page_sz)
719841fb73aSRaphael Moreira Zinsly source_sz = NX_MAX(source_sz / 2, page_sz);
720841fb73aSRaphael Moreira Zinsly --pgfault_retries;
721841fb73aSRaphael Moreira Zinsly goto restart_nx;
722841fb73aSRaphael Moreira Zinsly } else {
723841fb73aSRaphael Moreira Zinsly fprintf(stderr, "cannot make progress; too many ");
724841fb73aSRaphael Moreira Zinsly fprintf(stderr, "page fault retries cc= %d\n", cc);
725841fb73aSRaphael Moreira Zinsly rc = -1;
726841fb73aSRaphael Moreira Zinsly goto err5;
727841fb73aSRaphael Moreira Zinsly }
728841fb73aSRaphael Moreira Zinsly
729841fb73aSRaphael Moreira Zinsly case ERR_NX_DATA_LENGTH:
730841fb73aSRaphael Moreira Zinsly
731841fb73aSRaphael Moreira Zinsly NXPRT(fprintf(stderr, "ERR_NX_DATA_LENGTH; "));
732841fb73aSRaphael Moreira Zinsly NXPRT(fprintf(stderr, "stream may have trailing data\n"));
733841fb73aSRaphael Moreira Zinsly
734841fb73aSRaphael Moreira Zinsly /* Not an error in the most common case; it just says
735841fb73aSRaphael Moreira Zinsly * there is trailing data that we must examine.
736841fb73aSRaphael Moreira Zinsly *
737841fb73aSRaphael Moreira Zinsly * CC=3 CE(1)=0 CE(0)=1 indicates partial completion
738841fb73aSRaphael Moreira Zinsly * Fig.6-7 and Table 6-8.
739841fb73aSRaphael Moreira Zinsly */
740841fb73aSRaphael Moreira Zinsly nx_ce = get_csb_ce_ms3b(cmdp->crb.csb);
741841fb73aSRaphael Moreira Zinsly
742841fb73aSRaphael Moreira Zinsly if (!csb_ce_termination(nx_ce) &&
743841fb73aSRaphael Moreira Zinsly csb_ce_partial_completion(nx_ce)) {
744841fb73aSRaphael Moreira Zinsly /* Check CPB for more information
745841fb73aSRaphael Moreira Zinsly * spbc and tpbc are valid
746841fb73aSRaphael Moreira Zinsly */
747841fb73aSRaphael Moreira Zinsly sfbt = getnn(cmdp->cpb, out_sfbt); /* Table 6-4 */
748841fb73aSRaphael Moreira Zinsly subc = getnn(cmdp->cpb, out_subc); /* Table 6-4 */
749841fb73aSRaphael Moreira Zinsly spbc = get32(cmdp->cpb, out_spbc_decomp);
750841fb73aSRaphael Moreira Zinsly tpbc = get32(cmdp->crb.csb, tpbc);
751841fb73aSRaphael Moreira Zinsly assert(target_max >= tpbc);
752841fb73aSRaphael Moreira Zinsly
753841fb73aSRaphael Moreira Zinsly goto ok_cc3; /* not an error */
754841fb73aSRaphael Moreira Zinsly } else {
755841fb73aSRaphael Moreira Zinsly /* History length error when CE(1)=1 CE(0)=0. */
756841fb73aSRaphael Moreira Zinsly rc = -1;
757841fb73aSRaphael Moreira Zinsly fprintf(stderr, "history length error cc= %d\n", cc);
758841fb73aSRaphael Moreira Zinsly goto err5;
759841fb73aSRaphael Moreira Zinsly }
760841fb73aSRaphael Moreira Zinsly
761841fb73aSRaphael Moreira Zinsly case ERR_NX_TARGET_SPACE:
762841fb73aSRaphael Moreira Zinsly
763841fb73aSRaphael Moreira Zinsly /* Target buffer not large enough; retry smaller input
764841fb73aSRaphael Moreira Zinsly * data; give at least 1 byte. SPBC/TPBC are not valid.
765841fb73aSRaphael Moreira Zinsly */
766841fb73aSRaphael Moreira Zinsly assert(source_sz > history_len);
767841fb73aSRaphael Moreira Zinsly source_sz = ((source_sz - history_len + 2) / 2) + history_len;
768841fb73aSRaphael Moreira Zinsly NXPRT(fprintf(stderr, "ERR_NX_TARGET_SPACE; retry with "));
769841fb73aSRaphael Moreira Zinsly NXPRT(fprintf(stderr, "smaller input data src %d hist %d\n",
770841fb73aSRaphael Moreira Zinsly source_sz, history_len));
771841fb73aSRaphael Moreira Zinsly goto restart_nx;
772841fb73aSRaphael Moreira Zinsly
773841fb73aSRaphael Moreira Zinsly case ERR_NX_OK:
774841fb73aSRaphael Moreira Zinsly
775841fb73aSRaphael Moreira Zinsly /* This should not happen for gzip formatted data;
776841fb73aSRaphael Moreira Zinsly * we need trailing crc and isize
777841fb73aSRaphael Moreira Zinsly */
778841fb73aSRaphael Moreira Zinsly fprintf(stderr, "ERR_NX_OK\n");
779841fb73aSRaphael Moreira Zinsly spbc = get32(cmdp->cpb, out_spbc_decomp);
780841fb73aSRaphael Moreira Zinsly tpbc = get32(cmdp->crb.csb, tpbc);
781841fb73aSRaphael Moreira Zinsly assert(target_max >= tpbc);
782841fb73aSRaphael Moreira Zinsly assert(spbc >= history_len);
783841fb73aSRaphael Moreira Zinsly source_sz = spbc - history_len;
784841fb73aSRaphael Moreira Zinsly goto offsets_state;
785841fb73aSRaphael Moreira Zinsly
786841fb73aSRaphael Moreira Zinsly default:
787841fb73aSRaphael Moreira Zinsly fprintf(stderr, "error: cc= %d\n", cc);
788841fb73aSRaphael Moreira Zinsly rc = -1;
789841fb73aSRaphael Moreira Zinsly goto err5;
790841fb73aSRaphael Moreira Zinsly }
791841fb73aSRaphael Moreira Zinsly
792841fb73aSRaphael Moreira Zinsly ok_cc3:
793841fb73aSRaphael Moreira Zinsly
794841fb73aSRaphael Moreira Zinsly NXPRT(fprintf(stderr, "cc3: sfbt: %x\n", sfbt));
795841fb73aSRaphael Moreira Zinsly
796841fb73aSRaphael Moreira Zinsly assert(spbc > history_len);
797841fb73aSRaphael Moreira Zinsly source_sz = spbc - history_len;
798841fb73aSRaphael Moreira Zinsly
799841fb73aSRaphael Moreira Zinsly /* Table 6-4: Source Final Block Type (SFBT) describes the
800841fb73aSRaphael Moreira Zinsly * last processed deflate block and clues the software how to
801841fb73aSRaphael Moreira Zinsly * resume the next job. SUBC indicates how many input bits NX
802841fb73aSRaphael Moreira Zinsly * consumed but did not process. SPBC indicates how many
803841fb73aSRaphael Moreira Zinsly * bytes of source were given to the accelerator including
804841fb73aSRaphael Moreira Zinsly * history bytes.
805841fb73aSRaphael Moreira Zinsly */
806841fb73aSRaphael Moreira Zinsly
807841fb73aSRaphael Moreira Zinsly switch (sfbt) {
808841fb73aSRaphael Moreira Zinsly int dhtlen;
809841fb73aSRaphael Moreira Zinsly
810841fb73aSRaphael Moreira Zinsly case 0x0: /* Deflate final EOB received */
811841fb73aSRaphael Moreira Zinsly
812841fb73aSRaphael Moreira Zinsly /* Calculating the checksum start position. */
813841fb73aSRaphael Moreira Zinsly
814841fb73aSRaphael Moreira Zinsly source_sz = source_sz - subc / 8;
815841fb73aSRaphael Moreira Zinsly is_final = 1;
816841fb73aSRaphael Moreira Zinsly break;
817841fb73aSRaphael Moreira Zinsly
818841fb73aSRaphael Moreira Zinsly /* Resume decompression cases are below. Basically
819841fb73aSRaphael Moreira Zinsly * indicates where NX has suspended and how to resume
820841fb73aSRaphael Moreira Zinsly * the input stream.
821841fb73aSRaphael Moreira Zinsly */
822841fb73aSRaphael Moreira Zinsly
823841fb73aSRaphael Moreira Zinsly case 0x8: /* Within a literal block; use rembytecount */
824841fb73aSRaphael Moreira Zinsly case 0x9: /* Within a literal block; use rembytecount; bfinal=1 */
825841fb73aSRaphael Moreira Zinsly
826841fb73aSRaphael Moreira Zinsly /* Supply the partially processed source byte again */
827841fb73aSRaphael Moreira Zinsly source_sz = source_sz - ((subc + 7) / 8);
828841fb73aSRaphael Moreira Zinsly
829841fb73aSRaphael Moreira Zinsly /* SUBC LS 3bits: number of bits in the first source byte need
830841fb73aSRaphael Moreira Zinsly * to be processed.
831841fb73aSRaphael Moreira Zinsly * 000 means all 8 bits; Table 6-3
832841fb73aSRaphael Moreira Zinsly * Clear subc, histlen, sfbt, rembytecnt, dhtlen
833841fb73aSRaphael Moreira Zinsly */
834841fb73aSRaphael Moreira Zinsly cmdp->cpb.in_subc = 0;
835841fb73aSRaphael Moreira Zinsly cmdp->cpb.in_sfbt = 0;
836841fb73aSRaphael Moreira Zinsly putnn(cmdp->cpb, in_subc, subc % 8);
837841fb73aSRaphael Moreira Zinsly putnn(cmdp->cpb, in_sfbt, sfbt);
838841fb73aSRaphael Moreira Zinsly putnn(cmdp->cpb, in_rembytecnt, getnn(cmdp->cpb,
839841fb73aSRaphael Moreira Zinsly out_rembytecnt));
840841fb73aSRaphael Moreira Zinsly break;
841841fb73aSRaphael Moreira Zinsly
842841fb73aSRaphael Moreira Zinsly case 0xA: /* Within a FH block; */
843841fb73aSRaphael Moreira Zinsly case 0xB: /* Within a FH block; bfinal=1 */
844841fb73aSRaphael Moreira Zinsly
845841fb73aSRaphael Moreira Zinsly source_sz = source_sz - ((subc + 7) / 8);
846841fb73aSRaphael Moreira Zinsly
847841fb73aSRaphael Moreira Zinsly /* Clear subc, histlen, sfbt, rembytecnt, dhtlen */
848841fb73aSRaphael Moreira Zinsly cmdp->cpb.in_subc = 0;
849841fb73aSRaphael Moreira Zinsly cmdp->cpb.in_sfbt = 0;
850841fb73aSRaphael Moreira Zinsly putnn(cmdp->cpb, in_subc, subc % 8);
851841fb73aSRaphael Moreira Zinsly putnn(cmdp->cpb, in_sfbt, sfbt);
852841fb73aSRaphael Moreira Zinsly break;
853841fb73aSRaphael Moreira Zinsly
854841fb73aSRaphael Moreira Zinsly case 0xC: /* Within a DH block; */
855841fb73aSRaphael Moreira Zinsly case 0xD: /* Within a DH block; bfinal=1 */
856841fb73aSRaphael Moreira Zinsly
857841fb73aSRaphael Moreira Zinsly source_sz = source_sz - ((subc + 7) / 8);
858841fb73aSRaphael Moreira Zinsly
859841fb73aSRaphael Moreira Zinsly /* Clear subc, histlen, sfbt, rembytecnt, dhtlen */
860841fb73aSRaphael Moreira Zinsly cmdp->cpb.in_subc = 0;
861841fb73aSRaphael Moreira Zinsly cmdp->cpb.in_sfbt = 0;
862841fb73aSRaphael Moreira Zinsly putnn(cmdp->cpb, in_subc, subc % 8);
863841fb73aSRaphael Moreira Zinsly putnn(cmdp->cpb, in_sfbt, sfbt);
864841fb73aSRaphael Moreira Zinsly
865841fb73aSRaphael Moreira Zinsly dhtlen = getnn(cmdp->cpb, out_dhtlen);
866841fb73aSRaphael Moreira Zinsly putnn(cmdp->cpb, in_dhtlen, dhtlen);
867841fb73aSRaphael Moreira Zinsly assert(dhtlen >= 42);
868841fb73aSRaphael Moreira Zinsly
869841fb73aSRaphael Moreira Zinsly /* Round up to a qword */
870841fb73aSRaphael Moreira Zinsly dhtlen = (dhtlen + 127) / 128;
871841fb73aSRaphael Moreira Zinsly
872841fb73aSRaphael Moreira Zinsly while (dhtlen > 0) { /* Copy dht from cpb.out to cpb.in */
873841fb73aSRaphael Moreira Zinsly --dhtlen;
874841fb73aSRaphael Moreira Zinsly cmdp->cpb.in_dht[dhtlen] = cmdp->cpb.out_dht[dhtlen];
875841fb73aSRaphael Moreira Zinsly }
876841fb73aSRaphael Moreira Zinsly break;
877841fb73aSRaphael Moreira Zinsly
878841fb73aSRaphael Moreira Zinsly case 0xE: /* Within a block header; bfinal=0; */
879841fb73aSRaphael Moreira Zinsly /* Also given if source data exactly ends (SUBC=0) with
880841fb73aSRaphael Moreira Zinsly * EOB code with BFINAL=0. Means the next byte will
881841fb73aSRaphael Moreira Zinsly * contain a block header.
882841fb73aSRaphael Moreira Zinsly */
883841fb73aSRaphael Moreira Zinsly case 0xF: /* within a block header with BFINAL=1. */
884841fb73aSRaphael Moreira Zinsly
885841fb73aSRaphael Moreira Zinsly source_sz = source_sz - ((subc + 7) / 8);
886841fb73aSRaphael Moreira Zinsly
887841fb73aSRaphael Moreira Zinsly /* Clear subc, histlen, sfbt, rembytecnt, dhtlen */
888841fb73aSRaphael Moreira Zinsly cmdp->cpb.in_subc = 0;
889841fb73aSRaphael Moreira Zinsly cmdp->cpb.in_sfbt = 0;
890841fb73aSRaphael Moreira Zinsly putnn(cmdp->cpb, in_subc, subc % 8);
891841fb73aSRaphael Moreira Zinsly putnn(cmdp->cpb, in_sfbt, sfbt);
892841fb73aSRaphael Moreira Zinsly
893841fb73aSRaphael Moreira Zinsly /* Engine did not process any data */
894841fb73aSRaphael Moreira Zinsly if (is_eof && (source_sz == 0))
895841fb73aSRaphael Moreira Zinsly is_final = 1;
896841fb73aSRaphael Moreira Zinsly }
897841fb73aSRaphael Moreira Zinsly
898841fb73aSRaphael Moreira Zinsly offsets_state:
899841fb73aSRaphael Moreira Zinsly
900841fb73aSRaphael Moreira Zinsly /* Adjust the source and target buffer offsets and lengths */
901841fb73aSRaphael Moreira Zinsly
902841fb73aSRaphael Moreira Zinsly NXPRT(fprintf(stderr, "offsets_state:\n"));
903841fb73aSRaphael Moreira Zinsly
904841fb73aSRaphael Moreira Zinsly /* Delete input data from fifo_in */
905841fb73aSRaphael Moreira Zinsly used_in = used_in - source_sz;
906841fb73aSRaphael Moreira Zinsly cur_in = (cur_in + source_sz) % fifo_in_len;
907841fb73aSRaphael Moreira Zinsly input_file_offset = input_file_offset + source_sz;
908841fb73aSRaphael Moreira Zinsly
909841fb73aSRaphael Moreira Zinsly /* Add output data to fifo_out */
910841fb73aSRaphael Moreira Zinsly used_out = used_out + tpbc;
911841fb73aSRaphael Moreira Zinsly
912841fb73aSRaphael Moreira Zinsly assert(used_out <= fifo_out_len);
913841fb73aSRaphael Moreira Zinsly
914841fb73aSRaphael Moreira Zinsly total_out = total_out + tpbc;
915841fb73aSRaphael Moreira Zinsly
916841fb73aSRaphael Moreira Zinsly /* Deflate history is 32KB max. No need to supply more
917841fb73aSRaphael Moreira Zinsly * than 32KB on a resume.
918841fb73aSRaphael Moreira Zinsly */
919841fb73aSRaphael Moreira Zinsly history_len = (total_out > window_max) ? window_max : total_out;
920841fb73aSRaphael Moreira Zinsly
921841fb73aSRaphael Moreira Zinsly /* To estimate expected expansion in the next NX job; 500 means 50%.
922841fb73aSRaphael Moreira Zinsly * Deflate best case is around 1 to 1000.
923841fb73aSRaphael Moreira Zinsly */
924841fb73aSRaphael Moreira Zinsly last_comp_ratio = (1000UL * ((uint64_t)source_sz + 1))
925841fb73aSRaphael Moreira Zinsly / ((uint64_t)tpbc + 1);
926841fb73aSRaphael Moreira Zinsly last_comp_ratio = NX_MAX(NX_MIN(1000UL, last_comp_ratio), 1);
927841fb73aSRaphael Moreira Zinsly NXPRT(fprintf(stderr, "comp_ratio %ld source_sz %d spbc %d tpbc %d\n",
928841fb73aSRaphael Moreira Zinsly last_comp_ratio, source_sz, spbc, tpbc));
929841fb73aSRaphael Moreira Zinsly
930841fb73aSRaphael Moreira Zinsly resuming = 1;
931841fb73aSRaphael Moreira Zinsly
932841fb73aSRaphael Moreira Zinsly finish_state:
933841fb73aSRaphael Moreira Zinsly
934841fb73aSRaphael Moreira Zinsly NXPRT(fprintf(stderr, "finish_state:\n"));
935841fb73aSRaphael Moreira Zinsly
936841fb73aSRaphael Moreira Zinsly if (is_final) {
937841fb73aSRaphael Moreira Zinsly if (used_out)
938841fb73aSRaphael Moreira Zinsly goto write_state; /* More data to write out */
939841fb73aSRaphael Moreira Zinsly else if (used_in < 8) {
940841fb73aSRaphael Moreira Zinsly /* Need at least 8 more bytes containing gzip crc
941841fb73aSRaphael Moreira Zinsly * and isize.
942841fb73aSRaphael Moreira Zinsly */
943841fb73aSRaphael Moreira Zinsly rc = -1;
944841fb73aSRaphael Moreira Zinsly goto err4;
945841fb73aSRaphael Moreira Zinsly } else {
946841fb73aSRaphael Moreira Zinsly /* Compare checksums and exit */
947841fb73aSRaphael Moreira Zinsly int i;
948841fb73aSRaphael Moreira Zinsly unsigned char tail[8];
949841fb73aSRaphael Moreira Zinsly uint32_t cksum, isize;
950841fb73aSRaphael Moreira Zinsly
951841fb73aSRaphael Moreira Zinsly for (i = 0; i < 8; i++)
952841fb73aSRaphael Moreira Zinsly tail[i] = fifo_in[(cur_in + i) % fifo_in_len];
953841fb73aSRaphael Moreira Zinsly fprintf(stderr, "computed checksum %08x isize %08x\n",
954841fb73aSRaphael Moreira Zinsly cmdp->cpb.out_crc, (uint32_t) (total_out
955841fb73aSRaphael Moreira Zinsly % (1ULL<<32)));
956841fb73aSRaphael Moreira Zinsly cksum = ((uint32_t) tail[0] | (uint32_t) tail[1]<<8
957841fb73aSRaphael Moreira Zinsly | (uint32_t) tail[2]<<16
958841fb73aSRaphael Moreira Zinsly | (uint32_t) tail[3]<<24);
959841fb73aSRaphael Moreira Zinsly isize = ((uint32_t) tail[4] | (uint32_t) tail[5]<<8
960841fb73aSRaphael Moreira Zinsly | (uint32_t) tail[6]<<16
961841fb73aSRaphael Moreira Zinsly | (uint32_t) tail[7]<<24);
962841fb73aSRaphael Moreira Zinsly fprintf(stderr, "stored checksum %08x isize %08x\n",
963841fb73aSRaphael Moreira Zinsly cksum, isize);
964841fb73aSRaphael Moreira Zinsly
965841fb73aSRaphael Moreira Zinsly if (cksum == cmdp->cpb.out_crc && isize == (uint32_t)
966841fb73aSRaphael Moreira Zinsly (total_out % (1ULL<<32))) {
967841fb73aSRaphael Moreira Zinsly rc = 0; goto ok1;
968841fb73aSRaphael Moreira Zinsly } else {
969841fb73aSRaphael Moreira Zinsly rc = -1; goto err4;
970841fb73aSRaphael Moreira Zinsly }
971841fb73aSRaphael Moreira Zinsly }
972841fb73aSRaphael Moreira Zinsly } else
973841fb73aSRaphael Moreira Zinsly goto read_state;
974841fb73aSRaphael Moreira Zinsly
975841fb73aSRaphael Moreira Zinsly return -1;
976841fb73aSRaphael Moreira Zinsly
977841fb73aSRaphael Moreira Zinsly err1:
978841fb73aSRaphael Moreira Zinsly fprintf(stderr, "error: not a gzip file, expect %x, read %x\n",
979841fb73aSRaphael Moreira Zinsly expect, c);
980841fb73aSRaphael Moreira Zinsly return -1;
981841fb73aSRaphael Moreira Zinsly
982841fb73aSRaphael Moreira Zinsly err2:
983841fb73aSRaphael Moreira Zinsly fprintf(stderr, "error: the FLG byte is wrong or not being handled\n");
984841fb73aSRaphael Moreira Zinsly return -1;
985841fb73aSRaphael Moreira Zinsly
986841fb73aSRaphael Moreira Zinsly err3:
987841fb73aSRaphael Moreira Zinsly fprintf(stderr, "error: gzip header\n");
988841fb73aSRaphael Moreira Zinsly return -1;
989841fb73aSRaphael Moreira Zinsly
990841fb73aSRaphael Moreira Zinsly err4:
991841fb73aSRaphael Moreira Zinsly fprintf(stderr, "error: checksum missing or mismatch\n");
992841fb73aSRaphael Moreira Zinsly
993841fb73aSRaphael Moreira Zinsly err5:
994841fb73aSRaphael Moreira Zinsly ok1:
995841fb73aSRaphael Moreira Zinsly fprintf(stderr, "decomp is complete: fclose\n");
996841fb73aSRaphael Moreira Zinsly fclose(outf);
997841fb73aSRaphael Moreira Zinsly
998841fb73aSRaphael Moreira Zinsly return rc;
999841fb73aSRaphael Moreira Zinsly }
1000841fb73aSRaphael Moreira Zinsly
1001841fb73aSRaphael Moreira Zinsly
main(int argc,char ** argv)1002841fb73aSRaphael Moreira Zinsly int main(int argc, char **argv)
1003841fb73aSRaphael Moreira Zinsly {
1004841fb73aSRaphael Moreira Zinsly int rc;
1005841fb73aSRaphael Moreira Zinsly struct sigaction act;
1006841fb73aSRaphael Moreira Zinsly void *handle;
1007841fb73aSRaphael Moreira Zinsly
1008841fb73aSRaphael Moreira Zinsly nx_dbg = 0;
1009841fb73aSRaphael Moreira Zinsly nx_gzip_log = NULL;
1010841fb73aSRaphael Moreira Zinsly act.sa_handler = 0;
1011841fb73aSRaphael Moreira Zinsly act.sa_sigaction = nxu_sigsegv_handler;
1012841fb73aSRaphael Moreira Zinsly act.sa_flags = SA_SIGINFO;
1013841fb73aSRaphael Moreira Zinsly act.sa_restorer = 0;
1014841fb73aSRaphael Moreira Zinsly sigemptyset(&act.sa_mask);
1015841fb73aSRaphael Moreira Zinsly sigaction(SIGSEGV, &act, NULL);
1016841fb73aSRaphael Moreira Zinsly
1017841fb73aSRaphael Moreira Zinsly handle = nx_function_begin(NX_FUNC_COMP_GZIP, 0);
1018841fb73aSRaphael Moreira Zinsly if (!handle) {
1019841fb73aSRaphael Moreira Zinsly fprintf(stderr, "Unable to init NX, errno %d\n", errno);
1020841fb73aSRaphael Moreira Zinsly exit(-1);
1021841fb73aSRaphael Moreira Zinsly }
1022841fb73aSRaphael Moreira Zinsly
1023841fb73aSRaphael Moreira Zinsly rc = decompress_file(argc, argv, handle);
1024841fb73aSRaphael Moreira Zinsly
1025841fb73aSRaphael Moreira Zinsly nx_function_end(handle);
1026841fb73aSRaphael Moreira Zinsly
1027841fb73aSRaphael Moreira Zinsly return rc;
1028841fb73aSRaphael Moreira Zinsly }
1029