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