18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later
28c2ecf20Sopenharmony_ci
38c2ecf20Sopenharmony_ci/* P9 gunzip sample code for demonstrating the P9 NX hardware
48c2ecf20Sopenharmony_ci * interface.  Not intended for productive uses or for performance or
58c2ecf20Sopenharmony_ci * compression ratio measurements.  Note also that /dev/crypto/gzip,
68c2ecf20Sopenharmony_ci * VAS and skiboot support are required
78c2ecf20Sopenharmony_ci *
88c2ecf20Sopenharmony_ci * Copyright 2020 IBM Corp.
98c2ecf20Sopenharmony_ci *
108c2ecf20Sopenharmony_ci * Author: Bulent Abali <abali@us.ibm.com>
118c2ecf20Sopenharmony_ci *
128c2ecf20Sopenharmony_ci * https://github.com/libnxz/power-gzip for zlib api and other utils
138c2ecf20Sopenharmony_ci * Definitions of acronyms used here.  See
148c2ecf20Sopenharmony_ci * P9 NX Gzip Accelerator User's Manual for details:
158c2ecf20Sopenharmony_ci * https://github.com/libnxz/power-gzip/blob/develop/doc/power_nx_gzip_um.pdf
168c2ecf20Sopenharmony_ci *
178c2ecf20Sopenharmony_ci * adler/crc: 32 bit checksums appended to stream tail
188c2ecf20Sopenharmony_ci * ce:       completion extension
198c2ecf20Sopenharmony_ci * cpb:      coprocessor parameter block (metadata)
208c2ecf20Sopenharmony_ci * crb:      coprocessor request block (command)
218c2ecf20Sopenharmony_ci * csb:      coprocessor status block (status)
228c2ecf20Sopenharmony_ci * dht:      dynamic huffman table
238c2ecf20Sopenharmony_ci * dde:      data descriptor element (address, length)
248c2ecf20Sopenharmony_ci * ddl:      list of ddes
258c2ecf20Sopenharmony_ci * dh/fh:    dynamic and fixed huffman types
268c2ecf20Sopenharmony_ci * fc:       coprocessor function code
278c2ecf20Sopenharmony_ci * histlen:  history/dictionary length
288c2ecf20Sopenharmony_ci * history:  sliding window of up to 32KB of data
298c2ecf20Sopenharmony_ci * lzcount:  Deflate LZ symbol counts
308c2ecf20Sopenharmony_ci * rembytecnt: remaining byte count
318c2ecf20Sopenharmony_ci * sfbt:     source final block type; last block's type during decomp
328c2ecf20Sopenharmony_ci * spbc:     source processed byte count
338c2ecf20Sopenharmony_ci * subc:     source unprocessed bit count
348c2ecf20Sopenharmony_ci * tebc:     target ending bit count; valid bits in the last byte
358c2ecf20Sopenharmony_ci * tpbc:     target processed byte count
368c2ecf20Sopenharmony_ci * vas:      virtual accelerator switch; the user mode interface
378c2ecf20Sopenharmony_ci */
388c2ecf20Sopenharmony_ci
398c2ecf20Sopenharmony_ci#define _ISOC11_SOURCE	// For aligned_alloc()
408c2ecf20Sopenharmony_ci#define _DEFAULT_SOURCE	// For endian.h
418c2ecf20Sopenharmony_ci
428c2ecf20Sopenharmony_ci#include <stdio.h>
438c2ecf20Sopenharmony_ci#include <stdlib.h>
448c2ecf20Sopenharmony_ci#include <string.h>
458c2ecf20Sopenharmony_ci#include <unistd.h>
468c2ecf20Sopenharmony_ci#include <stdint.h>
478c2ecf20Sopenharmony_ci#include <sys/types.h>
488c2ecf20Sopenharmony_ci#include <sys/stat.h>
498c2ecf20Sopenharmony_ci#include <sys/time.h>
508c2ecf20Sopenharmony_ci#include <sys/fcntl.h>
518c2ecf20Sopenharmony_ci#include <sys/mman.h>
528c2ecf20Sopenharmony_ci#include <endian.h>
538c2ecf20Sopenharmony_ci#include <bits/endian.h>
548c2ecf20Sopenharmony_ci#include <sys/ioctl.h>
558c2ecf20Sopenharmony_ci#include <assert.h>
568c2ecf20Sopenharmony_ci#include <errno.h>
578c2ecf20Sopenharmony_ci#include <signal.h>
588c2ecf20Sopenharmony_ci#include "nxu.h"
598c2ecf20Sopenharmony_ci#include "nx.h"
608c2ecf20Sopenharmony_ci#include "crb.h"
618c2ecf20Sopenharmony_ci
628c2ecf20Sopenharmony_ciint nx_dbg;
638c2ecf20Sopenharmony_ciFILE *nx_gzip_log;
648c2ecf20Sopenharmony_ci
658c2ecf20Sopenharmony_ci#define NX_MIN(X, Y) (((X) < (Y))?(X):(Y))
668c2ecf20Sopenharmony_ci#define NX_MAX(X, Y) (((X) > (Y))?(X):(Y))
678c2ecf20Sopenharmony_ci
688c2ecf20Sopenharmony_ci#define GETINPC(X) fgetc(X)
698c2ecf20Sopenharmony_ci#define FNAME_MAX 1024
708c2ecf20Sopenharmony_ci
718c2ecf20Sopenharmony_ci/* fifo queue management */
728c2ecf20Sopenharmony_ci#define fifo_used_bytes(used) (used)
738c2ecf20Sopenharmony_ci#define fifo_free_bytes(used, len) ((len)-(used))
748c2ecf20Sopenharmony_ci/* amount of free bytes in the first and last parts */
758c2ecf20Sopenharmony_ci#define fifo_free_first_bytes(cur, used, len)  ((((cur)+(used)) <= (len)) \
768c2ecf20Sopenharmony_ci						  ? (len)-((cur)+(used)) : 0)
778c2ecf20Sopenharmony_ci#define fifo_free_last_bytes(cur, used, len)   ((((cur)+(used)) <= (len)) \
788c2ecf20Sopenharmony_ci						  ? (cur) : (len)-(used))
798c2ecf20Sopenharmony_ci/* amount of used bytes in the first and last parts */
808c2ecf20Sopenharmony_ci#define fifo_used_first_bytes(cur, used, len)  ((((cur)+(used)) <= (len)) \
818c2ecf20Sopenharmony_ci						  ? (used) : (len)-(cur))
828c2ecf20Sopenharmony_ci#define fifo_used_last_bytes(cur, used, len)   ((((cur)+(used)) <= (len)) \
838c2ecf20Sopenharmony_ci						  ? 0 : ((used)+(cur))-(len))
848c2ecf20Sopenharmony_ci/* first and last free parts start here */
858c2ecf20Sopenharmony_ci#define fifo_free_first_offset(cur, used)      ((cur)+(used))
868c2ecf20Sopenharmony_ci#define fifo_free_last_offset(cur, used, len)  \
878c2ecf20Sopenharmony_ci					   fifo_used_last_bytes(cur, used, len)
888c2ecf20Sopenharmony_ci/* first and last used parts start here */
898c2ecf20Sopenharmony_ci#define fifo_used_first_offset(cur)            (cur)
908c2ecf20Sopenharmony_ci#define fifo_used_last_offset(cur)             (0)
918c2ecf20Sopenharmony_ci
928c2ecf20Sopenharmony_ciconst int fifo_in_len = 1<<24;
938c2ecf20Sopenharmony_ciconst int fifo_out_len = 1<<24;
948c2ecf20Sopenharmony_ciconst int page_sz = 1<<16;
958c2ecf20Sopenharmony_ciconst int line_sz = 1<<7;
968c2ecf20Sopenharmony_ciconst int window_max = 1<<15;
978c2ecf20Sopenharmony_ci
988c2ecf20Sopenharmony_ci/*
998c2ecf20Sopenharmony_ci * Adds an (address, len) pair to the list of ddes (ddl) and updates
1008c2ecf20Sopenharmony_ci * the base dde.  ddl[0] is the only dde in a direct dde which
1018c2ecf20Sopenharmony_ci * contains a single (addr,len) pair.  For more pairs, ddl[0] becomes
1028c2ecf20Sopenharmony_ci * the indirect (base) dde that points to a list of direct ddes.
1038c2ecf20Sopenharmony_ci * See Section 6.4 of the NX-gzip user manual for DDE description.
1048c2ecf20Sopenharmony_ci * Addr=NULL, len=0 clears the ddl[0].  Returns the total number of
1058c2ecf20Sopenharmony_ci * bytes in ddl.  Caller is responsible for allocting the array of
1068c2ecf20Sopenharmony_ci * nx_dde_t *ddl.  If N addresses are required in the scatter-gather
1078c2ecf20Sopenharmony_ci * list, the ddl array must have N+1 entries minimum.
1088c2ecf20Sopenharmony_ci */
1098c2ecf20Sopenharmony_cistatic inline uint32_t nx_append_dde(struct nx_dde_t *ddl, void *addr,
1108c2ecf20Sopenharmony_ci					uint32_t len)
1118c2ecf20Sopenharmony_ci{
1128c2ecf20Sopenharmony_ci	uint32_t ddecnt;
1138c2ecf20Sopenharmony_ci	uint32_t bytes;
1148c2ecf20Sopenharmony_ci
1158c2ecf20Sopenharmony_ci	if (addr == NULL && len == 0) {
1168c2ecf20Sopenharmony_ci		clearp_dde(ddl);
1178c2ecf20Sopenharmony_ci		return 0;
1188c2ecf20Sopenharmony_ci	}
1198c2ecf20Sopenharmony_ci
1208c2ecf20Sopenharmony_ci	NXPRT(fprintf(stderr, "%d: %s addr %p len %x\n", __LINE__, addr,
1218c2ecf20Sopenharmony_ci			__func__, len));
1228c2ecf20Sopenharmony_ci
1238c2ecf20Sopenharmony_ci	/* Number of ddes in the dde list ; == 0 when it is a direct dde */
1248c2ecf20Sopenharmony_ci	ddecnt = getpnn(ddl, dde_count);
1258c2ecf20Sopenharmony_ci	bytes = getp32(ddl, ddebc);
1268c2ecf20Sopenharmony_ci
1278c2ecf20Sopenharmony_ci	if (ddecnt == 0 && bytes == 0) {
1288c2ecf20Sopenharmony_ci		/* First dde is unused; make it a direct dde */
1298c2ecf20Sopenharmony_ci		bytes = len;
1308c2ecf20Sopenharmony_ci		putp32(ddl, ddebc, bytes);
1318c2ecf20Sopenharmony_ci		putp64(ddl, ddead, (uint64_t) addr);
1328c2ecf20Sopenharmony_ci	} else if (ddecnt == 0) {
1338c2ecf20Sopenharmony_ci		/* Converting direct to indirect dde
1348c2ecf20Sopenharmony_ci		 * ddl[0] becomes head dde of ddl
1358c2ecf20Sopenharmony_ci		 * copy direct to indirect first.
1368c2ecf20Sopenharmony_ci		 */
1378c2ecf20Sopenharmony_ci		ddl[1] = ddl[0];
1388c2ecf20Sopenharmony_ci
1398c2ecf20Sopenharmony_ci		/* Add the new dde next */
1408c2ecf20Sopenharmony_ci		clear_dde(ddl[2]);
1418c2ecf20Sopenharmony_ci		put32(ddl[2], ddebc, len);
1428c2ecf20Sopenharmony_ci		put64(ddl[2], ddead, (uint64_t) addr);
1438c2ecf20Sopenharmony_ci
1448c2ecf20Sopenharmony_ci		/* Ddl head points to 2 direct ddes */
1458c2ecf20Sopenharmony_ci		ddecnt = 2;
1468c2ecf20Sopenharmony_ci		putpnn(ddl, dde_count, ddecnt);
1478c2ecf20Sopenharmony_ci		bytes = bytes + len;
1488c2ecf20Sopenharmony_ci		putp32(ddl, ddebc, bytes);
1498c2ecf20Sopenharmony_ci		/* Pointer to the first direct dde */
1508c2ecf20Sopenharmony_ci		putp64(ddl, ddead, (uint64_t) &ddl[1]);
1518c2ecf20Sopenharmony_ci	} else {
1528c2ecf20Sopenharmony_ci		/* Append a dde to an existing indirect ddl */
1538c2ecf20Sopenharmony_ci		++ddecnt;
1548c2ecf20Sopenharmony_ci		clear_dde(ddl[ddecnt]);
1558c2ecf20Sopenharmony_ci		put64(ddl[ddecnt], ddead, (uint64_t) addr);
1568c2ecf20Sopenharmony_ci		put32(ddl[ddecnt], ddebc, len);
1578c2ecf20Sopenharmony_ci
1588c2ecf20Sopenharmony_ci		putpnn(ddl, dde_count, ddecnt);
1598c2ecf20Sopenharmony_ci		bytes = bytes + len;
1608c2ecf20Sopenharmony_ci		putp32(ddl, ddebc, bytes); /* byte sum of all dde */
1618c2ecf20Sopenharmony_ci	}
1628c2ecf20Sopenharmony_ci	return bytes;
1638c2ecf20Sopenharmony_ci}
1648c2ecf20Sopenharmony_ci
1658c2ecf20Sopenharmony_ci/*
1668c2ecf20Sopenharmony_ci * Touch specified number of pages represented in number bytes
1678c2ecf20Sopenharmony_ci * beginning from the first buffer in a dde list.
1688c2ecf20Sopenharmony_ci * Do not touch the pages past buf_sz-th byte's page.
1698c2ecf20Sopenharmony_ci *
1708c2ecf20Sopenharmony_ci * Set buf_sz = 0 to touch all pages described by the ddep.
1718c2ecf20Sopenharmony_ci */
1728c2ecf20Sopenharmony_cistatic int nx_touch_pages_dde(struct nx_dde_t *ddep, long buf_sz, long page_sz,
1738c2ecf20Sopenharmony_ci				int wr)
1748c2ecf20Sopenharmony_ci{
1758c2ecf20Sopenharmony_ci	uint32_t indirect_count;
1768c2ecf20Sopenharmony_ci	uint32_t buf_len;
1778c2ecf20Sopenharmony_ci	long total;
1788c2ecf20Sopenharmony_ci	uint64_t buf_addr;
1798c2ecf20Sopenharmony_ci	struct nx_dde_t *dde_list;
1808c2ecf20Sopenharmony_ci	int i;
1818c2ecf20Sopenharmony_ci
1828c2ecf20Sopenharmony_ci	assert(!!ddep);
1838c2ecf20Sopenharmony_ci
1848c2ecf20Sopenharmony_ci	indirect_count = getpnn(ddep, dde_count);
1858c2ecf20Sopenharmony_ci
1868c2ecf20Sopenharmony_ci	NXPRT(fprintf(stderr, "%s dde_count %d request len ", __func__,
1878c2ecf20Sopenharmony_ci			indirect_count));
1888c2ecf20Sopenharmony_ci	NXPRT(fprintf(stderr, "0x%lx\n", buf_sz));
1898c2ecf20Sopenharmony_ci
1908c2ecf20Sopenharmony_ci	if (indirect_count == 0) {
1918c2ecf20Sopenharmony_ci		/* Direct dde */
1928c2ecf20Sopenharmony_ci		buf_len = getp32(ddep, ddebc);
1938c2ecf20Sopenharmony_ci		buf_addr = getp64(ddep, ddead);
1948c2ecf20Sopenharmony_ci
1958c2ecf20Sopenharmony_ci		NXPRT(fprintf(stderr, "touch direct ddebc 0x%x ddead %p\n",
1968c2ecf20Sopenharmony_ci				buf_len, (void *)buf_addr));
1978c2ecf20Sopenharmony_ci
1988c2ecf20Sopenharmony_ci		if (buf_sz == 0)
1998c2ecf20Sopenharmony_ci			nxu_touch_pages((void *)buf_addr, buf_len, page_sz, wr);
2008c2ecf20Sopenharmony_ci		else
2018c2ecf20Sopenharmony_ci			nxu_touch_pages((void *)buf_addr, NX_MIN(buf_len,
2028c2ecf20Sopenharmony_ci					buf_sz), page_sz, wr);
2038c2ecf20Sopenharmony_ci
2048c2ecf20Sopenharmony_ci		return ERR_NX_OK;
2058c2ecf20Sopenharmony_ci	}
2068c2ecf20Sopenharmony_ci
2078c2ecf20Sopenharmony_ci	/* Indirect dde */
2088c2ecf20Sopenharmony_ci	if (indirect_count > MAX_DDE_COUNT)
2098c2ecf20Sopenharmony_ci		return ERR_NX_EXCESSIVE_DDE;
2108c2ecf20Sopenharmony_ci
2118c2ecf20Sopenharmony_ci	/* First address of the list */
2128c2ecf20Sopenharmony_ci	dde_list = (struct nx_dde_t *) getp64(ddep, ddead);
2138c2ecf20Sopenharmony_ci
2148c2ecf20Sopenharmony_ci	if (buf_sz == 0)
2158c2ecf20Sopenharmony_ci		buf_sz = getp32(ddep, ddebc);
2168c2ecf20Sopenharmony_ci
2178c2ecf20Sopenharmony_ci	total = 0;
2188c2ecf20Sopenharmony_ci	for (i = 0; i < indirect_count; i++) {
2198c2ecf20Sopenharmony_ci		buf_len = get32(dde_list[i], ddebc);
2208c2ecf20Sopenharmony_ci		buf_addr = get64(dde_list[i], ddead);
2218c2ecf20Sopenharmony_ci		total += buf_len;
2228c2ecf20Sopenharmony_ci
2238c2ecf20Sopenharmony_ci		NXPRT(fprintf(stderr, "touch loop len 0x%x ddead %p total ",
2248c2ecf20Sopenharmony_ci				buf_len, (void *)buf_addr));
2258c2ecf20Sopenharmony_ci		NXPRT(fprintf(stderr, "0x%lx\n", total));
2268c2ecf20Sopenharmony_ci
2278c2ecf20Sopenharmony_ci		/* Touching fewer pages than encoded in the ddebc */
2288c2ecf20Sopenharmony_ci		if (total > buf_sz) {
2298c2ecf20Sopenharmony_ci			buf_len = NX_MIN(buf_len, total - buf_sz);
2308c2ecf20Sopenharmony_ci			nxu_touch_pages((void *)buf_addr, buf_len, page_sz, wr);
2318c2ecf20Sopenharmony_ci			NXPRT(fprintf(stderr, "touch loop break len 0x%x ",
2328c2ecf20Sopenharmony_ci				      buf_len));
2338c2ecf20Sopenharmony_ci			NXPRT(fprintf(stderr, "ddead %p\n", (void *)buf_addr));
2348c2ecf20Sopenharmony_ci			break;
2358c2ecf20Sopenharmony_ci		}
2368c2ecf20Sopenharmony_ci		nxu_touch_pages((void *)buf_addr, buf_len, page_sz, wr);
2378c2ecf20Sopenharmony_ci	}
2388c2ecf20Sopenharmony_ci	return ERR_NX_OK;
2398c2ecf20Sopenharmony_ci}
2408c2ecf20Sopenharmony_ci
2418c2ecf20Sopenharmony_ci/*
2428c2ecf20Sopenharmony_ci * Src and dst buffers are supplied in scatter gather lists.
2438c2ecf20Sopenharmony_ci * NX function code and other parameters supplied in cmdp.
2448c2ecf20Sopenharmony_ci */
2458c2ecf20Sopenharmony_cistatic int nx_submit_job(struct nx_dde_t *src, struct nx_dde_t *dst,
2468c2ecf20Sopenharmony_ci			 struct nx_gzip_crb_cpb_t *cmdp, void *handle)
2478c2ecf20Sopenharmony_ci{
2488c2ecf20Sopenharmony_ci	uint64_t csbaddr;
2498c2ecf20Sopenharmony_ci
2508c2ecf20Sopenharmony_ci	memset((void *)&cmdp->crb.csb, 0, sizeof(cmdp->crb.csb));
2518c2ecf20Sopenharmony_ci
2528c2ecf20Sopenharmony_ci	cmdp->crb.source_dde = *src;
2538c2ecf20Sopenharmony_ci	cmdp->crb.target_dde = *dst;
2548c2ecf20Sopenharmony_ci
2558c2ecf20Sopenharmony_ci	/* Status, output byte count in tpbc */
2568c2ecf20Sopenharmony_ci	csbaddr = ((uint64_t) &cmdp->crb.csb) & csb_address_mask;
2578c2ecf20Sopenharmony_ci	put64(cmdp->crb, csb_address, csbaddr);
2588c2ecf20Sopenharmony_ci
2598c2ecf20Sopenharmony_ci	/* NX reports input bytes in spbc; cleared */
2608c2ecf20Sopenharmony_ci	cmdp->cpb.out_spbc_comp_wrap = 0;
2618c2ecf20Sopenharmony_ci	cmdp->cpb.out_spbc_comp_with_count = 0;
2628c2ecf20Sopenharmony_ci	cmdp->cpb.out_spbc_decomp = 0;
2638c2ecf20Sopenharmony_ci
2648c2ecf20Sopenharmony_ci	/* Clear output */
2658c2ecf20Sopenharmony_ci	put32(cmdp->cpb, out_crc, INIT_CRC);
2668c2ecf20Sopenharmony_ci	put32(cmdp->cpb, out_adler, INIT_ADLER);
2678c2ecf20Sopenharmony_ci
2688c2ecf20Sopenharmony_ci	/* Submit the crb, the job descriptor, to the accelerator. */
2698c2ecf20Sopenharmony_ci	return nxu_submit_job(cmdp, handle);
2708c2ecf20Sopenharmony_ci}
2718c2ecf20Sopenharmony_ci
2728c2ecf20Sopenharmony_ciint decompress_file(int argc, char **argv, void *devhandle)
2738c2ecf20Sopenharmony_ci{
2748c2ecf20Sopenharmony_ci	FILE *inpf = NULL;
2758c2ecf20Sopenharmony_ci	FILE *outf = NULL;
2768c2ecf20Sopenharmony_ci
2778c2ecf20Sopenharmony_ci	int c, expect, i, cc, rc = 0;
2788c2ecf20Sopenharmony_ci	char gzfname[FNAME_MAX];
2798c2ecf20Sopenharmony_ci
2808c2ecf20Sopenharmony_ci	/* Queuing, file ops, byte counting */
2818c2ecf20Sopenharmony_ci	char *fifo_in, *fifo_out;
2828c2ecf20Sopenharmony_ci	int used_in, cur_in, used_out, cur_out, read_sz, n;
2838c2ecf20Sopenharmony_ci	int first_free, last_free, first_used, last_used;
2848c2ecf20Sopenharmony_ci	int first_offset, last_offset;
2858c2ecf20Sopenharmony_ci	int write_sz, free_space, source_sz;
2868c2ecf20Sopenharmony_ci	int source_sz_estimate, target_sz_estimate;
2878c2ecf20Sopenharmony_ci	uint64_t last_comp_ratio = 0; /* 1000 max */
2888c2ecf20Sopenharmony_ci	uint64_t total_out = 0;
2898c2ecf20Sopenharmony_ci	int is_final, is_eof;
2908c2ecf20Sopenharmony_ci
2918c2ecf20Sopenharmony_ci	/* nx hardware */
2928c2ecf20Sopenharmony_ci	int sfbt, subc, spbc, tpbc, nx_ce, fc, resuming = 0;
2938c2ecf20Sopenharmony_ci	int history_len = 0;
2948c2ecf20Sopenharmony_ci	struct nx_gzip_crb_cpb_t cmd, *cmdp;
2958c2ecf20Sopenharmony_ci	struct nx_dde_t *ddl_in;
2968c2ecf20Sopenharmony_ci	struct nx_dde_t dde_in[6] __aligned(128);
2978c2ecf20Sopenharmony_ci	struct nx_dde_t *ddl_out;
2988c2ecf20Sopenharmony_ci	struct nx_dde_t dde_out[6] __aligned(128);
2998c2ecf20Sopenharmony_ci	int pgfault_retries;
3008c2ecf20Sopenharmony_ci
3018c2ecf20Sopenharmony_ci	/* when using mmap'ed files */
3028c2ecf20Sopenharmony_ci	off_t input_file_offset;
3038c2ecf20Sopenharmony_ci
3048c2ecf20Sopenharmony_ci	if (argc > 2) {
3058c2ecf20Sopenharmony_ci		fprintf(stderr, "usage: %s <fname> or stdin\n", argv[0]);
3068c2ecf20Sopenharmony_ci		fprintf(stderr, "    writes to stdout or <fname>.nx.gunzip\n");
3078c2ecf20Sopenharmony_ci		return -1;
3088c2ecf20Sopenharmony_ci	}
3098c2ecf20Sopenharmony_ci
3108c2ecf20Sopenharmony_ci	if (argc == 1) {
3118c2ecf20Sopenharmony_ci		inpf = stdin;
3128c2ecf20Sopenharmony_ci		outf = stdout;
3138c2ecf20Sopenharmony_ci	} else if (argc == 2) {
3148c2ecf20Sopenharmony_ci		char w[1024];
3158c2ecf20Sopenharmony_ci		char *wp;
3168c2ecf20Sopenharmony_ci
3178c2ecf20Sopenharmony_ci		inpf = fopen(argv[1], "r");
3188c2ecf20Sopenharmony_ci		if (inpf == NULL) {
3198c2ecf20Sopenharmony_ci			perror(argv[1]);
3208c2ecf20Sopenharmony_ci			return -1;
3218c2ecf20Sopenharmony_ci		}
3228c2ecf20Sopenharmony_ci
3238c2ecf20Sopenharmony_ci		/* Make a new file name to write to.  Ignoring '.gz' */
3248c2ecf20Sopenharmony_ci		wp = (NULL != (wp = strrchr(argv[1], '/'))) ? (wp+1) : argv[1];
3258c2ecf20Sopenharmony_ci		strcpy(w, wp);
3268c2ecf20Sopenharmony_ci		strcat(w, ".nx.gunzip");
3278c2ecf20Sopenharmony_ci
3288c2ecf20Sopenharmony_ci		outf = fopen(w, "w");
3298c2ecf20Sopenharmony_ci		if (outf == NULL) {
3308c2ecf20Sopenharmony_ci			perror(w);
3318c2ecf20Sopenharmony_ci			return -1;
3328c2ecf20Sopenharmony_ci		}
3338c2ecf20Sopenharmony_ci	}
3348c2ecf20Sopenharmony_ci
3358c2ecf20Sopenharmony_ci	/* Decode the gzip header */
3368c2ecf20Sopenharmony_ci	c = GETINPC(inpf); expect = 0x1f; /* ID1 */
3378c2ecf20Sopenharmony_ci	if (c != expect)
3388c2ecf20Sopenharmony_ci		goto err1;
3398c2ecf20Sopenharmony_ci
3408c2ecf20Sopenharmony_ci	c = GETINPC(inpf); expect = 0x8b; /* ID2 */
3418c2ecf20Sopenharmony_ci	if (c != expect)
3428c2ecf20Sopenharmony_ci		goto err1;
3438c2ecf20Sopenharmony_ci
3448c2ecf20Sopenharmony_ci	c = GETINPC(inpf); expect = 0x08; /* CM */
3458c2ecf20Sopenharmony_ci	if (c != expect)
3468c2ecf20Sopenharmony_ci		goto err1;
3478c2ecf20Sopenharmony_ci
3488c2ecf20Sopenharmony_ci	int flg = GETINPC(inpf); /* FLG */
3498c2ecf20Sopenharmony_ci
3508c2ecf20Sopenharmony_ci	if (flg & 0xE0 || flg & 0x4 || flg == EOF)
3518c2ecf20Sopenharmony_ci		goto err2;
3528c2ecf20Sopenharmony_ci
3538c2ecf20Sopenharmony_ci	fprintf(stderr, "gzHeader FLG %x\n", flg);
3548c2ecf20Sopenharmony_ci
3558c2ecf20Sopenharmony_ci	/* Read 6 bytes; ignoring the MTIME, XFL, OS fields in this
3568c2ecf20Sopenharmony_ci	 * sample code.
3578c2ecf20Sopenharmony_ci	 */
3588c2ecf20Sopenharmony_ci	for (i = 0; i < 6; i++) {
3598c2ecf20Sopenharmony_ci		char tmp[10];
3608c2ecf20Sopenharmony_ci
3618c2ecf20Sopenharmony_ci		tmp[i] = GETINPC(inpf);
3628c2ecf20Sopenharmony_ci		if (tmp[i] == EOF)
3638c2ecf20Sopenharmony_ci			goto err3;
3648c2ecf20Sopenharmony_ci		fprintf(stderr, "%02x ", tmp[i]);
3658c2ecf20Sopenharmony_ci		if (i == 5)
3668c2ecf20Sopenharmony_ci			fprintf(stderr, "\n");
3678c2ecf20Sopenharmony_ci	}
3688c2ecf20Sopenharmony_ci	fprintf(stderr, "gzHeader MTIME, XFL, OS ignored\n");
3698c2ecf20Sopenharmony_ci
3708c2ecf20Sopenharmony_ci	/* FNAME */
3718c2ecf20Sopenharmony_ci	if (flg & 0x8) {
3728c2ecf20Sopenharmony_ci		int k = 0;
3738c2ecf20Sopenharmony_ci
3748c2ecf20Sopenharmony_ci		do {
3758c2ecf20Sopenharmony_ci			c = GETINPC(inpf);
3768c2ecf20Sopenharmony_ci			if (c == EOF || k >= FNAME_MAX)
3778c2ecf20Sopenharmony_ci				goto err3;
3788c2ecf20Sopenharmony_ci			gzfname[k++] = c;
3798c2ecf20Sopenharmony_ci		} while (c);
3808c2ecf20Sopenharmony_ci		fprintf(stderr, "gzHeader FNAME: %s\n", gzfname);
3818c2ecf20Sopenharmony_ci	}
3828c2ecf20Sopenharmony_ci
3838c2ecf20Sopenharmony_ci	/* FHCRC */
3848c2ecf20Sopenharmony_ci	if (flg & 0x2) {
3858c2ecf20Sopenharmony_ci		c = GETINPC(inpf);
3868c2ecf20Sopenharmony_ci		if (c == EOF)
3878c2ecf20Sopenharmony_ci			goto err3;
3888c2ecf20Sopenharmony_ci		c = GETINPC(inpf);
3898c2ecf20Sopenharmony_ci		if (c == EOF)
3908c2ecf20Sopenharmony_ci			goto err3;
3918c2ecf20Sopenharmony_ci		fprintf(stderr, "gzHeader FHCRC: ignored\n");
3928c2ecf20Sopenharmony_ci	}
3938c2ecf20Sopenharmony_ci
3948c2ecf20Sopenharmony_ci	used_in = cur_in = used_out = cur_out = 0;
3958c2ecf20Sopenharmony_ci	is_final = is_eof = 0;
3968c2ecf20Sopenharmony_ci
3978c2ecf20Sopenharmony_ci	/* Allocate one page larger to prevent page faults due to NX
3988c2ecf20Sopenharmony_ci	 * overfetching.
3998c2ecf20Sopenharmony_ci	 * Either do this (char*)(uintptr_t)aligned_alloc or use
4008c2ecf20Sopenharmony_ci	 * -std=c11 flag to make the int-to-pointer warning go away.
4018c2ecf20Sopenharmony_ci	 */
4028c2ecf20Sopenharmony_ci	assert((fifo_in  = (char *)(uintptr_t)aligned_alloc(line_sz,
4038c2ecf20Sopenharmony_ci				   fifo_in_len + page_sz)) != NULL);
4048c2ecf20Sopenharmony_ci	assert((fifo_out = (char *)(uintptr_t)aligned_alloc(line_sz,
4058c2ecf20Sopenharmony_ci				   fifo_out_len + page_sz + line_sz)) != NULL);
4068c2ecf20Sopenharmony_ci	/* Leave unused space due to history rounding rules */
4078c2ecf20Sopenharmony_ci	fifo_out = fifo_out + line_sz;
4088c2ecf20Sopenharmony_ci	nxu_touch_pages(fifo_out, fifo_out_len, page_sz, 1);
4098c2ecf20Sopenharmony_ci
4108c2ecf20Sopenharmony_ci	ddl_in  = &dde_in[0];
4118c2ecf20Sopenharmony_ci	ddl_out = &dde_out[0];
4128c2ecf20Sopenharmony_ci	cmdp = &cmd;
4138c2ecf20Sopenharmony_ci	memset(&cmdp->crb, 0, sizeof(cmdp->crb));
4148c2ecf20Sopenharmony_ci
4158c2ecf20Sopenharmony_ciread_state:
4168c2ecf20Sopenharmony_ci
4178c2ecf20Sopenharmony_ci	/* Read from .gz file */
4188c2ecf20Sopenharmony_ci
4198c2ecf20Sopenharmony_ci	NXPRT(fprintf(stderr, "read_state:\n"));
4208c2ecf20Sopenharmony_ci
4218c2ecf20Sopenharmony_ci	if (is_eof != 0)
4228c2ecf20Sopenharmony_ci		goto write_state;
4238c2ecf20Sopenharmony_ci
4248c2ecf20Sopenharmony_ci	/* We read in to fifo_in in two steps: first: read in to from
4258c2ecf20Sopenharmony_ci	 * cur_in to the end of the buffer.  last: if free space wrapped
4268c2ecf20Sopenharmony_ci	 * around, read from fifo_in offset 0 to offset cur_in.
4278c2ecf20Sopenharmony_ci	 */
4288c2ecf20Sopenharmony_ci
4298c2ecf20Sopenharmony_ci	/* Reset fifo head to reduce unnecessary wrap arounds */
4308c2ecf20Sopenharmony_ci	cur_in = (used_in == 0) ? 0 : cur_in;
4318c2ecf20Sopenharmony_ci
4328c2ecf20Sopenharmony_ci	/* Free space total is reduced by a gap */
4338c2ecf20Sopenharmony_ci	free_space = NX_MAX(0, fifo_free_bytes(used_in, fifo_in_len)
4348c2ecf20Sopenharmony_ci			    - line_sz);
4358c2ecf20Sopenharmony_ci
4368c2ecf20Sopenharmony_ci	/* Free space may wrap around as first and last */
4378c2ecf20Sopenharmony_ci	first_free = fifo_free_first_bytes(cur_in, used_in, fifo_in_len);
4388c2ecf20Sopenharmony_ci	last_free  = fifo_free_last_bytes(cur_in, used_in, fifo_in_len);
4398c2ecf20Sopenharmony_ci
4408c2ecf20Sopenharmony_ci	/* Start offsets of the free memory */
4418c2ecf20Sopenharmony_ci	first_offset = fifo_free_first_offset(cur_in, used_in);
4428c2ecf20Sopenharmony_ci	last_offset  = fifo_free_last_offset(cur_in, used_in, fifo_in_len);
4438c2ecf20Sopenharmony_ci
4448c2ecf20Sopenharmony_ci	/* Reduce read_sz because of the line_sz gap */
4458c2ecf20Sopenharmony_ci	read_sz = NX_MIN(free_space, first_free);
4468c2ecf20Sopenharmony_ci	n = 0;
4478c2ecf20Sopenharmony_ci	if (read_sz > 0) {
4488c2ecf20Sopenharmony_ci		/* Read in to offset cur_in + used_in */
4498c2ecf20Sopenharmony_ci		n = fread(fifo_in + first_offset, 1, read_sz, inpf);
4508c2ecf20Sopenharmony_ci		used_in = used_in + n;
4518c2ecf20Sopenharmony_ci		free_space = free_space - n;
4528c2ecf20Sopenharmony_ci		assert(n <= read_sz);
4538c2ecf20Sopenharmony_ci		if (n != read_sz) {
4548c2ecf20Sopenharmony_ci			/* Either EOF or error; exit the read loop */
4558c2ecf20Sopenharmony_ci			is_eof = 1;
4568c2ecf20Sopenharmony_ci			goto write_state;
4578c2ecf20Sopenharmony_ci		}
4588c2ecf20Sopenharmony_ci	}
4598c2ecf20Sopenharmony_ci
4608c2ecf20Sopenharmony_ci	/* If free space wrapped around */
4618c2ecf20Sopenharmony_ci	if (last_free > 0) {
4628c2ecf20Sopenharmony_ci		/* Reduce read_sz because of the line_sz gap */
4638c2ecf20Sopenharmony_ci		read_sz = NX_MIN(free_space, last_free);
4648c2ecf20Sopenharmony_ci		n = 0;
4658c2ecf20Sopenharmony_ci		if (read_sz > 0) {
4668c2ecf20Sopenharmony_ci			n = fread(fifo_in + last_offset, 1, read_sz, inpf);
4678c2ecf20Sopenharmony_ci			used_in = used_in + n;       /* Increase used space */
4688c2ecf20Sopenharmony_ci			free_space = free_space - n; /* Decrease free space */
4698c2ecf20Sopenharmony_ci			assert(n <= read_sz);
4708c2ecf20Sopenharmony_ci			if (n != read_sz) {
4718c2ecf20Sopenharmony_ci				/* Either EOF or error; exit the read loop */
4728c2ecf20Sopenharmony_ci				is_eof = 1;
4738c2ecf20Sopenharmony_ci				goto write_state;
4748c2ecf20Sopenharmony_ci			}
4758c2ecf20Sopenharmony_ci		}
4768c2ecf20Sopenharmony_ci	}
4778c2ecf20Sopenharmony_ci
4788c2ecf20Sopenharmony_ci	/* At this point we have used_in bytes in fifo_in with the
4798c2ecf20Sopenharmony_ci	 * data head starting at cur_in and possibly wrapping around.
4808c2ecf20Sopenharmony_ci	 */
4818c2ecf20Sopenharmony_ci
4828c2ecf20Sopenharmony_ciwrite_state:
4838c2ecf20Sopenharmony_ci
4848c2ecf20Sopenharmony_ci	/* Write decompressed data to output file */
4858c2ecf20Sopenharmony_ci
4868c2ecf20Sopenharmony_ci	NXPRT(fprintf(stderr, "write_state:\n"));
4878c2ecf20Sopenharmony_ci
4888c2ecf20Sopenharmony_ci	if (used_out == 0)
4898c2ecf20Sopenharmony_ci		goto decomp_state;
4908c2ecf20Sopenharmony_ci
4918c2ecf20Sopenharmony_ci	/* If fifo_out has data waiting, write it out to the file to
4928c2ecf20Sopenharmony_ci	 * make free target space for the accelerator used bytes in
4938c2ecf20Sopenharmony_ci	 * the first and last parts of fifo_out.
4948c2ecf20Sopenharmony_ci	 */
4958c2ecf20Sopenharmony_ci
4968c2ecf20Sopenharmony_ci	first_used = fifo_used_first_bytes(cur_out, used_out, fifo_out_len);
4978c2ecf20Sopenharmony_ci	last_used  = fifo_used_last_bytes(cur_out, used_out, fifo_out_len);
4988c2ecf20Sopenharmony_ci
4998c2ecf20Sopenharmony_ci	write_sz = first_used;
5008c2ecf20Sopenharmony_ci
5018c2ecf20Sopenharmony_ci	n = 0;
5028c2ecf20Sopenharmony_ci	if (write_sz > 0) {
5038c2ecf20Sopenharmony_ci		n = fwrite(fifo_out + cur_out, 1, write_sz, outf);
5048c2ecf20Sopenharmony_ci		used_out = used_out - n;
5058c2ecf20Sopenharmony_ci		/* Move head of the fifo */
5068c2ecf20Sopenharmony_ci		cur_out = (cur_out + n) % fifo_out_len;
5078c2ecf20Sopenharmony_ci		assert(n <= write_sz);
5088c2ecf20Sopenharmony_ci		if (n != write_sz) {
5098c2ecf20Sopenharmony_ci			fprintf(stderr, "error: write\n");
5108c2ecf20Sopenharmony_ci			rc = -1;
5118c2ecf20Sopenharmony_ci			goto err5;
5128c2ecf20Sopenharmony_ci		}
5138c2ecf20Sopenharmony_ci	}
5148c2ecf20Sopenharmony_ci
5158c2ecf20Sopenharmony_ci	if (last_used > 0) { /* If more data available in the last part */
5168c2ecf20Sopenharmony_ci		write_sz = last_used; /* Keep it here for later */
5178c2ecf20Sopenharmony_ci		n = 0;
5188c2ecf20Sopenharmony_ci		if (write_sz > 0) {
5198c2ecf20Sopenharmony_ci			n = fwrite(fifo_out, 1, write_sz, outf);
5208c2ecf20Sopenharmony_ci			used_out = used_out - n;
5218c2ecf20Sopenharmony_ci			cur_out = (cur_out + n) % fifo_out_len;
5228c2ecf20Sopenharmony_ci			assert(n <= write_sz);
5238c2ecf20Sopenharmony_ci			if (n != write_sz) {
5248c2ecf20Sopenharmony_ci				fprintf(stderr, "error: write\n");
5258c2ecf20Sopenharmony_ci				rc = -1;
5268c2ecf20Sopenharmony_ci				goto err5;
5278c2ecf20Sopenharmony_ci			}
5288c2ecf20Sopenharmony_ci		}
5298c2ecf20Sopenharmony_ci	}
5308c2ecf20Sopenharmony_ci
5318c2ecf20Sopenharmony_cidecomp_state:
5328c2ecf20Sopenharmony_ci
5338c2ecf20Sopenharmony_ci	/* NX decompresses input data */
5348c2ecf20Sopenharmony_ci
5358c2ecf20Sopenharmony_ci	NXPRT(fprintf(stderr, "decomp_state:\n"));
5368c2ecf20Sopenharmony_ci
5378c2ecf20Sopenharmony_ci	if (is_final)
5388c2ecf20Sopenharmony_ci		goto finish_state;
5398c2ecf20Sopenharmony_ci
5408c2ecf20Sopenharmony_ci	/* Address/len lists */
5418c2ecf20Sopenharmony_ci	clearp_dde(ddl_in);
5428c2ecf20Sopenharmony_ci	clearp_dde(ddl_out);
5438c2ecf20Sopenharmony_ci
5448c2ecf20Sopenharmony_ci	/* FC, CRC, HistLen, Table 6-6 */
5458c2ecf20Sopenharmony_ci	if (resuming) {
5468c2ecf20Sopenharmony_ci		/* Resuming a partially decompressed input.
5478c2ecf20Sopenharmony_ci		 * The key to resume is supplying the 32KB
5488c2ecf20Sopenharmony_ci		 * dictionary (history) to NX, which is basically
5498c2ecf20Sopenharmony_ci		 * the last 32KB of output produced.
5508c2ecf20Sopenharmony_ci		 */
5518c2ecf20Sopenharmony_ci		fc = GZIP_FC_DECOMPRESS_RESUME;
5528c2ecf20Sopenharmony_ci
5538c2ecf20Sopenharmony_ci		cmdp->cpb.in_crc   = cmdp->cpb.out_crc;
5548c2ecf20Sopenharmony_ci		cmdp->cpb.in_adler = cmdp->cpb.out_adler;
5558c2ecf20Sopenharmony_ci
5568c2ecf20Sopenharmony_ci		/* Round up the history size to quadword.  Section 2.10 */
5578c2ecf20Sopenharmony_ci		history_len = (history_len + 15) / 16;
5588c2ecf20Sopenharmony_ci		putnn(cmdp->cpb, in_histlen, history_len);
5598c2ecf20Sopenharmony_ci		history_len = history_len * 16; /* bytes */
5608c2ecf20Sopenharmony_ci
5618c2ecf20Sopenharmony_ci		if (history_len > 0) {
5628c2ecf20Sopenharmony_ci			/* Chain in the history buffer to the DDE list */
5638c2ecf20Sopenharmony_ci			if (cur_out >= history_len) {
5648c2ecf20Sopenharmony_ci				nx_append_dde(ddl_in, fifo_out
5658c2ecf20Sopenharmony_ci					      + (cur_out - history_len),
5668c2ecf20Sopenharmony_ci					      history_len);
5678c2ecf20Sopenharmony_ci			} else {
5688c2ecf20Sopenharmony_ci				nx_append_dde(ddl_in, fifo_out
5698c2ecf20Sopenharmony_ci					      + ((fifo_out_len + cur_out)
5708c2ecf20Sopenharmony_ci					      - history_len),
5718c2ecf20Sopenharmony_ci					      history_len - cur_out);
5728c2ecf20Sopenharmony_ci				/* Up to 32KB history wraps around fifo_out */
5738c2ecf20Sopenharmony_ci				nx_append_dde(ddl_in, fifo_out, cur_out);
5748c2ecf20Sopenharmony_ci			}
5758c2ecf20Sopenharmony_ci
5768c2ecf20Sopenharmony_ci		}
5778c2ecf20Sopenharmony_ci	} else {
5788c2ecf20Sopenharmony_ci		/* First decompress job */
5798c2ecf20Sopenharmony_ci		fc = GZIP_FC_DECOMPRESS;
5808c2ecf20Sopenharmony_ci
5818c2ecf20Sopenharmony_ci		history_len = 0;
5828c2ecf20Sopenharmony_ci		/* Writing 0 clears out subc as well */
5838c2ecf20Sopenharmony_ci		cmdp->cpb.in_histlen = 0;
5848c2ecf20Sopenharmony_ci		total_out = 0;
5858c2ecf20Sopenharmony_ci
5868c2ecf20Sopenharmony_ci		put32(cmdp->cpb, in_crc, INIT_CRC);
5878c2ecf20Sopenharmony_ci		put32(cmdp->cpb, in_adler, INIT_ADLER);
5888c2ecf20Sopenharmony_ci		put32(cmdp->cpb, out_crc, INIT_CRC);
5898c2ecf20Sopenharmony_ci		put32(cmdp->cpb, out_adler, INIT_ADLER);
5908c2ecf20Sopenharmony_ci
5918c2ecf20Sopenharmony_ci		/* Assuming 10% compression ratio initially; use the
5928c2ecf20Sopenharmony_ci		 * most recently measured compression ratio as a
5938c2ecf20Sopenharmony_ci		 * heuristic to estimate the input and output
5948c2ecf20Sopenharmony_ci		 * sizes.  If we give too much input, the target buffer
5958c2ecf20Sopenharmony_ci		 * overflows and NX cycles are wasted, and then we
5968c2ecf20Sopenharmony_ci		 * must retry with smaller input size.  1000 is 100%.
5978c2ecf20Sopenharmony_ci		 */
5988c2ecf20Sopenharmony_ci		last_comp_ratio = 100UL;
5998c2ecf20Sopenharmony_ci	}
6008c2ecf20Sopenharmony_ci	cmdp->crb.gzip_fc = 0;
6018c2ecf20Sopenharmony_ci	putnn(cmdp->crb, gzip_fc, fc);
6028c2ecf20Sopenharmony_ci
6038c2ecf20Sopenharmony_ci	/*
6048c2ecf20Sopenharmony_ci	 * NX source buffers
6058c2ecf20Sopenharmony_ci	 */
6068c2ecf20Sopenharmony_ci	first_used = fifo_used_first_bytes(cur_in, used_in, fifo_in_len);
6078c2ecf20Sopenharmony_ci	last_used = fifo_used_last_bytes(cur_in, used_in, fifo_in_len);
6088c2ecf20Sopenharmony_ci
6098c2ecf20Sopenharmony_ci	if (first_used > 0)
6108c2ecf20Sopenharmony_ci		nx_append_dde(ddl_in, fifo_in + cur_in, first_used);
6118c2ecf20Sopenharmony_ci
6128c2ecf20Sopenharmony_ci	if (last_used > 0)
6138c2ecf20Sopenharmony_ci		nx_append_dde(ddl_in, fifo_in, last_used);
6148c2ecf20Sopenharmony_ci
6158c2ecf20Sopenharmony_ci	/*
6168c2ecf20Sopenharmony_ci	 * NX target buffers
6178c2ecf20Sopenharmony_ci	 */
6188c2ecf20Sopenharmony_ci	first_free = fifo_free_first_bytes(cur_out, used_out, fifo_out_len);
6198c2ecf20Sopenharmony_ci	last_free = fifo_free_last_bytes(cur_out, used_out, fifo_out_len);
6208c2ecf20Sopenharmony_ci
6218c2ecf20Sopenharmony_ci	/* Reduce output free space amount not to overwrite the history */
6228c2ecf20Sopenharmony_ci	int target_max = NX_MAX(0, fifo_free_bytes(used_out, fifo_out_len)
6238c2ecf20Sopenharmony_ci				- (1<<16));
6248c2ecf20Sopenharmony_ci
6258c2ecf20Sopenharmony_ci	NXPRT(fprintf(stderr, "target_max %d (0x%x)\n", target_max,
6268c2ecf20Sopenharmony_ci		      target_max));
6278c2ecf20Sopenharmony_ci
6288c2ecf20Sopenharmony_ci	first_free = NX_MIN(target_max, first_free);
6298c2ecf20Sopenharmony_ci	if (first_free > 0) {
6308c2ecf20Sopenharmony_ci		first_offset = fifo_free_first_offset(cur_out, used_out);
6318c2ecf20Sopenharmony_ci		nx_append_dde(ddl_out, fifo_out + first_offset, first_free);
6328c2ecf20Sopenharmony_ci	}
6338c2ecf20Sopenharmony_ci
6348c2ecf20Sopenharmony_ci	if (last_free > 0) {
6358c2ecf20Sopenharmony_ci		last_free = NX_MIN(target_max - first_free, last_free);
6368c2ecf20Sopenharmony_ci		if (last_free > 0) {
6378c2ecf20Sopenharmony_ci			last_offset = fifo_free_last_offset(cur_out, used_out,
6388c2ecf20Sopenharmony_ci							    fifo_out_len);
6398c2ecf20Sopenharmony_ci			nx_append_dde(ddl_out, fifo_out + last_offset,
6408c2ecf20Sopenharmony_ci				      last_free);
6418c2ecf20Sopenharmony_ci		}
6428c2ecf20Sopenharmony_ci	}
6438c2ecf20Sopenharmony_ci
6448c2ecf20Sopenharmony_ci	/* Target buffer size is used to limit the source data size
6458c2ecf20Sopenharmony_ci	 * based on previous measurements of compression ratio.
6468c2ecf20Sopenharmony_ci	 */
6478c2ecf20Sopenharmony_ci
6488c2ecf20Sopenharmony_ci	/* source_sz includes history */
6498c2ecf20Sopenharmony_ci	source_sz = getp32(ddl_in, ddebc);
6508c2ecf20Sopenharmony_ci	assert(source_sz > history_len);
6518c2ecf20Sopenharmony_ci	source_sz = source_sz - history_len;
6528c2ecf20Sopenharmony_ci
6538c2ecf20Sopenharmony_ci	/* Estimating how much source is needed to 3/4 fill a
6548c2ecf20Sopenharmony_ci	 * target_max size target buffer.  If we overshoot, then NX
6558c2ecf20Sopenharmony_ci	 * must repeat the job with smaller input and we waste
6568c2ecf20Sopenharmony_ci	 * bandwidth.  If we undershoot then we use more NX calls than
6578c2ecf20Sopenharmony_ci	 * necessary.
6588c2ecf20Sopenharmony_ci	 */
6598c2ecf20Sopenharmony_ci
6608c2ecf20Sopenharmony_ci	source_sz_estimate = ((uint64_t)target_max * last_comp_ratio * 3UL)
6618c2ecf20Sopenharmony_ci				/ 4000;
6628c2ecf20Sopenharmony_ci
6638c2ecf20Sopenharmony_ci	if (source_sz_estimate < source_sz) {
6648c2ecf20Sopenharmony_ci		/* Target might be small, therefore limiting the
6658c2ecf20Sopenharmony_ci		 * source data.
6668c2ecf20Sopenharmony_ci		 */
6678c2ecf20Sopenharmony_ci		source_sz = source_sz_estimate;
6688c2ecf20Sopenharmony_ci		target_sz_estimate = target_max;
6698c2ecf20Sopenharmony_ci	} else {
6708c2ecf20Sopenharmony_ci		/* Source file might be small, therefore limiting target
6718c2ecf20Sopenharmony_ci		 * touch pages to a smaller value to save processor cycles.
6728c2ecf20Sopenharmony_ci		 */
6738c2ecf20Sopenharmony_ci		target_sz_estimate = ((uint64_t)source_sz * 1000UL)
6748c2ecf20Sopenharmony_ci					/ (last_comp_ratio + 1);
6758c2ecf20Sopenharmony_ci		target_sz_estimate = NX_MIN(2 * target_sz_estimate,
6768c2ecf20Sopenharmony_ci					    target_max);
6778c2ecf20Sopenharmony_ci	}
6788c2ecf20Sopenharmony_ci
6798c2ecf20Sopenharmony_ci	source_sz = source_sz + history_len;
6808c2ecf20Sopenharmony_ci
6818c2ecf20Sopenharmony_ci	/* Some NX condition codes require submitting the NX job again.
6828c2ecf20Sopenharmony_ci	 * Kernel doesn't handle NX page faults. Expects user code to
6838c2ecf20Sopenharmony_ci	 * touch pages.
6848c2ecf20Sopenharmony_ci	 */
6858c2ecf20Sopenharmony_ci	pgfault_retries = NX_MAX_FAULTS;
6868c2ecf20Sopenharmony_ci
6878c2ecf20Sopenharmony_cirestart_nx:
6888c2ecf20Sopenharmony_ci
6898c2ecf20Sopenharmony_ci	putp32(ddl_in, ddebc, source_sz);
6908c2ecf20Sopenharmony_ci
6918c2ecf20Sopenharmony_ci	/* Fault in pages */
6928c2ecf20Sopenharmony_ci	nxu_touch_pages(cmdp, sizeof(struct nx_gzip_crb_cpb_t), page_sz, 1);
6938c2ecf20Sopenharmony_ci	nx_touch_pages_dde(ddl_in, 0, page_sz, 0);
6948c2ecf20Sopenharmony_ci	nx_touch_pages_dde(ddl_out, target_sz_estimate, page_sz, 1);
6958c2ecf20Sopenharmony_ci
6968c2ecf20Sopenharmony_ci	/* Send job to NX */
6978c2ecf20Sopenharmony_ci	cc = nx_submit_job(ddl_in, ddl_out, cmdp, devhandle);
6988c2ecf20Sopenharmony_ci
6998c2ecf20Sopenharmony_ci	switch (cc) {
7008c2ecf20Sopenharmony_ci
7018c2ecf20Sopenharmony_ci	case ERR_NX_AT_FAULT:
7028c2ecf20Sopenharmony_ci
7038c2ecf20Sopenharmony_ci		/* We touched the pages ahead of time.  In the most common case
7048c2ecf20Sopenharmony_ci		 * we shouldn't be here.  But may be some pages were paged out.
7058c2ecf20Sopenharmony_ci		 * Kernel should have placed the faulting address to fsaddr.
7068c2ecf20Sopenharmony_ci		 */
7078c2ecf20Sopenharmony_ci		NXPRT(fprintf(stderr, "ERR_NX_AT_FAULT %p\n",
7088c2ecf20Sopenharmony_ci			      (void *)cmdp->crb.csb.fsaddr));
7098c2ecf20Sopenharmony_ci
7108c2ecf20Sopenharmony_ci		if (pgfault_retries == NX_MAX_FAULTS) {
7118c2ecf20Sopenharmony_ci			/* Try once with exact number of pages */
7128c2ecf20Sopenharmony_ci			--pgfault_retries;
7138c2ecf20Sopenharmony_ci			goto restart_nx;
7148c2ecf20Sopenharmony_ci		} else if (pgfault_retries > 0) {
7158c2ecf20Sopenharmony_ci			/* If still faulting try fewer input pages
7168c2ecf20Sopenharmony_ci			 * assuming memory outage
7178c2ecf20Sopenharmony_ci			 */
7188c2ecf20Sopenharmony_ci			if (source_sz > page_sz)
7198c2ecf20Sopenharmony_ci				source_sz = NX_MAX(source_sz / 2, page_sz);
7208c2ecf20Sopenharmony_ci			--pgfault_retries;
7218c2ecf20Sopenharmony_ci			goto restart_nx;
7228c2ecf20Sopenharmony_ci		} else {
7238c2ecf20Sopenharmony_ci			fprintf(stderr, "cannot make progress; too many ");
7248c2ecf20Sopenharmony_ci			fprintf(stderr, "page fault retries cc= %d\n", cc);
7258c2ecf20Sopenharmony_ci			rc = -1;
7268c2ecf20Sopenharmony_ci			goto err5;
7278c2ecf20Sopenharmony_ci		}
7288c2ecf20Sopenharmony_ci
7298c2ecf20Sopenharmony_ci	case ERR_NX_DATA_LENGTH:
7308c2ecf20Sopenharmony_ci
7318c2ecf20Sopenharmony_ci		NXPRT(fprintf(stderr, "ERR_NX_DATA_LENGTH; "));
7328c2ecf20Sopenharmony_ci		NXPRT(fprintf(stderr, "stream may have trailing data\n"));
7338c2ecf20Sopenharmony_ci
7348c2ecf20Sopenharmony_ci		/* Not an error in the most common case; it just says
7358c2ecf20Sopenharmony_ci		 * there is trailing data that we must examine.
7368c2ecf20Sopenharmony_ci		 *
7378c2ecf20Sopenharmony_ci		 * CC=3 CE(1)=0 CE(0)=1 indicates partial completion
7388c2ecf20Sopenharmony_ci		 * Fig.6-7 and Table 6-8.
7398c2ecf20Sopenharmony_ci		 */
7408c2ecf20Sopenharmony_ci		nx_ce = get_csb_ce_ms3b(cmdp->crb.csb);
7418c2ecf20Sopenharmony_ci
7428c2ecf20Sopenharmony_ci		if (!csb_ce_termination(nx_ce) &&
7438c2ecf20Sopenharmony_ci		    csb_ce_partial_completion(nx_ce)) {
7448c2ecf20Sopenharmony_ci			/* Check CPB for more information
7458c2ecf20Sopenharmony_ci			 * spbc and tpbc are valid
7468c2ecf20Sopenharmony_ci			 */
7478c2ecf20Sopenharmony_ci			sfbt = getnn(cmdp->cpb, out_sfbt); /* Table 6-4 */
7488c2ecf20Sopenharmony_ci			subc = getnn(cmdp->cpb, out_subc); /* Table 6-4 */
7498c2ecf20Sopenharmony_ci			spbc = get32(cmdp->cpb, out_spbc_decomp);
7508c2ecf20Sopenharmony_ci			tpbc = get32(cmdp->crb.csb, tpbc);
7518c2ecf20Sopenharmony_ci			assert(target_max >= tpbc);
7528c2ecf20Sopenharmony_ci
7538c2ecf20Sopenharmony_ci			goto ok_cc3; /* not an error */
7548c2ecf20Sopenharmony_ci		} else {
7558c2ecf20Sopenharmony_ci			/* History length error when CE(1)=1 CE(0)=0. */
7568c2ecf20Sopenharmony_ci			rc = -1;
7578c2ecf20Sopenharmony_ci			fprintf(stderr, "history length error cc= %d\n", cc);
7588c2ecf20Sopenharmony_ci			goto err5;
7598c2ecf20Sopenharmony_ci		}
7608c2ecf20Sopenharmony_ci
7618c2ecf20Sopenharmony_ci	case ERR_NX_TARGET_SPACE:
7628c2ecf20Sopenharmony_ci
7638c2ecf20Sopenharmony_ci		/* Target buffer not large enough; retry smaller input
7648c2ecf20Sopenharmony_ci		 * data; give at least 1 byte.  SPBC/TPBC are not valid.
7658c2ecf20Sopenharmony_ci		 */
7668c2ecf20Sopenharmony_ci		assert(source_sz > history_len);
7678c2ecf20Sopenharmony_ci		source_sz = ((source_sz - history_len + 2) / 2) + history_len;
7688c2ecf20Sopenharmony_ci		NXPRT(fprintf(stderr, "ERR_NX_TARGET_SPACE; retry with "));
7698c2ecf20Sopenharmony_ci		NXPRT(fprintf(stderr, "smaller input data src %d hist %d\n",
7708c2ecf20Sopenharmony_ci			      source_sz, history_len));
7718c2ecf20Sopenharmony_ci		goto restart_nx;
7728c2ecf20Sopenharmony_ci
7738c2ecf20Sopenharmony_ci	case ERR_NX_OK:
7748c2ecf20Sopenharmony_ci
7758c2ecf20Sopenharmony_ci		/* This should not happen for gzip formatted data;
7768c2ecf20Sopenharmony_ci		 * we need trailing crc and isize
7778c2ecf20Sopenharmony_ci		 */
7788c2ecf20Sopenharmony_ci		fprintf(stderr, "ERR_NX_OK\n");
7798c2ecf20Sopenharmony_ci		spbc = get32(cmdp->cpb, out_spbc_decomp);
7808c2ecf20Sopenharmony_ci		tpbc = get32(cmdp->crb.csb, tpbc);
7818c2ecf20Sopenharmony_ci		assert(target_max >= tpbc);
7828c2ecf20Sopenharmony_ci		assert(spbc >= history_len);
7838c2ecf20Sopenharmony_ci		source_sz = spbc - history_len;
7848c2ecf20Sopenharmony_ci		goto offsets_state;
7858c2ecf20Sopenharmony_ci
7868c2ecf20Sopenharmony_ci	default:
7878c2ecf20Sopenharmony_ci		fprintf(stderr, "error: cc= %d\n", cc);
7888c2ecf20Sopenharmony_ci		rc = -1;
7898c2ecf20Sopenharmony_ci		goto err5;
7908c2ecf20Sopenharmony_ci	}
7918c2ecf20Sopenharmony_ci
7928c2ecf20Sopenharmony_ciok_cc3:
7938c2ecf20Sopenharmony_ci
7948c2ecf20Sopenharmony_ci	NXPRT(fprintf(stderr, "cc3: sfbt: %x\n", sfbt));
7958c2ecf20Sopenharmony_ci
7968c2ecf20Sopenharmony_ci	assert(spbc > history_len);
7978c2ecf20Sopenharmony_ci	source_sz = spbc - history_len;
7988c2ecf20Sopenharmony_ci
7998c2ecf20Sopenharmony_ci	/* Table 6-4: Source Final Block Type (SFBT) describes the
8008c2ecf20Sopenharmony_ci	 * last processed deflate block and clues the software how to
8018c2ecf20Sopenharmony_ci	 * resume the next job.  SUBC indicates how many input bits NX
8028c2ecf20Sopenharmony_ci	 * consumed but did not process.  SPBC indicates how many
8038c2ecf20Sopenharmony_ci	 * bytes of source were given to the accelerator including
8048c2ecf20Sopenharmony_ci	 * history bytes.
8058c2ecf20Sopenharmony_ci	 */
8068c2ecf20Sopenharmony_ci
8078c2ecf20Sopenharmony_ci	switch (sfbt) {
8088c2ecf20Sopenharmony_ci		int dhtlen;
8098c2ecf20Sopenharmony_ci
8108c2ecf20Sopenharmony_ci	case 0x0: /* Deflate final EOB received */
8118c2ecf20Sopenharmony_ci
8128c2ecf20Sopenharmony_ci		/* Calculating the checksum start position. */
8138c2ecf20Sopenharmony_ci
8148c2ecf20Sopenharmony_ci		source_sz = source_sz - subc / 8;
8158c2ecf20Sopenharmony_ci		is_final = 1;
8168c2ecf20Sopenharmony_ci		break;
8178c2ecf20Sopenharmony_ci
8188c2ecf20Sopenharmony_ci		/* Resume decompression cases are below. Basically
8198c2ecf20Sopenharmony_ci		 * indicates where NX has suspended and how to resume
8208c2ecf20Sopenharmony_ci		 * the input stream.
8218c2ecf20Sopenharmony_ci		 */
8228c2ecf20Sopenharmony_ci
8238c2ecf20Sopenharmony_ci	case 0x8: /* Within a literal block; use rembytecount */
8248c2ecf20Sopenharmony_ci	case 0x9: /* Within a literal block; use rembytecount; bfinal=1 */
8258c2ecf20Sopenharmony_ci
8268c2ecf20Sopenharmony_ci		/* Supply the partially processed source byte again */
8278c2ecf20Sopenharmony_ci		source_sz = source_sz - ((subc + 7) / 8);
8288c2ecf20Sopenharmony_ci
8298c2ecf20Sopenharmony_ci		/* SUBC LS 3bits: number of bits in the first source byte need
8308c2ecf20Sopenharmony_ci		 * to be processed.
8318c2ecf20Sopenharmony_ci		 * 000 means all 8 bits;  Table 6-3
8328c2ecf20Sopenharmony_ci		 * Clear subc, histlen, sfbt, rembytecnt, dhtlen
8338c2ecf20Sopenharmony_ci		 */
8348c2ecf20Sopenharmony_ci		cmdp->cpb.in_subc = 0;
8358c2ecf20Sopenharmony_ci		cmdp->cpb.in_sfbt = 0;
8368c2ecf20Sopenharmony_ci		putnn(cmdp->cpb, in_subc, subc % 8);
8378c2ecf20Sopenharmony_ci		putnn(cmdp->cpb, in_sfbt, sfbt);
8388c2ecf20Sopenharmony_ci		putnn(cmdp->cpb, in_rembytecnt, getnn(cmdp->cpb,
8398c2ecf20Sopenharmony_ci						      out_rembytecnt));
8408c2ecf20Sopenharmony_ci		break;
8418c2ecf20Sopenharmony_ci
8428c2ecf20Sopenharmony_ci	case 0xA: /* Within a FH block; */
8438c2ecf20Sopenharmony_ci	case 0xB: /* Within a FH block; bfinal=1 */
8448c2ecf20Sopenharmony_ci
8458c2ecf20Sopenharmony_ci		source_sz = source_sz - ((subc + 7) / 8);
8468c2ecf20Sopenharmony_ci
8478c2ecf20Sopenharmony_ci		/* Clear subc, histlen, sfbt, rembytecnt, dhtlen */
8488c2ecf20Sopenharmony_ci		cmdp->cpb.in_subc = 0;
8498c2ecf20Sopenharmony_ci		cmdp->cpb.in_sfbt = 0;
8508c2ecf20Sopenharmony_ci		putnn(cmdp->cpb, in_subc, subc % 8);
8518c2ecf20Sopenharmony_ci		putnn(cmdp->cpb, in_sfbt, sfbt);
8528c2ecf20Sopenharmony_ci		break;
8538c2ecf20Sopenharmony_ci
8548c2ecf20Sopenharmony_ci	case 0xC: /* Within a DH block; */
8558c2ecf20Sopenharmony_ci	case 0xD: /* Within a DH block; bfinal=1 */
8568c2ecf20Sopenharmony_ci
8578c2ecf20Sopenharmony_ci		source_sz = source_sz - ((subc + 7) / 8);
8588c2ecf20Sopenharmony_ci
8598c2ecf20Sopenharmony_ci		/* Clear subc, histlen, sfbt, rembytecnt, dhtlen */
8608c2ecf20Sopenharmony_ci		cmdp->cpb.in_subc = 0;
8618c2ecf20Sopenharmony_ci		cmdp->cpb.in_sfbt = 0;
8628c2ecf20Sopenharmony_ci		putnn(cmdp->cpb, in_subc, subc % 8);
8638c2ecf20Sopenharmony_ci		putnn(cmdp->cpb, in_sfbt, sfbt);
8648c2ecf20Sopenharmony_ci
8658c2ecf20Sopenharmony_ci		dhtlen = getnn(cmdp->cpb, out_dhtlen);
8668c2ecf20Sopenharmony_ci		putnn(cmdp->cpb, in_dhtlen, dhtlen);
8678c2ecf20Sopenharmony_ci		assert(dhtlen >= 42);
8688c2ecf20Sopenharmony_ci
8698c2ecf20Sopenharmony_ci		/* Round up to a qword */
8708c2ecf20Sopenharmony_ci		dhtlen = (dhtlen + 127) / 128;
8718c2ecf20Sopenharmony_ci
8728c2ecf20Sopenharmony_ci		while (dhtlen > 0) { /* Copy dht from cpb.out to cpb.in */
8738c2ecf20Sopenharmony_ci			--dhtlen;
8748c2ecf20Sopenharmony_ci			cmdp->cpb.in_dht[dhtlen] = cmdp->cpb.out_dht[dhtlen];
8758c2ecf20Sopenharmony_ci		}
8768c2ecf20Sopenharmony_ci		break;
8778c2ecf20Sopenharmony_ci
8788c2ecf20Sopenharmony_ci	case 0xE: /* Within a block header; bfinal=0; */
8798c2ecf20Sopenharmony_ci		     /* Also given if source data exactly ends (SUBC=0) with
8808c2ecf20Sopenharmony_ci		      * EOB code with BFINAL=0.  Means the next byte will
8818c2ecf20Sopenharmony_ci		      * contain a block header.
8828c2ecf20Sopenharmony_ci		      */
8838c2ecf20Sopenharmony_ci	case 0xF: /* within a block header with BFINAL=1. */
8848c2ecf20Sopenharmony_ci
8858c2ecf20Sopenharmony_ci		source_sz = source_sz - ((subc + 7) / 8);
8868c2ecf20Sopenharmony_ci
8878c2ecf20Sopenharmony_ci		/* Clear subc, histlen, sfbt, rembytecnt, dhtlen */
8888c2ecf20Sopenharmony_ci		cmdp->cpb.in_subc = 0;
8898c2ecf20Sopenharmony_ci		cmdp->cpb.in_sfbt = 0;
8908c2ecf20Sopenharmony_ci		putnn(cmdp->cpb, in_subc, subc % 8);
8918c2ecf20Sopenharmony_ci		putnn(cmdp->cpb, in_sfbt, sfbt);
8928c2ecf20Sopenharmony_ci
8938c2ecf20Sopenharmony_ci		/* Engine did not process any data */
8948c2ecf20Sopenharmony_ci		if (is_eof && (source_sz == 0))
8958c2ecf20Sopenharmony_ci			is_final = 1;
8968c2ecf20Sopenharmony_ci	}
8978c2ecf20Sopenharmony_ci
8988c2ecf20Sopenharmony_cioffsets_state:
8998c2ecf20Sopenharmony_ci
9008c2ecf20Sopenharmony_ci	/* Adjust the source and target buffer offsets and lengths  */
9018c2ecf20Sopenharmony_ci
9028c2ecf20Sopenharmony_ci	NXPRT(fprintf(stderr, "offsets_state:\n"));
9038c2ecf20Sopenharmony_ci
9048c2ecf20Sopenharmony_ci	/* Delete input data from fifo_in */
9058c2ecf20Sopenharmony_ci	used_in = used_in - source_sz;
9068c2ecf20Sopenharmony_ci	cur_in = (cur_in + source_sz) % fifo_in_len;
9078c2ecf20Sopenharmony_ci	input_file_offset = input_file_offset + source_sz;
9088c2ecf20Sopenharmony_ci
9098c2ecf20Sopenharmony_ci	/* Add output data to fifo_out */
9108c2ecf20Sopenharmony_ci	used_out = used_out + tpbc;
9118c2ecf20Sopenharmony_ci
9128c2ecf20Sopenharmony_ci	assert(used_out <= fifo_out_len);
9138c2ecf20Sopenharmony_ci
9148c2ecf20Sopenharmony_ci	total_out = total_out + tpbc;
9158c2ecf20Sopenharmony_ci
9168c2ecf20Sopenharmony_ci	/* Deflate history is 32KB max.  No need to supply more
9178c2ecf20Sopenharmony_ci	 * than 32KB on a resume.
9188c2ecf20Sopenharmony_ci	 */
9198c2ecf20Sopenharmony_ci	history_len = (total_out > window_max) ? window_max : total_out;
9208c2ecf20Sopenharmony_ci
9218c2ecf20Sopenharmony_ci	/* To estimate expected expansion in the next NX job; 500 means 50%.
9228c2ecf20Sopenharmony_ci	 * Deflate best case is around 1 to 1000.
9238c2ecf20Sopenharmony_ci	 */
9248c2ecf20Sopenharmony_ci	last_comp_ratio = (1000UL * ((uint64_t)source_sz + 1))
9258c2ecf20Sopenharmony_ci			  / ((uint64_t)tpbc + 1);
9268c2ecf20Sopenharmony_ci	last_comp_ratio = NX_MAX(NX_MIN(1000UL, last_comp_ratio), 1);
9278c2ecf20Sopenharmony_ci	NXPRT(fprintf(stderr, "comp_ratio %ld source_sz %d spbc %d tpbc %d\n",
9288c2ecf20Sopenharmony_ci		      last_comp_ratio, source_sz, spbc, tpbc));
9298c2ecf20Sopenharmony_ci
9308c2ecf20Sopenharmony_ci	resuming = 1;
9318c2ecf20Sopenharmony_ci
9328c2ecf20Sopenharmony_cifinish_state:
9338c2ecf20Sopenharmony_ci
9348c2ecf20Sopenharmony_ci	NXPRT(fprintf(stderr, "finish_state:\n"));
9358c2ecf20Sopenharmony_ci
9368c2ecf20Sopenharmony_ci	if (is_final) {
9378c2ecf20Sopenharmony_ci		if (used_out)
9388c2ecf20Sopenharmony_ci			goto write_state; /* More data to write out */
9398c2ecf20Sopenharmony_ci		else if (used_in < 8) {
9408c2ecf20Sopenharmony_ci			/* Need at least 8 more bytes containing gzip crc
9418c2ecf20Sopenharmony_ci			 * and isize.
9428c2ecf20Sopenharmony_ci			 */
9438c2ecf20Sopenharmony_ci			rc = -1;
9448c2ecf20Sopenharmony_ci			goto err4;
9458c2ecf20Sopenharmony_ci		} else {
9468c2ecf20Sopenharmony_ci			/* Compare checksums and exit */
9478c2ecf20Sopenharmony_ci			int i;
9488c2ecf20Sopenharmony_ci			unsigned char tail[8];
9498c2ecf20Sopenharmony_ci			uint32_t cksum, isize;
9508c2ecf20Sopenharmony_ci
9518c2ecf20Sopenharmony_ci			for (i = 0; i < 8; i++)
9528c2ecf20Sopenharmony_ci				tail[i] = fifo_in[(cur_in + i) % fifo_in_len];
9538c2ecf20Sopenharmony_ci			fprintf(stderr, "computed checksum %08x isize %08x\n",
9548c2ecf20Sopenharmony_ci				cmdp->cpb.out_crc, (uint32_t) (total_out
9558c2ecf20Sopenharmony_ci				% (1ULL<<32)));
9568c2ecf20Sopenharmony_ci			cksum = ((uint32_t) tail[0] | (uint32_t) tail[1]<<8
9578c2ecf20Sopenharmony_ci				 | (uint32_t) tail[2]<<16
9588c2ecf20Sopenharmony_ci				 | (uint32_t) tail[3]<<24);
9598c2ecf20Sopenharmony_ci			isize = ((uint32_t) tail[4] | (uint32_t) tail[5]<<8
9608c2ecf20Sopenharmony_ci				 | (uint32_t) tail[6]<<16
9618c2ecf20Sopenharmony_ci				 | (uint32_t) tail[7]<<24);
9628c2ecf20Sopenharmony_ci			fprintf(stderr, "stored   checksum %08x isize %08x\n",
9638c2ecf20Sopenharmony_ci				cksum, isize);
9648c2ecf20Sopenharmony_ci
9658c2ecf20Sopenharmony_ci			if (cksum == cmdp->cpb.out_crc && isize == (uint32_t)
9668c2ecf20Sopenharmony_ci			    (total_out % (1ULL<<32))) {
9678c2ecf20Sopenharmony_ci				rc = 0;	goto ok1;
9688c2ecf20Sopenharmony_ci			} else {
9698c2ecf20Sopenharmony_ci				rc = -1; goto err4;
9708c2ecf20Sopenharmony_ci			}
9718c2ecf20Sopenharmony_ci		}
9728c2ecf20Sopenharmony_ci	} else
9738c2ecf20Sopenharmony_ci		goto read_state;
9748c2ecf20Sopenharmony_ci
9758c2ecf20Sopenharmony_ci	return -1;
9768c2ecf20Sopenharmony_ci
9778c2ecf20Sopenharmony_cierr1:
9788c2ecf20Sopenharmony_ci	fprintf(stderr, "error: not a gzip file, expect %x, read %x\n",
9798c2ecf20Sopenharmony_ci		expect, c);
9808c2ecf20Sopenharmony_ci	return -1;
9818c2ecf20Sopenharmony_ci
9828c2ecf20Sopenharmony_cierr2:
9838c2ecf20Sopenharmony_ci	fprintf(stderr, "error: the FLG byte is wrong or not being handled\n");
9848c2ecf20Sopenharmony_ci	return -1;
9858c2ecf20Sopenharmony_ci
9868c2ecf20Sopenharmony_cierr3:
9878c2ecf20Sopenharmony_ci	fprintf(stderr, "error: gzip header\n");
9888c2ecf20Sopenharmony_ci	return -1;
9898c2ecf20Sopenharmony_ci
9908c2ecf20Sopenharmony_cierr4:
9918c2ecf20Sopenharmony_ci	fprintf(stderr, "error: checksum missing or mismatch\n");
9928c2ecf20Sopenharmony_ci
9938c2ecf20Sopenharmony_cierr5:
9948c2ecf20Sopenharmony_ciok1:
9958c2ecf20Sopenharmony_ci	fprintf(stderr, "decomp is complete: fclose\n");
9968c2ecf20Sopenharmony_ci	fclose(outf);
9978c2ecf20Sopenharmony_ci
9988c2ecf20Sopenharmony_ci	return rc;
9998c2ecf20Sopenharmony_ci}
10008c2ecf20Sopenharmony_ci
10018c2ecf20Sopenharmony_ci
10028c2ecf20Sopenharmony_ciint main(int argc, char **argv)
10038c2ecf20Sopenharmony_ci{
10048c2ecf20Sopenharmony_ci	int rc;
10058c2ecf20Sopenharmony_ci	struct sigaction act;
10068c2ecf20Sopenharmony_ci	void *handle;
10078c2ecf20Sopenharmony_ci
10088c2ecf20Sopenharmony_ci	nx_dbg = 0;
10098c2ecf20Sopenharmony_ci	nx_gzip_log = NULL;
10108c2ecf20Sopenharmony_ci	act.sa_handler = 0;
10118c2ecf20Sopenharmony_ci	act.sa_sigaction = nxu_sigsegv_handler;
10128c2ecf20Sopenharmony_ci	act.sa_flags = SA_SIGINFO;
10138c2ecf20Sopenharmony_ci	act.sa_restorer = 0;
10148c2ecf20Sopenharmony_ci	sigemptyset(&act.sa_mask);
10158c2ecf20Sopenharmony_ci	sigaction(SIGSEGV, &act, NULL);
10168c2ecf20Sopenharmony_ci
10178c2ecf20Sopenharmony_ci	handle = nx_function_begin(NX_FUNC_COMP_GZIP, 0);
10188c2ecf20Sopenharmony_ci	if (!handle) {
10198c2ecf20Sopenharmony_ci		fprintf(stderr, "Unable to init NX, errno %d\n", errno);
10208c2ecf20Sopenharmony_ci		exit(-1);
10218c2ecf20Sopenharmony_ci	}
10228c2ecf20Sopenharmony_ci
10238c2ecf20Sopenharmony_ci	rc = decompress_file(argc, argv, handle);
10248c2ecf20Sopenharmony_ci
10258c2ecf20Sopenharmony_ci	nx_function_end(handle);
10268c2ecf20Sopenharmony_ci
10278c2ecf20Sopenharmony_ci	return rc;
10288c2ecf20Sopenharmony_ci}
1029