Resguardo inicial

This commit is contained in:
lastdragon
2026-09-06 12:53:21 -06:00
parent 662efe3c2a
commit ad2088d178
94853 changed files with 43200404 additions and 0 deletions
@@ -0,0 +1,3 @@
# SPDX-License-Identifier: GPL-2.0-only
gunz_test
gzfht_test
@@ -0,0 +1 @@
SUBSYSTEM=="nxgzip", KERNEL=="nx-gzip", MODE="0666"
@@ -0,0 +1,9 @@
TEST_GEN_FILES := gzfht_test gunz_test
TEST_PROGS := nx-gzip-test.sh
include ../../lib.mk
include ../flags.mk
CFLAGS = -O3 -m64 -I./include -I../include
$(TEST_GEN_FILES): gzip_vas.c ../utils.c
@@ -0,0 +1,45 @@
Test the nx-gzip function:
=========================
Verify that following device exists:
/dev/crypto/nx-gzip
If you get a permission error run as sudo or set the device permissions:
sudo chmod go+rw /dev/crypto/nx-gzip
However, chmod may not survive across boots. You may create a udev file such
as:
/etc/udev/rules.d/99-nx-gzip.rules
To manually build and run:
$ gcc -O3 -I./include -o gzfht_test gzfht_test.c gzip_vas.c
$ gcc -O3 -I./include -o gunz_test gunz_test.c gzip_vas.c
Compress any file using Fixed Huffman mode. Output will have a .nx.gz suffix:
$ ./gzfht_test gzip_vas.c
file gzip_vas.c read, 6413 bytes
compressed 6413 to 3124 bytes total, crc32 checksum = abd15e8a
Uncompress the previous output. Output will have a .nx.gunzip suffix:
./gunz_test gzip_vas.c.nx.gz
gzHeader FLG 0
00 00 00 00 04 03
gzHeader MTIME, XFL, OS ignored
computed checksum abd15e8a isize 0000190d
stored checksum abd15e8a isize 0000190d
decomp is complete: fclose
Compare two files:
$ sha1sum gzip_vas.c.nx.gz.nx.gunzip gzip_vas.c
bf43e3c0c3651f5f22b6f9784cd9b1eeab4120b6 gzip_vas.c.nx.gz.nx.gunzip
bf43e3c0c3651f5f22b6f9784cd9b1eeab4120b6 gzip_vas.c
Note that the code here are intended for testing the nx-gzip hardware function.
They are not intended for demonstrating performance or compression ratio.
By being simplistic these selftests expect to allocate the entire set of source
and target pages in the memory so it needs enough memory to work.
For more information and source code consider using:
https://github.com/libnxz/power-gzip
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,398 @@
// SPDX-License-Identifier: GPL-2.0-or-later
/* P9 gzip sample code for demonstrating the P9 NX hardware interface.
* Not intended for productive uses or for performance or compression
* ratio measurements. For simplicity of demonstration, this sample
* code compresses in to fixed Huffman blocks only (Deflate btype=1)
* and has very simple memory management. Dynamic Huffman blocks
* (Deflate btype=2) are more involved as detailed in the user guide.
* Note also that /dev/crypto/gzip, VAS and skiboot support are
* required.
*
* Copyright 2020 IBM Corp.
*
* https://github.com/libnxz/power-gzip for zlib api and other utils
*
* Author: Bulent Abali <abali@us.ibm.com>
*
* Definitions of acronyms used here. See
* P9 NX Gzip Accelerator User's Manual for details:
* https://github.com/libnxz/power-gzip/blob/develop/doc/power_nx_gzip_um.pdf
*
* adler/crc: 32 bit checksums appended to stream tail
* ce: completion extension
* cpb: coprocessor parameter block (metadata)
* crb: coprocessor request block (command)
* csb: coprocessor status block (status)
* dht: dynamic huffman table
* dde: data descriptor element (address, length)
* ddl: list of ddes
* dh/fh: dynamic and fixed huffman types
* fc: coprocessor function code
* histlen: history/dictionary length
* history: sliding window of up to 32KB of data
* lzcount: Deflate LZ symbol counts
* rembytecnt: remaining byte count
* sfbt: source final block type; last block's type during decomp
* spbc: source processed byte count
* subc: source unprocessed bit count
* tebc: target ending bit count; valid bits in the last byte
* tpbc: target processed byte count
* vas: virtual accelerator switch; the user mode interface
*/
#define _ISOC11_SOURCE // For aligned_alloc()
#define _DEFAULT_SOURCE // For endian.h
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <stdint.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/time.h>
#include <sys/fcntl.h>
#include <sys/mman.h>
#include <endian.h>
#include <bits/endian.h>
#include <sys/ioctl.h>
#include <assert.h>
#include <errno.h>
#include <signal.h>
#include "utils.h"
#include "nxu.h"
#include "nx.h"
int nx_dbg;
FILE *nx_gzip_log;
#define NX_MIN(X, Y) (((X) < (Y)) ? (X) : (Y))
#define FNAME_MAX 1024
#define FEXT ".nx.gz"
#define SYSFS_MAX_REQ_BUF_PATH "devices/vio/ibm,compression-v1/nx_gzip_caps/req_max_processed_len"
/*
* LZ counts returned in the user supplied nx_gzip_crb_cpb_t structure.
*/
static int compress_fht_sample(char *src, uint32_t srclen, char *dst,
uint32_t dstlen, int with_count,
struct nx_gzip_crb_cpb_t *cmdp, void *handle)
{
uint32_t fc;
assert(!!cmdp);
put32(cmdp->crb, gzip_fc, 0); /* clear */
fc = (with_count) ? GZIP_FC_COMPRESS_RESUME_FHT_COUNT :
GZIP_FC_COMPRESS_RESUME_FHT;
putnn(cmdp->crb, gzip_fc, fc);
putnn(cmdp->cpb, in_histlen, 0); /* resuming with no history */
memset((void *) &cmdp->crb.csb, 0, sizeof(cmdp->crb.csb));
/* Section 6.6 programming notes; spbc may be in two different
* places depending on FC.
*/
if (!with_count)
put32(cmdp->cpb, out_spbc_comp, 0);
else
put32(cmdp->cpb, out_spbc_comp_with_count, 0);
/* Figure 6-3 6-4; CSB location */
put64(cmdp->crb, csb_address, 0);
put64(cmdp->crb, csb_address,
(uint64_t) &cmdp->crb.csb & csb_address_mask);
/* Source direct dde (scatter-gather list) */
clear_dde(cmdp->crb.source_dde);
putnn(cmdp->crb.source_dde, dde_count, 0);
put32(cmdp->crb.source_dde, ddebc, srclen);
put64(cmdp->crb.source_dde, ddead, (uint64_t) src);
/* Target direct dde (scatter-gather list) */
clear_dde(cmdp->crb.target_dde);
putnn(cmdp->crb.target_dde, dde_count, 0);
put32(cmdp->crb.target_dde, ddebc, dstlen);
put64(cmdp->crb.target_dde, ddead, (uint64_t) dst);
/* Submit the crb, the job descriptor, to the accelerator */
return nxu_submit_job(cmdp, handle);
}
/*
* Prepares a blank no filename no timestamp gzip header and returns
* the number of bytes written to buf.
* Gzip specification at https://tools.ietf.org/html/rfc1952
*/
int gzip_header_blank(char *buf)
{
int i = 0;
buf[i++] = 0x1f; /* ID1 */
buf[i++] = 0x8b; /* ID2 */
buf[i++] = 0x08; /* CM */
buf[i++] = 0x00; /* FLG */
buf[i++] = 0x00; /* MTIME */
buf[i++] = 0x00; /* MTIME */
buf[i++] = 0x00; /* MTIME */
buf[i++] = 0x00; /* MTIME */
buf[i++] = 0x04; /* XFL 4=fastest */
buf[i++] = 0x03; /* OS UNIX */
return i;
}
/*
* Z_SYNC_FLUSH as described in zlib.h.
* Returns number of appended bytes
*/
int append_sync_flush(char *buf, int tebc, int final)
{
uint64_t flush;
int shift = (tebc & 0x7);
if (tebc > 0) {
/* Last byte is partially full */
buf = buf - 1;
*buf = *buf & (unsigned char) ((1<<tebc)-1);
} else
*buf = 0;
flush = ((0x1ULL & final) << shift) | *buf;
shift = shift + 3; /* BFINAL and BTYPE written */
shift = (shift <= 8) ? 8 : 16;
flush |= (0xFFFF0000ULL) << shift; /* Zero length block */
shift = shift + 32;
while (shift > 0) {
*buf++ = (unsigned char) (flush & 0xffULL);
flush = flush >> 8;
shift = shift - 8;
}
return(((tebc > 5) || (tebc == 0)) ? 5 : 4);
}
/*
* Final deflate block bit. This call assumes the block
* beginning is byte aligned.
*/
static void set_bfinal(void *buf, int bfinal)
{
char *b = buf;
if (bfinal)
*b = *b | (unsigned char) 0x01;
else
*b = *b & (unsigned char) 0xfe;
}
int compress_file(int argc, char **argv, void *handle)
{
char *inbuf, *outbuf, *srcbuf, *dstbuf;
char outname[FNAME_MAX];
uint32_t srclen, dstlen;
uint32_t flushlen, chunk;
size_t inlen, outlen, dsttotlen, srctotlen;
uint32_t crc, spbc, tpbc, tebc;
int lzcounts = 0;
int cc;
int num_hdr_bytes;
struct nx_gzip_crb_cpb_t *cmdp;
uint32_t pagelen = 65536;
int fault_tries = NX_MAX_FAULTS;
char buf[32];
cmdp = (void *)(uintptr_t)
aligned_alloc(sizeof(struct nx_gzip_crb_cpb_t),
sizeof(struct nx_gzip_crb_cpb_t));
if (argc != 2) {
fprintf(stderr, "usage: %s <fname>\n", argv[0]);
exit(-1);
}
if (read_file_alloc(argv[1], &inbuf, &inlen))
exit(-1);
fprintf(stderr, "file %s read, %ld bytes\n", argv[1], inlen);
/* Generous output buffer for header/trailer */
outlen = 2 * inlen + 1024;
assert(NULL != (outbuf = (char *)malloc(outlen)));
nxu_touch_pages(outbuf, outlen, pagelen, 1);
/*
* On PowerVM, the hypervisor defines the maximum request buffer
* size is defined and this value is available via sysfs.
*/
if (!read_sysfs_file(SYSFS_MAX_REQ_BUF_PATH, buf, sizeof(buf))) {
chunk = atoi(buf);
} else {
/* sysfs entry is not available on PowerNV */
/* Compress piecemeal in smallish chunks */
chunk = 1<<22;
}
/* Write the gzip header to the stream */
num_hdr_bytes = gzip_header_blank(outbuf);
dstbuf = outbuf + num_hdr_bytes;
outlen = outlen - num_hdr_bytes;
dsttotlen = num_hdr_bytes;
srcbuf = inbuf;
srctotlen = 0;
/* Init the CRB, the coprocessor request block */
memset(&cmdp->crb, 0, sizeof(cmdp->crb));
/* Initial gzip crc32 */
put32(cmdp->cpb, in_crc, 0);
while (inlen > 0) {
/* Submit chunk size source data per job */
srclen = NX_MIN(chunk, inlen);
/* Supply large target in case data expands */
dstlen = NX_MIN(2*srclen, outlen);
/* Page faults are handled by the user code */
/* Fault-in pages; an improved code wouldn't touch so
* many pages but would try to estimate the
* compression ratio and adjust both the src and dst
* touch amounts.
*/
nxu_touch_pages(cmdp, sizeof(struct nx_gzip_crb_cpb_t), pagelen,
1);
nxu_touch_pages(srcbuf, srclen, pagelen, 0);
nxu_touch_pages(dstbuf, dstlen, pagelen, 1);
cc = compress_fht_sample(
srcbuf, srclen,
dstbuf, dstlen,
lzcounts, cmdp, handle);
if (cc != ERR_NX_OK && cc != ERR_NX_TPBC_GT_SPBC &&
cc != ERR_NX_AT_FAULT) {
fprintf(stderr, "nx error: cc= %d\n", cc);
exit(-1);
}
/* Page faults are handled by the user code */
if (cc == ERR_NX_AT_FAULT) {
NXPRT(fprintf(stderr, "page fault: cc= %d, ", cc));
NXPRT(fprintf(stderr, "try= %d, fsa= %08llx\n",
fault_tries,
(unsigned long long) cmdp->crb.csb.fsaddr));
fault_tries--;
if (fault_tries > 0) {
continue;
} else {
fprintf(stderr, "error: cannot progress; ");
fprintf(stderr, "too many faults\n");
exit(-1);
}
}
fault_tries = NX_MAX_FAULTS; /* Reset for the next chunk */
inlen = inlen - srclen;
srcbuf = srcbuf + srclen;
srctotlen = srctotlen + srclen;
/* Two possible locations for spbc depending on the function
* code.
*/
spbc = (!lzcounts) ? get32(cmdp->cpb, out_spbc_comp) :
get32(cmdp->cpb, out_spbc_comp_with_count);
assert(spbc == srclen);
/* Target byte count */
tpbc = get32(cmdp->crb.csb, tpbc);
/* Target ending bit count */
tebc = getnn(cmdp->cpb, out_tebc);
NXPRT(fprintf(stderr, "compressed chunk %d ", spbc));
NXPRT(fprintf(stderr, "to %d bytes, tebc= %d\n", tpbc, tebc));
if (inlen > 0) { /* More chunks to go */
set_bfinal(dstbuf, 0);
dstbuf = dstbuf + tpbc;
dsttotlen = dsttotlen + tpbc;
outlen = outlen - tpbc;
/* Round up to the next byte with a flush
* block; do not set the BFINAqL bit.
*/
flushlen = append_sync_flush(dstbuf, tebc, 0);
dsttotlen = dsttotlen + flushlen;
outlen = outlen - flushlen;
dstbuf = dstbuf + flushlen;
NXPRT(fprintf(stderr, "added sync_flush %d bytes\n",
flushlen));
} else { /* Done */
/* Set the BFINAL bit of the last block per Deflate
* specification.
*/
set_bfinal(dstbuf, 1);
dstbuf = dstbuf + tpbc;
dsttotlen = dsttotlen + tpbc;
outlen = outlen - tpbc;
}
/* Resuming crc32 for the next chunk */
crc = get32(cmdp->cpb, out_crc);
put32(cmdp->cpb, in_crc, crc);
crc = be32toh(crc);
}
/* Append crc32 and ISIZE to the end */
memcpy(dstbuf, &crc, 4);
memcpy(dstbuf+4, &srctotlen, 4);
dsttotlen = dsttotlen + 8;
outlen = outlen - 8;
assert(FNAME_MAX > (strlen(argv[1]) + strlen(FEXT)));
strcpy(outname, argv[1]);
strcat(outname, FEXT);
if (write_file(outname, outbuf, dsttotlen)) {
fprintf(stderr, "write error: %s\n", outname);
exit(-1);
}
fprintf(stderr, "compressed %ld to %ld bytes total, ", srctotlen,
dsttotlen);
fprintf(stderr, "crc32 checksum = %08x\n", crc);
if (inbuf != NULL)
free(inbuf);
if (outbuf != NULL)
free(outbuf);
return 0;
}
int main(int argc, char **argv)
{
int rc;
struct sigaction act;
void *handle;
nx_dbg = 0;
nx_gzip_log = NULL;
act.sa_handler = 0;
act.sa_sigaction = nxu_sigsegv_handler;
act.sa_flags = SA_SIGINFO;
act.sa_restorer = 0;
sigemptyset(&act.sa_mask);
sigaction(SIGSEGV, &act, NULL);
handle = nx_function_begin(NX_FUNC_COMP_GZIP, 0);
if (!handle) {
fprintf(stderr, "Unable to init NX, errno %d\n", errno);
exit(-1);
}
rc = compress_file(argc, argv, handle);
nx_function_end(handle);
return rc;
}
@@ -0,0 +1,316 @@
// SPDX-License-Identifier: GPL-2.0-or-later
/*
* Copyright 2020 IBM Corp.
*
* Author: Bulent Abali <abali@us.ibm.com>
*
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <stdint.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/time.h>
#include <sys/fcntl.h>
#include <sys/mman.h>
#include <endian.h>
#include <bits/endian.h>
#include <sys/ioctl.h>
#include <assert.h>
#include <errno.h>
#include <signal.h>
#include "vas-api.h"
#include "nx.h"
#include "copy-paste.h"
#include "nxu.h"
#include "nx_dbg.h"
#include <sys/platform/ppc.h>
#define barrier()
#define hwsync() ({ asm volatile("sync" ::: "memory"); })
#ifndef NX_NO_CPU_PRI
#define cpu_pri_default() ({ asm volatile ("or 2, 2, 2"); })
#define cpu_pri_low() ({ asm volatile ("or 31, 31, 31"); })
#else
#define cpu_pri_default()
#define cpu_pri_low()
#endif
void *nx_fault_storage_address;
struct nx_handle {
int fd;
int function;
void *paste_addr;
};
static int open_device_nodes(char *devname, int pri, struct nx_handle *handle)
{
int rc, fd;
void *addr;
struct vas_tx_win_open_attr txattr;
fd = open(devname, O_RDWR);
if (fd < 0) {
fprintf(stderr, " open device name %s\n", devname);
return -errno;
}
memset(&txattr, 0, sizeof(txattr));
txattr.version = 1;
txattr.vas_id = pri;
rc = ioctl(fd, VAS_TX_WIN_OPEN, (unsigned long)&txattr);
if (rc < 0) {
fprintf(stderr, "ioctl() n %d, error %d\n", rc, errno);
rc = -errno;
goto out;
}
addr = mmap(NULL, 4096, PROT_READ|PROT_WRITE, MAP_SHARED, fd, 0ULL);
if (addr == MAP_FAILED) {
fprintf(stderr, "mmap() failed, errno %d\n", errno);
rc = -errno;
goto out;
}
handle->fd = fd;
handle->paste_addr = (void *)((char *)addr + 0x400);
rc = 0;
out:
close(fd);
return rc;
}
void *nx_function_begin(int function, int pri)
{
int rc;
char *devname = "/dev/crypto/nx-gzip";
struct nx_handle *nxhandle;
if (function != NX_FUNC_COMP_GZIP) {
errno = EINVAL;
fprintf(stderr, " NX_FUNC_COMP_GZIP not found\n");
return NULL;
}
nxhandle = malloc(sizeof(*nxhandle));
if (!nxhandle) {
errno = ENOMEM;
fprintf(stderr, " No memory\n");
return NULL;
}
nxhandle->function = function;
rc = open_device_nodes(devname, pri, nxhandle);
if (rc < 0) {
errno = -rc;
fprintf(stderr, " open_device_nodes failed\n");
return NULL;
}
return nxhandle;
}
int nx_function_end(void *handle)
{
int rc = 0;
struct nx_handle *nxhandle = handle;
rc = munmap(nxhandle->paste_addr - 0x400, 4096);
if (rc < 0) {
fprintf(stderr, "munmap() failed, errno %d\n", errno);
return rc;
}
close(nxhandle->fd);
free(nxhandle);
return rc;
}
static int nx_wait_for_csb(struct nx_gzip_crb_cpb_t *cmdp)
{
long poll = 0;
uint64_t t;
/* Save power and let other threads use the h/w. top may show
* 100% but only because OS doesn't know we slowed the this
* h/w thread while polling. We're letting other threads have
* higher throughput on the core.
*/
cpu_pri_low();
#define CSB_MAX_POLL 200000000UL
#define USLEEP_TH 300000UL
t = __ppc_get_timebase();
while (getnn(cmdp->crb.csb, csb_v) == 0) {
++poll;
hwsync();
cpu_pri_low();
/* usleep(0) takes around 29000 ticks ~60 us.
* 300000 is spinning for about 600 us then
* start sleeping.
*/
if ((__ppc_get_timebase() - t) > USLEEP_TH) {
cpu_pri_default();
usleep(1);
}
if (poll > CSB_MAX_POLL)
break;
/* Fault address from signal handler */
if (nx_fault_storage_address) {
cpu_pri_default();
return -EAGAIN;
}
}
cpu_pri_default();
/* hw has updated csb and output buffer */
hwsync();
/* Check CSB flags. */
if (getnn(cmdp->crb.csb, csb_v) == 0) {
fprintf(stderr, "CSB still not valid after %d polls.\n",
(int) poll);
prt_err("CSB still not valid after %d polls, giving up.\n",
(int) poll);
return -ETIMEDOUT;
}
return 0;
}
static int nxu_run_job(struct nx_gzip_crb_cpb_t *cmdp, void *handle)
{
int i, ret, retries;
struct nx_handle *nxhandle = handle;
assert(handle != NULL);
i = 0;
retries = 5000;
while (i++ < retries) {
hwsync();
vas_copy(&cmdp->crb, 0);
ret = vas_paste(nxhandle->paste_addr, 0);
hwsync();
NXPRT(fprintf(stderr, "Paste attempt %d/%d returns 0x%x\n",
i, retries, ret));
if ((ret == 2) || (ret == 3)) {
ret = nx_wait_for_csb(cmdp);
if (!ret) {
goto out;
} else if (ret == -EAGAIN) {
long x;
prt_err("Touching address %p, 0x%lx\n",
nx_fault_storage_address,
*(long *) nx_fault_storage_address);
x = *(long *) nx_fault_storage_address;
*(long *) nx_fault_storage_address = x;
nx_fault_storage_address = 0;
continue;
} else {
prt_err("wait_for_csb() returns %d\n", ret);
break;
}
} else {
if (i < 10) {
/* spin for few ticks */
#define SPIN_TH 500UL
uint64_t fail_spin;
fail_spin = __ppc_get_timebase();
while ((__ppc_get_timebase() - fail_spin) <
SPIN_TH)
;
} else {
/* sleep */
unsigned int pr = 0;
if (pr++ % 100 == 0) {
prt_err("Paste attempt %d/", i);
prt_err("%d, failed pid= %d\n", retries,
getpid());
}
usleep(1);
}
continue;
}
}
out:
cpu_pri_default();
return ret;
}
int nxu_submit_job(struct nx_gzip_crb_cpb_t *cmdp, void *handle)
{
int cc;
cc = nxu_run_job(cmdp, handle);
if (!cc)
cc = getnn(cmdp->crb.csb, csb_cc); /* CC Table 6-8 */
return cc;
}
void nxu_sigsegv_handler(int sig, siginfo_t *info, void *ctx)
{
fprintf(stderr, "%d: Got signal %d si_code %d, si_addr %p\n", getpid(),
sig, info->si_code, info->si_addr);
nx_fault_storage_address = info->si_addr;
}
/*
* Fault in pages prior to NX job submission. wr=1 may be required to
* touch writeable pages. System zero pages do not fault-in the page as
* intended. Typically set wr=1 for NX target pages and set wr=0 for NX
* source pages.
*/
int nxu_touch_pages(void *buf, long buf_len, long page_len, int wr)
{
char *begin = buf;
char *end = (char *) buf + buf_len - 1;
volatile char t;
assert(buf_len >= 0 && !!buf);
NXPRT(fprintf(stderr, "touch %p %p len 0x%lx wr=%d\n", buf,
(buf + buf_len), buf_len, wr));
if (buf_len <= 0 || buf == NULL)
return -1;
do {
t = *begin;
if (wr)
*begin = t;
begin = begin + page_len;
} while (begin < end);
/* When buf_sz is small or buf tail is in another page */
t = *end;
if (wr)
*end = t;
return 0;
}
@@ -0,0 +1,56 @@
/* SPDX-License-Identifier: GPL-2.0-or-later */
/* From asm-compat.h */
#define __stringify_in_c(...) #__VA_ARGS__
#define stringify_in_c(...) __stringify_in_c(__VA_ARGS__) " "
/*
* Macros taken from arch/powerpc/include/asm/ppc-opcode.h and other
* header files.
*/
#define ___PPC_RA(a) (((a) & 0x1f) << 16)
#define ___PPC_RB(b) (((b) & 0x1f) << 11)
#define PPC_INST_COPY 0x7c20060c
#define PPC_INST_PASTE 0x7c20070d
#define PPC_COPY(a, b) stringify_in_c(.long PPC_INST_COPY | \
___PPC_RA(a) | ___PPC_RB(b))
#define PPC_PASTE(a, b) stringify_in_c(.long PPC_INST_PASTE | \
___PPC_RA(a) | ___PPC_RB(b))
#define CR0_SHIFT 28
#define CR0_MASK 0xF
/*
* Copy/paste instructions:
*
* copy RA,RB
* Copy contents of address (RA) + effective_address(RB)
* to internal copy-buffer.
*
* paste RA,RB
* Paste contents of internal copy-buffer to the address
* (RA) + effective_address(RB)
*/
static inline int vas_copy(void *crb, int offset)
{
asm volatile(PPC_COPY(%0, %1)";"
:
: "b" (offset), "b" (crb)
: "memory");
return 0;
}
static inline int vas_paste(void *paste_address, int offset)
{
__u32 cr;
cr = 0;
asm volatile(PPC_PASTE(%1, %2)";"
"mfocrf %0, 0x80;"
: "=r" (cr)
: "b" (offset), "b" (paste_address)
: "memory", "cr0");
return (cr >> CR0_SHIFT) & CR0_MASK;
}
@@ -0,0 +1,155 @@
/* SPDX-License-Identifier: GPL-2.0-or-later */
#ifndef __CRB_H
#define __CRB_H
#include <linux/types.h>
#include "nx.h"
/* CCW 842 CI/FC masks
* NX P8 workbook, section 4.3.1, figure 4-6
* "CI/FC Boundary by NX CT type"
*/
#define CCW_CI_842 (0x00003ff8)
#define CCW_FC_842 (0x00000007)
/* Chapter 6.5.8 Coprocessor-Completion Block (CCB) */
#define CCB_VALUE (0x3fffffffffffffff)
#define CCB_ADDRESS (0xfffffffffffffff8)
#define CCB_CM (0x0000000000000007)
#define CCB_CM0 (0x0000000000000004)
#define CCB_CM12 (0x0000000000000003)
#define CCB_CM0_ALL_COMPLETIONS (0x0)
#define CCB_CM0_LAST_IN_CHAIN (0x4)
#define CCB_CM12_STORE (0x0)
#define CCB_CM12_INTERRUPT (0x1)
#define CCB_SIZE (0x10)
#define CCB_ALIGN CCB_SIZE
struct coprocessor_completion_block {
__be64 value;
__be64 address;
} __aligned(CCB_ALIGN);
/* Chapter 6.5.7 Coprocessor-Status Block (CSB) */
#define CSB_V (0x80)
#define CSB_F (0x04)
#define CSB_CH (0x03)
#define CSB_CE_INCOMPLETE (0x80)
#define CSB_CE_TERMINATION (0x40)
#define CSB_CE_TPBC (0x20)
#define CSB_CC_SUCCESS (0)
#define CSB_CC_INVALID_ALIGN (1)
#define CSB_CC_OPERAND_OVERLAP (2)
#define CSB_CC_DATA_LENGTH (3)
#define CSB_CC_TRANSLATION (5)
#define CSB_CC_PROTECTION (6)
#define CSB_CC_RD_EXTERNAL (7)
#define CSB_CC_INVALID_OPERAND (8)
#define CSB_CC_PRIVILEGE (9)
#define CSB_CC_INTERNAL (10)
#define CSB_CC_WR_EXTERNAL (12)
#define CSB_CC_NOSPC (13)
#define CSB_CC_EXCESSIVE_DDE (14)
#define CSB_CC_WR_TRANSLATION (15)
#define CSB_CC_WR_PROTECTION (16)
#define CSB_CC_UNKNOWN_CODE (17)
#define CSB_CC_ABORT (18)
#define CSB_CC_TRANSPORT (20)
#define CSB_CC_SEGMENTED_DDL (31)
#define CSB_CC_PROGRESS_POINT (32)
#define CSB_CC_DDE_OVERFLOW (33)
#define CSB_CC_SESSION (34)
#define CSB_CC_PROVISION (36)
#define CSB_CC_CHAIN (37)
#define CSB_CC_SEQUENCE (38)
#define CSB_CC_HW (39)
#define CSB_SIZE (0x10)
#define CSB_ALIGN CSB_SIZE
struct coprocessor_status_block {
__u8 flags;
__u8 cs;
__u8 cc;
__u8 ce;
__be32 count;
__be64 address;
} __aligned(CSB_ALIGN);
/* Chapter 6.5.10 Data-Descriptor List (DDL)
* each list contains one or more Data-Descriptor Entries (DDE)
*/
#define DDE_P (0x8000)
#define DDE_SIZE (0x10)
#define DDE_ALIGN DDE_SIZE
struct data_descriptor_entry {
__be16 flags;
__u8 count;
__u8 index;
__be32 length;
__be64 address;
} __aligned(DDE_ALIGN);
/* Chapter 6.5.2 Coprocessor-Request Block (CRB) */
#define CRB_SIZE (0x80)
#define CRB_ALIGN (0x100) /* Errata: requires 256 alignment */
/* Coprocessor Status Block field
* ADDRESS address of CSB
* C CCB is valid
* AT 0 = addrs are virtual, 1 = addrs are phys
* M enable perf monitor
*/
#define CRB_CSB_ADDRESS (0xfffffffffffffff0)
#define CRB_CSB_C (0x0000000000000008)
#define CRB_CSB_AT (0x0000000000000002)
#define CRB_CSB_M (0x0000000000000001)
struct coprocessor_request_block {
__be32 ccw;
__be32 flags;
__be64 csb_addr;
struct data_descriptor_entry source;
struct data_descriptor_entry target;
struct coprocessor_completion_block ccb;
__u8 reserved[48];
struct coprocessor_status_block csb;
} __aligned(CRB_ALIGN);
#define crb_csb_addr(c) __be64_to_cpu(c->csb_addr)
#define crb_nx_fault_addr(c) __be64_to_cpu(c->stamp.nx.fault_storage_addr)
#define crb_nx_flags(c) c->stamp.nx.flags
#define crb_nx_fault_status(c) c->stamp.nx.fault_status
#define crb_nx_pswid(c) c->stamp.nx.pswid
/* RFC02167 Initiate Coprocessor Instructions document
* Chapter 8.2.1.1.1 RS
* Chapter 8.2.3 Coprocessor Directive
* Chapter 8.2.4 Execution
*
* The CCW must be converted to BE before passing to icswx()
*/
#define CCW_PS (0xff000000)
#define CCW_CT (0x00ff0000)
#define CCW_CD (0x0000ffff)
#define CCW_CL (0x0000c000)
#endif
@@ -0,0 +1,38 @@
/* SPDX-License-Identifier: GPL-2.0-or-later */
/*
* Copyright 2020 IBM Corp.
*
*/
#ifndef _NX_H
#define _NX_H
#include <stdbool.h>
#define NX_FUNC_COMP_842 1
#define NX_FUNC_COMP_GZIP 2
#ifndef __aligned
#define __aligned(x) __attribute__((aligned(x)))
#endif
struct nx842_func_args {
bool use_crc;
bool decompress; /* true decompress; false compress */
bool move_data;
int timeout; /* seconds */
};
struct nxbuf_t {
int len;
char *buf;
};
/* @function should be EFT (aka 842), GZIP etc */
void *nx_function_begin(int function, int pri);
int nx_function(void *handle, struct nxbuf_t *in, struct nxbuf_t *out,
void *arg);
int nx_function_end(void *handle);
#endif /* _NX_H */
@@ -0,0 +1,95 @@
/* SPDX-License-Identifier: GPL-2.0-or-later */
/*
* Copyright 2020 IBM Corporation
*
*/
#ifndef _NXU_DBG_H_
#define _NXU_DBG_H_
#include <sys/file.h>
#include <stdint.h>
#include <stdio.h>
#include <time.h>
#include <pthread.h>
extern FILE * nx_gzip_log;
extern int nx_gzip_trace;
extern unsigned int nx_gzip_inflate_impl;
extern unsigned int nx_gzip_deflate_impl;
extern unsigned int nx_gzip_inflate_flags;
extern unsigned int nx_gzip_deflate_flags;
extern int nx_dbg;
pthread_mutex_t mutex_log;
#define nx_gzip_trace_enabled() (nx_gzip_trace & 0x1)
#define nx_gzip_hw_trace_enabled() (nx_gzip_trace & 0x2)
#define nx_gzip_sw_trace_enabled() (nx_gzip_trace & 0x4)
#define nx_gzip_gather_statistics() (nx_gzip_trace & 0x8)
#define nx_gzip_per_stream_stat() (nx_gzip_trace & 0x10)
#define prt(fmt, ...) do { \
pthread_mutex_lock(&mutex_log); \
flock(nx_gzip_log->_fileno, LOCK_EX); \
time_t t; struct tm *m; time(&t); m = localtime(&t); \
fprintf(nx_gzip_log, "[%04d/%02d/%02d %02d:%02d:%02d] " \
"pid %d: " fmt, \
(int)m->tm_year + 1900, (int)m->tm_mon+1, (int)m->tm_mday, \
(int)m->tm_hour, (int)m->tm_min, (int)m->tm_sec, \
(int)getpid(), ## __VA_ARGS__); \
fflush(nx_gzip_log); \
flock(nx_gzip_log->_fileno, LOCK_UN); \
pthread_mutex_unlock(&mutex_log); \
} while (0)
/* Use in case of an error */
#define prt_err(fmt, ...) do { if (nx_dbg >= 0) { \
prt("%s:%u: Error: "fmt, \
__FILE__, __LINE__, ## __VA_ARGS__); \
}} while (0)
/* Use in case of an warning */
#define prt_warn(fmt, ...) do { if (nx_dbg >= 1) { \
prt("%s:%u: Warning: "fmt, \
__FILE__, __LINE__, ## __VA_ARGS__); \
}} while (0)
/* Informational printouts */
#define prt_info(fmt, ...) do { if (nx_dbg >= 2) { \
prt("Info: "fmt, ## __VA_ARGS__); \
}} while (0)
/* Trace zlib wrapper code */
#define prt_trace(fmt, ...) do { if (nx_gzip_trace_enabled()) { \
prt("### "fmt, ## __VA_ARGS__); \
}} while (0)
/* Trace statistics */
#define prt_stat(fmt, ...) do { if (nx_gzip_gather_statistics()) { \
prt("### "fmt, ## __VA_ARGS__); \
}} while (0)
/* Trace zlib hardware implementation */
#define hw_trace(fmt, ...) do { \
if (nx_gzip_hw_trace_enabled()) \
fprintf(nx_gzip_log, "hhh " fmt, ## __VA_ARGS__); \
} while (0)
/* Trace zlib software implementation */
#define sw_trace(fmt, ...) do { \
if (nx_gzip_sw_trace_enabled()) \
fprintf(nx_gzip_log, "sss " fmt, ## __VA_ARGS__); \
} while (0)
/**
* str_to_num - Convert string into number and copy with endings like
* KiB for kilobyte
* MiB for megabyte
* GiB for gigabyte
*/
uint64_t str_to_num(char *str);
void nx_lib_debug(int onoff);
#endif /* _NXU_DBG_H_ */
@@ -0,0 +1,650 @@
/* SPDX-License-Identifier: GPL-2.0-or-later */
/*
* Hardware interface of the NX-GZIP compression accelerator
*
* Copyright (C) IBM Corporation, 2020
*
* Author: Bulent Abali <abali@us.ibm.com>
*
*/
#ifndef _NXU_H
#define _NXU_H
#include <stdint.h>
#include <endian.h>
#include "nx.h"
/* deflate */
#define LLSZ 286
#define DSZ 30
/* nx */
#define DHTSZ 18
#define DHT_MAXSZ 288
#define MAX_DDE_COUNT 256
/* util */
#ifdef NXDBG
#define NXPRT(X) X
#else
#define NXPRT(X)
#endif
#ifdef NXTIMER
#include <sys/platform/ppc.h>
#define NX_CLK(X) X
#define nx_get_time() __ppc_get_timebase()
#define nx_get_freq() __ppc_get_timebase_freq()
#else
#define NX_CLK(X)
#define nx_get_time() (-1)
#define nx_get_freq() (-1)
#endif
#define NX_MAX_FAULTS 500
/*
* Definitions of acronyms used here. See
* P9 NX Gzip Accelerator User's Manual for details:
* https://github.com/libnxz/power-gzip/blob/develop/doc/power_nx_gzip_um.pdf
*
* adler/crc: 32 bit checksums appended to stream tail
* ce: completion extension
* cpb: coprocessor parameter block (metadata)
* crb: coprocessor request block (command)
* csb: coprocessor status block (status)
* dht: dynamic huffman table
* dde: data descriptor element (address, length)
* ddl: list of ddes
* dh/fh: dynamic and fixed huffman types
* fc: coprocessor function code
* histlen: history/dictionary length
* history: sliding window of up to 32KB of data
* lzcount: Deflate LZ symbol counts
* rembytecnt: remaining byte count
* sfbt: source final block type; last block's type during decomp
* spbc: source processed byte count
* subc: source unprocessed bit count
* tebc: target ending bit count; valid bits in the last byte
* tpbc: target processed byte count
* vas: virtual accelerator switch; the user mode interface
*/
union nx_qw_t {
uint32_t word[4];
uint64_t dword[2];
} __aligned(16);
/*
* Note: NX registers with fewer than 32 bits are declared by
* convention as uint32_t variables in unions. If *_offset and *_mask
* are defined for a variable, then use get_ put_ macros to
* conveniently access the register fields for endian conversions.
*/
struct nx_dde_t {
/* Data Descriptor Element, Section 6.4 */
union {
uint32_t dde_count;
/* When dde_count == 0 ddead is a pointer to a data buffer;
* ddebc is the buffer length bytes.
* When dde_count > 0 dde is an indirect dde; ddead is a
* pointer to a contiguous list of direct ddes; ddebc is the
* total length of all data pointed to by the list of direct
* ddes. Note that only one level of indirection is permitted.
* See Section 6.4 of the user manual for additional details.
*/
};
uint32_t ddebc; /* dde byte count */
uint64_t ddead; /* dde address */
} __aligned(16);
struct nx_csb_t {
/* Coprocessor Status Block, Section 6.6 */
union {
uint32_t csb_v;
/* Valid bit. v must be set to 0 by the program
* before submitting the coprocessor command.
* Software can poll for the v bit
*/
uint32_t csb_f;
/* 16B CSB size. Written to 0 by DMA when it writes the CPB */
uint32_t csb_cs;
/* cs completion sequence; unused */
uint32_t csb_cc;
/* cc completion code; cc != 0 exception occurred */
uint32_t csb_ce;
/* ce completion extension */
};
uint32_t tpbc;
/* target processed byte count TPBC */
uint64_t fsaddr;
/* Section 6.12.1 CSB NonZero error summary. FSA Failing storage
* address. Address where error occurred. When available, written
* to A field of CSB
*/
} __aligned(16);
struct nx_ccb_t {
/* Coprocessor Completion Block, Section 6.7 */
uint32_t reserved[3];
union {
/* When crb.c==0 (no ccb defined) it is reserved;
* When crb.c==1 (ccb defined) it is cm
*/
uint32_t ccb_cm;
/* Signal interrupt of crb.c==1 and cm==1 */
uint32_t word;
/* generic access to the 32bit word */
};
} __aligned(16);
struct vas_stamped_crb_t {
/*
* CRB operand of the paste coprocessor instruction is stamped
* in quadword 4 with the information shown here as its written
* in to the receive FIFO of the coprocessor
*/
union {
uint32_t vas_buf_num;
/* Verification only vas buffer number which correlates to
* the low order bits of the atag in the paste command
*/
uint32_t send_wc_id;
/* Pointer to Send Window Context that provides for NX address
* translation information, such as MSR and LPCR bits, job
* completion interrupt RA, PSWID, and job utilization counter.
*/
};
union {
uint32_t recv_wc_id;
/* Pointer to Receive Window Context. NX uses this to return
* credits to a Receive FIFO as entries are dequeued.
*/
};
uint32_t reserved2;
union {
uint32_t vas_invalid;
/* Invalid bit. If this bit is 1 the CRB is discarded by
* NX upon fetching from the receive FIFO. If this bit is 0
* the CRB is processed normally. The bit is stamped to 0
* by VAS and may be written to 1 by hypervisor while
* the CRB is in the receive FIFO (in memory).
*/
};
};
struct nx_stamped_fault_crb_t {
/*
* A CRB that has a translation fault is stamped by NX in quadword 4
* and pasted to the Fault Send Window in VAS.
*/
uint64_t fsa;
union {
uint32_t nxsf_t;
uint32_t nxsf_fs;
};
uint32_t pswid;
};
union stamped_crb_t {
struct vas_stamped_crb_t vas;
struct nx_stamped_fault_crb_t nx;
};
struct nx_gzip_cpb_t {
/*
* Coprocessor Parameter Block In/Out are used to pass metadata
* to/from accelerator. Tables 6.5 and 6.6 of the user manual.
*/
/* CPBInput */
struct {
union {
union nx_qw_t qw0;
struct {
uint32_t in_adler; /* bits 0:31 */
uint32_t in_crc; /* bits 32:63 */
union {
uint32_t in_histlen; /* bits 64:75 */
uint32_t in_subc; /* bits 93:95 */
};
union {
/* bits 108:111 */
uint32_t in_sfbt;
/* bits 112:127 */
uint32_t in_rembytecnt;
/* bits 116:127 */
uint32_t in_dhtlen;
};
};
};
union {
union nx_qw_t in_dht[DHTSZ]; /* qw[1:18] */
char in_dht_char[DHT_MAXSZ]; /* byte access */
};
union nx_qw_t reserved[5]; /* qw[19:23] */
};
/* CPBOutput */
volatile struct {
union {
union nx_qw_t qw24;
struct {
uint32_t out_adler; /* bits 0:31 qw[24] */
uint32_t out_crc; /* bits 32:63 qw[24] */
union {
/* bits 77:79 qw[24] */
uint32_t out_tebc;
/* bits 80:95 qw[24] */
uint32_t out_subc;
};
union {
/* bits 108:111 qw[24] */
uint32_t out_sfbt;
/* bits 112:127 qw[24] */
uint32_t out_rembytecnt;
/* bits 116:127 qw[24] */
uint32_t out_dhtlen;
};
};
};
union {
union nx_qw_t qw25[79]; /* qw[25:103] */
/* qw[25] compress no lzcounts or wrap */
uint32_t out_spbc_comp_wrap;
uint32_t out_spbc_wrap; /* qw[25] wrap */
/* qw[25] compress no lzcounts */
uint32_t out_spbc_comp;
/* 286 LL and 30 D symbol counts */
uint32_t out_lzcount[LLSZ+DSZ];
struct {
union nx_qw_t out_dht[DHTSZ]; /* qw[25:42] */
/* qw[43] decompress */
uint32_t out_spbc_decomp;
};
};
/* qw[104] compress with lzcounts */
uint32_t out_spbc_comp_with_count;
};
} __aligned(128);
struct nx_gzip_crb_t {
union { /* byte[0:3] */
uint32_t gzip_fc; /* bits[24-31] */
};
uint32_t reserved1; /* byte[4:7] */
union {
uint64_t csb_address; /* byte[8:15] */
struct {
uint32_t reserved2;
union {
uint32_t crb_c;
/* c==0 no ccb defined */
uint32_t crb_at;
/* at==0 address type is ignored;
* all addrs effective assumed.
*/
};
};
};
struct nx_dde_t source_dde; /* byte[16:31] */
struct nx_dde_t target_dde; /* byte[32:47] */
volatile struct nx_ccb_t ccb; /* byte[48:63] */
volatile union {
/* byte[64:239] shift csb by 128 bytes out of the crb; csb was
* in crb earlier; JReilly says csb written with partial inject
*/
union nx_qw_t reserved64[11];
union stamped_crb_t stamp; /* byte[64:79] */
};
volatile struct nx_csb_t csb;
} __aligned(128);
struct nx_gzip_crb_cpb_t {
struct nx_gzip_crb_t crb;
struct nx_gzip_cpb_t cpb;
} __aligned(2048);
/*
* NX hardware convention has the msb bit on the left numbered 0.
* The defines below has *_offset defined as the right most bit
* position of a field. x of size_mask(x) is the field width in bits.
*/
#define size_mask(x) ((1U<<(x))-1)
/*
* Offsets and Widths within the containing 32 bits of the various NX
* gzip hardware registers. Use the getnn/putnn macros to access
* these regs
*/
#define dde_count_mask size_mask(8)
#define dde_count_offset 23
/* CSB */
#define csb_v_mask size_mask(1)
#define csb_v_offset 0
#define csb_f_mask size_mask(1)
#define csb_f_offset 6
#define csb_cs_mask size_mask(8)
#define csb_cs_offset 15
#define csb_cc_mask size_mask(8)
#define csb_cc_offset 23
#define csb_ce_mask size_mask(8)
#define csb_ce_offset 31
/* CCB */
#define ccb_cm_mask size_mask(3)
#define ccb_cm_offset 31
/* VAS stamped CRB fields */
#define vas_buf_num_mask size_mask(6)
#define vas_buf_num_offset 5
#define send_wc_id_mask size_mask(16)
#define send_wc_id_offset 31
#define recv_wc_id_mask size_mask(16)
#define recv_wc_id_offset 31
#define vas_invalid_mask size_mask(1)
#define vas_invalid_offset 31
/* NX stamped fault CRB fields */
#define nxsf_t_mask size_mask(1)
#define nxsf_t_offset 23
#define nxsf_fs_mask size_mask(8)
#define nxsf_fs_offset 31
/* CPB input */
#define in_histlen_mask size_mask(12)
#define in_histlen_offset 11
#define in_dhtlen_mask size_mask(12)
#define in_dhtlen_offset 31
#define in_subc_mask size_mask(3)
#define in_subc_offset 31
#define in_sfbt_mask size_mask(4)
#define in_sfbt_offset 15
#define in_rembytecnt_mask size_mask(16)
#define in_rembytecnt_offset 31
/* CPB output */
#define out_tebc_mask size_mask(3)
#define out_tebc_offset 15
#define out_subc_mask size_mask(16)
#define out_subc_offset 31
#define out_sfbt_mask size_mask(4)
#define out_sfbt_offset 15
#define out_rembytecnt_mask size_mask(16)
#define out_rembytecnt_offset 31
#define out_dhtlen_mask size_mask(12)
#define out_dhtlen_offset 31
/* CRB */
#define gzip_fc_mask size_mask(8)
#define gzip_fc_offset 31
#define crb_c_mask size_mask(1)
#define crb_c_offset 28
#define crb_at_mask size_mask(1)
#define crb_at_offset 30
#define csb_address_mask ~(15UL) /* mask off bottom 4b */
/*
* Access macros for the registers. Do not access registers directly
* because of the endian conversion. P9 processor may run either as
* Little or Big endian. However the NX coprocessor regs are always
* big endian.
* Use the 32 and 64b macros to access respective
* register sizes.
* Use nn forms for the register fields shorter than 32 bits.
*/
#define getnn(ST, REG) ((be32toh(ST.REG) >> (31-REG##_offset)) \
& REG##_mask)
#define getpnn(ST, REG) ((be32toh((ST)->REG) >> (31-REG##_offset)) \
& REG##_mask)
#define get32(ST, REG) (be32toh(ST.REG))
#define getp32(ST, REG) (be32toh((ST)->REG))
#define get64(ST, REG) (be64toh(ST.REG))
#define getp64(ST, REG) (be64toh((ST)->REG))
#define unget32(ST, REG) (get32(ST, REG) & ~((REG##_mask) \
<< (31-REG##_offset)))
/* get 32bits less the REG field */
#define ungetp32(ST, REG) (getp32(ST, REG) & ~((REG##_mask) \
<< (31-REG##_offset)))
/* get 32bits less the REG field */
#define clear_regs(ST) memset((void *)(&(ST)), 0, sizeof(ST))
#define clear_dde(ST) do { ST.dde_count = ST.ddebc = 0; ST.ddead = 0; \
} while (0)
#define clearp_dde(ST) do { (ST)->dde_count = (ST)->ddebc = 0; \
(ST)->ddead = 0; \
} while (0)
#define clear_struct(ST) memset((void *)(&(ST)), 0, sizeof(ST))
#define putnn(ST, REG, X) (ST.REG = htobe32(unget32(ST, REG) | (((X) \
& REG##_mask) << (31-REG##_offset))))
#define putpnn(ST, REG, X) ((ST)->REG = htobe32(ungetp32(ST, REG) \
| (((X) & REG##_mask) << (31-REG##_offset))))
#define put32(ST, REG, X) (ST.REG = htobe32(X))
#define putp32(ST, REG, X) ((ST)->REG = htobe32(X))
#define put64(ST, REG, X) (ST.REG = htobe64(X))
#define putp64(ST, REG, X) ((ST)->REG = htobe64(X))
/*
* Completion extension ce(0) ce(1) ce(2). Bits ce(3-7)
* unused. Section 6.6 Figure 6.7.
*/
#define get_csb_ce(ST) ((uint32_t)getnn(ST, csb_ce))
#define get_csb_ce_ms3b(ST) (get_csb_ce(ST) >> 5)
#define put_csb_ce_ms3b(ST, X) putnn(ST, csb_ce, ((uint32_t)(X) << 5))
#define CSB_CE_PARTIAL 0x4
#define CSB_CE_TERMINATE 0x2
#define CSB_CE_TPBC_VALID 0x1
#define csb_ce_termination(X) (!!((X) & CSB_CE_TERMINATE))
/* termination, output buffers may be modified, SPBC/TPBC invalid Fig.6-7 */
#define csb_ce_check_completion(X) (!csb_ce_termination(X))
/* if not terminated then check full or partial completion */
#define csb_ce_partial_completion(X) (!!((X) & CSB_CE_PARTIAL))
#define csb_ce_full_completion(X) (!csb_ce_partial_completion(X))
#define csb_ce_tpbc_valid(X) (!!((X) & CSB_CE_TPBC_VALID))
/* TPBC indicates successfully stored data count */
#define csb_ce_default_err(X) csb_ce_termination(X)
/* most error CEs have CE(0)=0 and CE(1)=1 */
#define csb_ce_cc3_partial(X) csb_ce_partial_completion(X)
/* some CC=3 are partially completed, Table 6-8 */
#define csb_ce_cc64(X) ((X)&(CSB_CE_PARTIAL \
| CSB_CE_TERMINATE) == 0)
/* Compression: when TPBC>SPBC then CC=64 Table 6-8; target didn't
* compress smaller than source.
*/
/* Decompress SFBT combinations Tables 5-3, 6-4, 6-6 */
#define SFBT_BFINAL 0x1
#define SFBT_LIT 0x4
#define SFBT_FHT 0x5
#define SFBT_DHT 0x6
#define SFBT_HDR 0x7
/*
* NX gzip function codes. Table 6.2.
* Bits 0:4 are the FC. Bit 5 is used by the DMA controller to
* select one of the two Byte Count Limits.
*/
#define GZIP_FC_LIMIT_MASK 0x01
#define GZIP_FC_COMPRESS_FHT 0x00
#define GZIP_FC_COMPRESS_DHT 0x02
#define GZIP_FC_COMPRESS_FHT_COUNT 0x04
#define GZIP_FC_COMPRESS_DHT_COUNT 0x06
#define GZIP_FC_COMPRESS_RESUME_FHT 0x08
#define GZIP_FC_COMPRESS_RESUME_DHT 0x0a
#define GZIP_FC_COMPRESS_RESUME_FHT_COUNT 0x0c
#define GZIP_FC_COMPRESS_RESUME_DHT_COUNT 0x0e
#define GZIP_FC_DECOMPRESS 0x10
#define GZIP_FC_DECOMPRESS_SINGLE_BLK_N_SUSPEND 0x12
#define GZIP_FC_DECOMPRESS_RESUME 0x14
#define GZIP_FC_DECOMPRESS_RESUME_SINGLE_BLK_N_SUSPEND 0x16
#define GZIP_FC_WRAP 0x1e
#define fc_is_compress(fc) (((fc) & 0x10) == 0)
#define fc_has_count(fc) (fc_is_compress(fc) && (((fc) & 0x4) != 0))
/* CSB.CC Error codes */
#define ERR_NX_OK 0
#define ERR_NX_ALIGNMENT 1
#define ERR_NX_OPOVERLAP 2
#define ERR_NX_DATA_LENGTH 3
#define ERR_NX_TRANSLATION 5
#define ERR_NX_PROTECTION 6
#define ERR_NX_EXTERNAL_UE7 7
#define ERR_NX_INVALID_OP 8
#define ERR_NX_PRIVILEGE 9
#define ERR_NX_INTERNAL_UE 10
#define ERR_NX_EXTERN_UE_WR 12
#define ERR_NX_TARGET_SPACE 13
#define ERR_NX_EXCESSIVE_DDE 14
#define ERR_NX_TRANSL_WR 15
#define ERR_NX_PROTECT_WR 16
#define ERR_NX_SUBFUNCTION 17
#define ERR_NX_FUNC_ABORT 18
#define ERR_NX_BYTE_MAX 19
#define ERR_NX_CORRUPT_CRB 20
#define ERR_NX_INVALID_CRB 21
#define ERR_NX_INVALID_DDE 30
#define ERR_NX_SEGMENTED_DDL 31
#define ERR_NX_DDE_OVERFLOW 33
#define ERR_NX_TPBC_GT_SPBC 64
#define ERR_NX_MISSING_CODE 66
#define ERR_NX_INVALID_DIST 67
#define ERR_NX_INVALID_DHT 68
#define ERR_NX_EXTERNAL_UE90 90
#define ERR_NX_WDOG_TIMER 224
#define ERR_NX_AT_FAULT 250
#define ERR_NX_INTR_SERVER 252
#define ERR_NX_UE253 253
#define ERR_NX_NO_HW 254
#define ERR_NX_HUNG_OP 255
#define ERR_NX_END 256
/* initial values for non-resume operations */
#define INIT_CRC 0 /* crc32(0L, Z_NULL, 0) */
#define INIT_ADLER 1 /* adler32(0L, Z_NULL, 0) adler is initialized to 1 */
/* prototypes */
int nxu_submit_job(struct nx_gzip_crb_cpb_t *c, void *handle);
extern void nxu_sigsegv_handler(int sig, siginfo_t *info, void *ctx);
extern int nxu_touch_pages(void *buf, long buf_len, long page_len, int wr);
/* caller supplies a print buffer 4*sizeof(crb) */
char *nx_crb_str(struct nx_gzip_crb_t *crb, char *prbuf);
char *nx_cpb_str(struct nx_gzip_cpb_t *cpb, char *prbuf);
char *nx_prt_hex(void *cp, int sz, char *prbuf);
char *nx_lzcount_str(struct nx_gzip_cpb_t *cpb, char *prbuf);
char *nx_strerror(int e);
#ifdef NX_SIM
#include <stdio.h>
int nx_sim_init(void *ctx);
int nx_sim_end(void *ctx);
int nxu_run_sim_job(struct nx_gzip_crb_cpb_t *c, void *ctx);
#endif /* NX_SIM */
/* Deflate stream manipulation */
#define set_final_bit(x) (x |= (unsigned char)1)
#define clr_final_bit(x) (x &= ~(unsigned char)1)
#define append_empty_fh_blk(p, b) do { *(p) = (2 | (1&(b))); *((p)+1) = 0; \
} while (0)
/* append 10 bits 0000001b 00...... ;
* assumes appending starts on a byte boundary; b is the final bit.
*/
#ifdef NX_842
/* 842 Engine */
struct nx_eft_crb_t {
union { /* byte[0:3] */
uint32_t eft_fc; /* bits[29-31] */
};
uint32_t reserved1; /* byte[4:7] */
union {
uint64_t csb_address; /* byte[8:15] */
struct {
uint32_t reserved2;
union {
uint32_t crb_c;
/* c==0 no ccb defined */
uint32_t crb_at;
/* at==0 address type is ignored;
* all addrs effective assumed.
*/
};
};
};
struct nx_dde_t source_dde; /* byte[16:31] */
struct nx_dde_t target_dde; /* byte[32:47] */
struct nx_ccb_t ccb; /* byte[48:63] */
union {
union nx_qw_t reserved64[3]; /* byte[64:96] */
};
struct nx_csb_t csb;
} __aligned(128);
/* 842 CRB */
#define EFT_FC_MASK size_mask(3)
#define EFT_FC_OFFSET 31
#define EFT_FC_COMPRESS 0x0
#define EFT_FC_COMPRESS_WITH_CRC 0x1
#define EFT_FC_DECOMPRESS 0x2
#define EFT_FC_DECOMPRESS_WITH_CRC 0x3
#define EFT_FC_BLK_DATA_MOVE 0x4
#endif /* NX_842 */
#endif /* _NXU_H */
@@ -0,0 +1 @@
../../../../../../arch/powerpc/include/uapi/asm/vas-api.h
@@ -0,0 +1,46 @@
#!/bin/bash
# SPDX-License-Identifier: GPL-2.0-or-later
if [[ ! -w /dev/crypto/nx-gzip ]]; then
echo "Can't access /dev/crypto/nx-gzip, skipping"
echo "skip: $0"
exit 4
fi
set -e
function cleanup
{
rm -f nx-tempfile*
}
trap cleanup EXIT
function test_sizes
{
local n=$1
local fname="nx-tempfile.$n"
for size in 4K 64K 1M 64M
do
echo "Testing $size ($n) ..."
dd if=/dev/urandom of=$fname bs=$size count=1
./gzfht_test $fname
./gunz_test ${fname}.nx.gz
done
}
echo "Doing basic test of different sizes ..."
test_sizes 0
echo "Running tests in parallel ..."
for i in {1..16}
do
test_sizes $i &
done
wait
echo "OK"
exit 0
@@ -0,0 +1 @@
timeout=130