[Skiboot] [RFC 08/12] add PowerNV platform NX-842 driver

Dan Streetman ddstreet at ieee.org
Tue Mar 10 14:58:38 AEDT 2015


Add driver for NX-842 hardware on the PowerNV platform.

This allows the use of the 842 compression hardware coprocessor on
the PowerNV platform.

Signed-off-by: Dan Streetman <ddstreet at ieee.org>
---
 drivers/crypto/nx/Kconfig          |  10 +
 drivers/crypto/nx/Makefile         |   2 +
 drivers/crypto/nx/nx-842-powernv.c | 690 +++++++++++++++++++++++++++++++++++++
 drivers/crypto/nx/nx-842-pseries.c |   9 -
 drivers/crypto/nx/nx-842-xscom.h   | 265 ++++++++++++++
 drivers/crypto/nx/nx-842.c         |   4 +-
 drivers/crypto/nx/nx-842.h         |  97 ++++++
 include/linux/nx842.h              |   6 +-
 8 files changed, 1071 insertions(+), 12 deletions(-)
 create mode 100644 drivers/crypto/nx/nx-842-powernv.c
 create mode 100644 drivers/crypto/nx/nx-842-xscom.h

diff --git a/drivers/crypto/nx/Kconfig b/drivers/crypto/nx/Kconfig
index 2e99b09..894aa6c 100644
--- a/drivers/crypto/nx/Kconfig
+++ b/drivers/crypto/nx/Kconfig
@@ -35,3 +35,13 @@ config CRYPTO_DEV_NX_PSERIES_COMPRESS
 	  module supports acceleration for compressing memory with the 842
 	  algorithm.  This supports NX hardware on the pSeries platform.
 	  If you choose 'M' here, this module will be called nx_compress_pseries.
+
+config CRYPTO_DEV_NX_POWERNV_COMPRESS
+	tristate "Compression acceleration support on PowerNV platform"
+	depends on CRYPTO_DEV_NX_COMPRESS
+	default y
+	help
+	  Support for Power in-Nest compression acceleration. This
+	  module supports acceleration for compressing memory with the 842
+	  algorithm.  This supports NX hardware on the PowerNV platform.
+	  If you choose 'M' here, this module will be called nx_compress_powernv.
diff --git a/drivers/crypto/nx/Makefile b/drivers/crypto/nx/Makefile
index bc7b7ea..82221f2 100644
--- a/drivers/crypto/nx/Makefile
+++ b/drivers/crypto/nx/Makefile
@@ -12,5 +12,7 @@ nx-crypto-objs := nx.o \
 
 obj-$(CONFIG_CRYPTO_DEV_NX_COMPRESS) += nx-compress.o
 obj-$(CONFIG_CRYPTO_DEV_NX_PSERIES_COMPRESS) += nx-compress-pseries.o
+obj-$(CONFIG_CRYPTO_DEV_NX_POWERNV_COMPRESS) += nx-compress-powernv.o
 nx-compress-objs := nx-842.o
 nx-compress-pseries-objs := nx-842-pseries.o
+nx-compress-powernv-objs := nx-842-powernv.o
diff --git a/drivers/crypto/nx/nx-842-powernv.c b/drivers/crypto/nx/nx-842-powernv.c
new file mode 100644
index 0000000..3a6fbf3
--- /dev/null
+++ b/drivers/crypto/nx/nx-842-powernv.c
@@ -0,0 +1,690 @@
+/*
+ * Driver for IBM PowerNV 842 compression accelerator
+ *
+ * Copyright (C) 2015 Dan Streetman, IBM Corp
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
+#include "nx-842.h"
+#include "nx-842-xscom.h"
+
+#include <linux/timer.h>
+
+#include <asm/prom.h>
+#include <asm/icswx.h>
+
+#define MODULE_NAME NX842_POWERNV_MODULE_NAME
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Dan Streetman <ddstreet at ieee.org>");
+MODULE_DESCRIPTION("842 H/W Compression driver for IBM PowerNV processors");
+
+#define WORKMEM_ALIGN	(CRB_ALIGN)
+#define CSB_WAIT_MAX	(5000) /* ms */
+#define MONITOR_PERIOD	(jiffies + msecs_to_jiffies(500))
+
+struct nx842_workmem {
+	/* Below fields must be properly aligned */
+	struct coprocessor_request_block crb; /* CRB_ALIGN align */
+	struct data_descriptor_entry ddl_in[DDL_LEN_MAX]; /* DDE_ALIGN align */
+	struct data_descriptor_entry ddl_out[DDL_LEN_MAX]; /* DDE_ALIGN align */
+	/* Above fields must be properly aligned */
+
+	ktime_t start;
+
+	char padding[WORKMEM_ALIGN]; /* unused, to allow alignment */
+} __packed __aligned(WORKMEM_ALIGN);
+
+struct nx842_coproc {
+	unsigned int chip_id;
+	unsigned int ct;
+	unsigned int ci;
+	struct list_head list;
+};
+
+/* no cpu hotplug on powernv, so this list never changes after init */
+static LIST_HEAD(nx842_coprocs);
+static unsigned int nx842_ct;
+
+static void monitor_coprocs(unsigned long ignore);
+static DEFINE_TIMER(nx842_monitor, monitor_coprocs, 0, 0);
+
+static void check_coproc_channel(struct nx842_coproc *coproc,
+				 unsigned int channel)
+{
+	unsigned int gcid = coproc->chip_id;
+	uint64_t val;
+
+	/*
+	 * NX workbook section 5.3 "Channel Abort"
+	 *
+	 * The valid bit must be set by software to start monitoring
+	 * the channel.  The next read of the valid bit will indicate
+	 * if the channel is active or not.  When the channel request
+	 * completes, the valid bit will be cleared.  The bit will
+	 * not be set by hardware, so software must set it again
+	 * to continue monitoring the channel.
+	 */
+	if (xscom_write_ch_status_valid(gcid, channel))
+		return; /* error writing register */
+
+	if (xscom_read_ch_status_valid(gcid, channel, &val))
+		return; /* error reading register */
+
+	/* TODO - monitor for channel hang */
+}
+
+static void check_coproc(struct nx842_coproc *coproc)
+{
+	unsigned int gcid = coproc->chip_id;
+	uint64_t fir;
+
+	if (xscom_read_engine_fir(gcid, &fir))
+		return;
+
+	if (fir) {
+		pr_err_ratelimited("chip %u DMA_ENGINE_FIR_DATA 0x%lx\n",
+				   gcid, (unsigned long)fir);
+
+		/* TODO - recover from FIR error */
+		pr_err_ratelimited("please implement FIR recovery...\n");
+
+		/* clear FIR error bits */
+		xscom_clear_engine_fir(gcid, fir);
+	}
+
+	/* 842 uses only channels 0 and 1 */
+	check_coproc_channel(coproc, 0);
+	check_coproc_channel(coproc, 1);
+}
+
+static void monitor_coprocs(unsigned long ignore)
+{
+	struct nx842_coproc *c;
+
+	list_for_each_entry(c, &nx842_coprocs, list)
+		check_coproc(c);
+
+	mod_timer(&nx842_monitor, MONITOR_PERIOD);
+}
+
+/**
+ * setup_indirect_dde - Setup an indirect DDE
+ *
+ * The DDE is setup with the the DDE count, byte count, and address of
+ * first direct DDE in the list.
+ */
+static void setup_indirect_dde(struct data_descriptor_entry *dde,
+			struct data_descriptor_entry *ddl,
+			unsigned int dde_count, unsigned int byte_count)
+{
+	dde->flags = 0;
+	dde->count = dde_count;
+	dde->index = 0;
+	dde->length = cpu_to_be32(byte_count);
+	dde->address = cpu_to_be64(nx842_get_pa(ddl));
+}
+
+/**
+ * setup_direct_dde - Setup single DDE from buffer
+ *
+ * The DDE is setup with the buffer and length.  The buffer must be properly
+ * aligned.  The used length is returned.
+ * Returns:
+ *   N    Successfully set up DDE with N bytes
+ */
+static unsigned int setup_direct_dde(struct data_descriptor_entry *dde,
+			unsigned long pa, unsigned int len)
+{
+	unsigned int l = min_t(unsigned int, len, LEN_ON_PAGE(pa));
+
+	dde->flags = 0;
+	dde->count = 0;
+	dde->index = 0;
+	dde->length = cpu_to_be32(l);
+	dde->address = cpu_to_be64(pa);
+
+	return l;
+}
+
+/**
+ * setup_ddl - Setup DDL from buffer
+ *
+ * Returns:
+ *   0		Successfully set up DDL
+ */
+static int setup_ddl(struct data_descriptor_entry *dde,
+			struct data_descriptor_entry *ddl,
+			unsigned char *buf, unsigned int len,
+			bool in)
+{
+	unsigned long pa = nx842_get_pa(buf);
+	int i, ret, total_len = len;
+
+	if (!IS_ALIGNED(pa, DDE_BUFFER_ALIGN)) {
+		pr_debug("%s buffer pa 0x%lx not 0x%x-byte aligned\n",
+			 in ? "input" : "output", pa, DDE_BUFFER_ALIGN);
+		return -EINVAL;
+	}
+
+	/* only need to check last mult; since buffer must be
+	 * DDE_BUFFER_ALIGN aligned, and that is a multiple of
+	 * DDE_BUFFER_SIZE_MULT, and pre-last page DDE buffers
+	 * are guaranteed a multiple of DDE_BUFFER_SIZE_MULT.
+	 */
+	if (len % DDE_BUFFER_LAST_MULT) {
+		pr_debug("%s buffer len 0x%x not a multiple of 0x%x\n",
+			 in ? "input" : "output", len, DDE_BUFFER_LAST_MULT);
+		if (in)
+			return -EINVAL;
+		len = round_down(len, DDE_BUFFER_LAST_MULT);
+	}
+
+	/* use a single direct DDE */
+	if (len <= LEN_ON_PAGE(pa)) {
+		ret = setup_direct_dde(dde, pa, len);
+		WARN_ON(ret < len);
+		return 0;
+	}
+
+	/* use the DDL */
+	for (i = 0; i < DDL_LEN_MAX && len > 0; i++) {
+		ret = setup_direct_dde(&ddl[i], pa, len);
+		buf += ret;
+		len -= ret;
+		pa = nx842_get_pa(buf);
+	}
+
+	if (len > 0) {
+		pr_debug("0x%x total %s bytes 0x%x too many for DDL.\n",
+			 total_len, in ? "input" : "output", len);
+		if (in)
+			return -EMSGSIZE;
+		total_len -= len;
+	}
+	setup_indirect_dde(dde, ddl, i, total_len);
+
+	return 0;
+}
+
+#define CSB_ERR(csb, msg, ...)					\
+	pr_err("ERROR: " msg " : %02x %02x %02x %02x %08x\n",	\
+	       ##__VA_ARGS__, (csb)->flags,			\
+	       (csb)->cs, (csb)->cc, (csb)->ce,			\
+	       be32_to_cpu((csb)->count))
+
+#define CSB_ERR_ADDR(csb, msg, ...)				\
+	CSB_ERR(csb, msg " at %lx", ##__VA_ARGS__,		\
+		(unsigned long)be64_to_cpu((csb)->address))
+
+/**
+ * wait_for_csb
+ */
+static int wait_for_csb(struct nx842_workmem *wmem,
+			struct coprocessor_status_block *csb)
+{
+	ktime_t start = wmem->start, now = ktime_get();
+	ktime_t timeout = ktime_add_ms(start, CSB_WAIT_MAX);
+
+	while (!(ACCESS_ONCE(csb->flags) & CSB_V)) {
+		cpu_relax();
+		now = ktime_get();
+		if (ktime_after(now, timeout))
+			break;
+	}
+
+	/* hw has updated csb and output buffer */
+	barrier();
+
+	/* check CSB flags */
+	if (!(csb->flags & CSB_V)) {
+		CSB_ERR(csb, "CSB still not valid after %ld us, giving up",
+			(long)ktime_us_delta(now, start));
+		return -ETIMEDOUT;
+	}
+	if (csb->flags & CSB_F) {
+		CSB_ERR(csb, "Invalid CSB format");
+		return -EPROTO;
+	}
+	if (csb->flags & CSB_CH) {
+		CSB_ERR(csb, "Invalid CSB chaining state");
+		return -EPROTO;
+	}
+
+	/* verify CSB completion sequence is 0 */
+	if (csb->cs) {
+		CSB_ERR(csb, "Invalid CSB completion sequence");
+		return -EPROTO;
+	}
+
+	/* check CSB Completion Code */
+	switch (csb->cc) {
+	/* no error */
+	case CSB_CC_SUCCESS:
+		break;
+	case CSB_CC_TPBC_GT_SPBC:
+		/* not an error, but the compressed data is
+		 * larger than the uncompressed data :(
+		 */
+		break;
+
+	/* input data errors */
+	case CSB_CC_OPERAND_OVERLAP:
+		/* input and output buffers overlap */
+		CSB_ERR(csb, "Operand Overlap error");
+		return -EINVAL;
+	case CSB_CC_INVALID_OPERAND:
+		CSB_ERR(csb, "Invalid operand");
+		return -EINVAL;
+	case CSB_CC_NOSPC:
+		/* output buffer too small */
+		return -ENOSPC;
+	case CSB_CC_ABORT:
+		CSB_ERR(csb, "Function aborted");
+		return -EINTR;
+	case CSB_CC_CRC_MISMATCH:
+		CSB_ERR(csb, "CRC mismatch");
+		return -EINVAL;
+	case CSB_CC_TEMPL_INVALID:
+		CSB_ERR(csb, "Compressed data template invalid");
+		return -EINVAL;
+	case CSB_CC_TEMPL_OVERFLOW:
+		CSB_ERR(csb, "Compressed data template shows data past end");
+		return -EINVAL;
+
+	/* these should not happen */
+	case CSB_CC_INVALID_ALIGN:
+		/* setup_ddl should have detected this */
+		CSB_ERR_ADDR(csb, "Invalid alignment");
+		return -EINVAL;
+	case CSB_CC_DATA_LENGTH:
+		/* setup_ddl should have detected this */
+		CSB_ERR(csb, "Invalid data length");
+		return -EINVAL;
+	case CSB_CC_WR_TRANSLATION:
+	case CSB_CC_TRANSLATION:
+	case CSB_CC_TRANSLATION_DUP1:
+	case CSB_CC_TRANSLATION_DUP2:
+	case CSB_CC_TRANSLATION_DUP3:
+	case CSB_CC_TRANSLATION_DUP4:
+	case CSB_CC_TRANSLATION_DUP5:
+	case CSB_CC_TRANSLATION_DUP6:
+		/* should not happen, we use physical addrs */
+		CSB_ERR_ADDR(csb, "Translation error");
+		return -EPROTO;
+	case CSB_CC_WR_PROTECTION:
+	case CSB_CC_PROTECTION:
+	case CSB_CC_PROTECTION_DUP1:
+	case CSB_CC_PROTECTION_DUP2:
+	case CSB_CC_PROTECTION_DUP3:
+	case CSB_CC_PROTECTION_DUP4:
+	case CSB_CC_PROTECTION_DUP5:
+	case CSB_CC_PROTECTION_DUP6:
+		/* should not happen, we use physical addrs */
+		CSB_ERR_ADDR(csb, "Protection error");
+		return -EPROTO;
+	case CSB_CC_PRIVILEGE:
+		/* shouldn't happen, we're in HYP mode */
+		CSB_ERR(csb, "Insufficient Privilege error");
+		return -EPROTO;
+	case CSB_CC_EXCESSIVE_DDE:
+		/* shouldn't happen, setup_ddl doesn't use many dde's */
+		CSB_ERR(csb, "Too many DDEs in DDL");
+		return -EINVAL;
+	case CSB_CC_TRANSPORT:
+		/* shouldn't happen, we setup CRB correctly */
+		CSB_ERR(csb, "Invalid CRB");
+		return -EINVAL;
+	case CSB_CC_SEGMENTED_DDL:
+		/* shouldn't happen, setup_ddl creates DDL right */
+		CSB_ERR(csb, "Segmented DDL error");
+		return -EINVAL;
+	case CSB_CC_DDE_OVERFLOW:
+		/* shouldn't happen, setup_ddl creates DDL right */
+		CSB_ERR(csb, "DDE overflow error");
+		return -EINVAL;
+	case CSB_CC_SESSION:
+		/* should not happen with ICSWX */
+		CSB_ERR(csb, "Session violation error");
+		return -EPROTO;
+	case CSB_CC_CHAIN:
+		/* should not happen, we don't use chained CRBs */
+		CSB_ERR(csb, "Chained CRB error");
+		return -EPROTO;
+	case CSB_CC_SEQUENCE:
+		/* should not happen, we don't use chained CRBs */
+		CSB_ERR(csb, "CRB seqeunce number error");
+		return -EPROTO;
+	case CSB_CC_UNKNOWN_CODE:
+		CSB_ERR(csb, "Unknown subfunction code");
+		return -EPROTO;
+
+	/* hardware errors */
+	case CSB_CC_RD_EXTERNAL:
+	case CSB_CC_RD_EXTERNAL_DUP1:
+	case CSB_CC_RD_EXTERNAL_DUP2:
+	case CSB_CC_RD_EXTERNAL_DUP3:
+		CSB_ERR_ADDR(csb, "Read error outside coprocessor");
+		return -EPROTO;
+	case CSB_CC_WR_EXTERNAL:
+		CSB_ERR_ADDR(csb, "Write error outside coprocessor");
+		return -EPROTO;
+	case CSB_CC_INTERNAL:
+		CSB_ERR(csb, "Internal error in coprocessor");
+		return -EPROTO;
+	case CSB_CC_PROVISION:
+		CSB_ERR(csb, "Storage provision error");
+		return -EPROTO;
+	case CSB_CC_HW:
+		CSB_ERR(csb, "Correctable hardware error");
+		return -EPROTO;
+
+	default:
+		CSB_ERR(csb, "Invalid CC %d", csb->cc);
+		return -EPROTO;
+	}
+
+	/* check Completion Extension state */
+	if (csb->ce & CSB_CE_TERMINATION) {
+		CSB_ERR(csb, "CSB request was terminated");
+		return -EPROTO;
+	}
+	if (csb->ce & CSB_CE_INCOMPLETE) {
+		CSB_ERR(csb, "CSB request not complete");
+		return -EPROTO;
+	}
+	if (!(csb->ce & CSB_CE_TPBC)) {
+		CSB_ERR(csb, "TPBC not provided, unknown target length");
+		return -EPROTO;
+	}
+
+	/* successful completion */
+	pr_debug_ratelimited("Processed %u bytes in %lu us\n", csb->count,
+			     (unsigned long)ktime_us_delta(now, start));
+
+	return 0;
+}
+
+/**
+ * nx842_powernv_function - compress/decompress data using the 842 algorithm
+ *
+ * (De)compression provided by the NX842 coprocessor on IBM PowerNV systems.
+ * This compresses or decompresses the provided input buffer into the provided
+ * output buffer.
+ *
+ * Upon return from this function @outlen contains the length of the
+ * output data.  If there is an error then @outlen will be 0 and an
+ * error will be specified by the return code from this function.
+ *
+ * The @workmem buffer should only be used by one function call at a time.
+ *
+ * @in: input buffer pointer
+ * @inlen: input buffer size
+ * @out: output buffer pointer
+ * @outlenp: output buffer size pointer
+ * @workmem: working memory buffer pointer, must be at least NX842_MEM_COMPRESS
+ * @fc: function code, see CCW Function Codes in nx-842.h
+ *
+ * Returns:
+ *   0		Success, output of length @outlenp stored in the buffer at @out
+ *   -ENODEV	Hardware unavailable
+ *   -ENOSPC	Output buffer is to small
+ *   -EMSGSIZE	Input buffer too large
+ *   -EINVAL	buffer constraints do not fix nx842_constraints
+ *   -EPROTO	hardware error during operation
+ *   -ETIMEDOUT	hardware did not complete operation in reasonable time
+ *   -EINTR	operation was aborted
+ */
+static int nx842_powernv_function(const unsigned char *in, unsigned int inlen,
+			unsigned char *out, unsigned int *outlenp,
+			void *workmem, int fc)
+{
+	struct coprocessor_request_block *crb;
+	struct coprocessor_status_block *csb;
+	struct nx842_workmem *wmem;
+	int ret;
+	u64 csb_addr;
+	u32 ccw;
+	unsigned int outlen = *outlenp;
+
+	wmem = PTR_ALIGN(workmem, WORKMEM_ALIGN);
+
+	*outlenp = 0;
+
+	/* shoudn't happen, we don't load without a coproc */
+	if (!nx842_ct) {
+		pr_err_ratelimited("coprocessor CT is 0");
+		return -ENODEV;
+	}
+
+	crb = &wmem->crb;
+	csb = &crb->csb;
+
+	/* Clear any previous values */
+	memset(crb, 0, sizeof(*crb));
+
+	/* set up DDLs */
+	ret = setup_ddl(&crb->source, wmem->ddl_in,
+			(unsigned char *)in, inlen, true);
+	if (ret)
+		return ret;
+	ret = setup_ddl(&crb->target, wmem->ddl_out,
+			out, outlen, false);
+	if (ret)
+		return ret;
+
+	/* set up CCW */
+	ccw = 0;
+	ccw = SET_FIELD(ccw, CCW_CT, nx842_ct);
+	ccw = SET_FIELD(ccw, CCW_CI_842, 0); /* use 0 for hw auto-selection */
+	ccw = SET_FIELD(ccw, CCW_FC_842, fc);
+
+	/* set up CRB's CSB addr */
+	csb_addr = nx842_get_pa(csb) & CRB_CSB_ADDRESS;
+	csb_addr |= CRB_CSB_AT; /* Addrs are phys */
+	crb->csb_addr = cpu_to_be64(csb_addr);
+
+	wmem->start = ktime_get();
+
+	/* do ICSWX */
+	ret = icswx(cpu_to_be32(ccw), crb);
+
+	pr_debug_ratelimited("icswx CR %x ccw %x crb->ccw %x\n", ret,
+			     (unsigned int)ccw,
+			     (unsigned int)be32_to_cpu(crb->ccw));
+
+	switch (ret) {
+	case ICSWX_INITIATED:
+		ret = wait_for_csb(wmem, csb);
+		break;
+	case ICSWX_BUSY:
+		pr_debug_ratelimited("842 Coprocessor busy\n");
+		ret = -EBUSY;
+		break;
+	case ICSWX_REJECTED:
+		pr_err_ratelimited("ICSWX rejected\n");
+		ret = -EPROTO;
+		break;
+	default:
+		pr_err_ratelimited("Invalid ICSWX return code %x\n", ret);
+		ret = -EPROTO;
+		break;
+	}
+
+	if (!ret)
+		*outlenp = be32_to_cpu(csb->count);
+
+	return ret;
+}
+
+/**
+ * nx842_powernv_compress - Compress data using the 842 algorithm
+ *
+ * Compression provided by the NX842 coprocessor on IBM PowerNV systems.
+ * The input buffer is compressed and the result is stored in the
+ * provided output buffer.
+ *
+ * Upon return from this function @outlen contains the length of the
+ * compressed data.  If there is an error then @outlen will be 0 and an
+ * error will be specified by the return code from this function.
+ *
+ * @in: input buffer pointer
+ * @inlen: input buffer size
+ * @out: output buffer pointer
+ * @outlenp: output buffer size pointer
+ * @workmem: working memory buffer pointer, must be at least NX842_MEM_COMPRESS
+ *
+ * Returns: see @nx842_powernv_function()
+ */
+static int nx842_powernv_compress(const unsigned char *in, unsigned int inlen,
+		       unsigned char *out, unsigned int *outlenp, void *wmem)
+{
+	return nx842_powernv_function(in, inlen, out, outlenp,
+				      wmem, CCW_FC_842_COMP_NOCRC);
+}
+
+/**
+ * nx842_powernv_decompress - Decompress data using the 842 algorithm
+ *
+ * Decompression provided by the NX842 coprocessor on IBM PowerNV systems.
+ * The input buffer is decompressed and the result is stored in the
+ * provided output buffer.
+ *
+ * Upon return from this function @outlen contains the length of the
+ * decompressed data.  If there is an error then @outlen will be 0 and an
+ * error will be specified by the return code from this function.
+ *
+ * @in: input buffer pointer
+ * @inlen: input buffer size
+ * @out: output buffer pointer
+ * @outlenp: output buffer size pointer
+ * @workmem: working memory buffer pointer, must be at least NX842_MEM_COMPRESS
+ *
+ * Returns: see @nx842_powernv_function()
+ */
+static int nx842_powernv_decompress(const unsigned char *in, unsigned int inlen,
+			 unsigned char *out, unsigned int *outlenp, void *wmem)
+{
+	return nx842_powernv_function(in, inlen, out, outlenp,
+				      wmem, CCW_FC_842_DECOMP_NOCRC);
+}
+
+static int __init nx842_powernv_probe(struct device_node *dn)
+{
+	struct nx842_coproc *coproc = kmalloc(sizeof(*coproc), GFP_KERNEL);
+	struct property *ct_prop, *ci_prop;
+	unsigned int ct, ci;
+	int chip_id;
+
+	if (!coproc)
+		return -ENOMEM;
+
+	chip_id = of_get_ibm_chip_id(dn);
+	if (chip_id < 0) {
+		pr_err("ibm,chip-id missing\n");
+		return -EINVAL;
+	}
+	ct_prop = of_find_property(dn, "ibm,coprocessor-type", NULL);
+	if (!ct_prop) {
+		pr_err("ibm,coprocessor-type missing\n");
+		return -EINVAL;
+	}
+	ct = be32_to_cpu(*(unsigned int *)ct_prop->value);
+	ci_prop = of_find_property(dn, "ibm,coprocessor-instance", NULL);
+	if (!ci_prop) {
+		pr_err("ibm,coprocessor-instance missing\n");
+		return -EINVAL;
+	}
+	ci = be32_to_cpu(*(unsigned int *)ci_prop->value);
+
+	coproc->chip_id = chip_id;
+	coproc->ct = ct;
+	coproc->ci = ci;
+	INIT_LIST_HEAD(&coproc->list);
+	list_add(&coproc->list, &nx842_coprocs);
+
+	pr_info("coprocessor found on chip %d, CT %d CI %d\n", chip_id, ct, ci);
+
+	if (!nx842_ct)
+		nx842_ct = ct;
+	else if (nx842_ct != ct)
+		pr_err("NX842 chip %d, CT %d != first found CT %d\n",
+		       chip_id, ct, nx842_ct);
+
+	return 0;
+}
+
+static struct nx842_constraints nx842_powernv_constraints = {
+	.alignment =	DDE_BUFFER_ALIGN,
+	.multiple =	DDE_BUFFER_LAST_MULT,
+	.minimum =	DDE_BUFFER_LAST_MULT,
+	.maximum =	(DDL_LEN_MAX - 1) * PAGE_SIZE,
+};
+
+static struct nx842_driver nx842_powernv_driver = {
+	.owner =	THIS_MODULE,
+	.constraints =	&nx842_powernv_constraints,
+	.compress =	nx842_powernv_compress,
+	.decompress =	nx842_powernv_decompress,
+};
+
+static __init int nx842_powernv_init(void)
+{
+	struct device_node *dn;
+
+	/* verify workmem size/align restrictions */
+	BUILD_BUG_ON(sizeof(struct nx842_workmem) > NX842_MEM_COMPRESS);
+	BUILD_BUG_ON(WORKMEM_ALIGN % CRB_ALIGN);
+	BUILD_BUG_ON(CRB_ALIGN % DDE_ALIGN);
+	BUILD_BUG_ON(CRB_SIZE % DDE_ALIGN);
+	/* verify buffer size/align restrictions */
+	BUILD_BUG_ON(PAGE_SIZE % DDE_BUFFER_ALIGN);
+	BUILD_BUG_ON(DDE_BUFFER_ALIGN % DDE_BUFFER_SIZE_MULT);
+	BUILD_BUG_ON(DDE_BUFFER_SIZE_MULT % DDE_BUFFER_LAST_MULT);
+
+	pr_info("loading\n");
+
+	for_each_compatible_node(dn, NULL, NX842_POWERNV_COMPAT_NAME)
+		nx842_powernv_probe(dn);
+
+	if (!nx842_ct) {
+		pr_err("no coprocessors found\n");
+		return -ENODEV;
+	}
+
+	mod_timer(&nx842_monitor, MONITOR_PERIOD);
+
+	nx842_register_driver(&nx842_powernv_driver);
+
+	pr_info("loaded\n");
+
+	return 0;
+}
+module_init(nx842_powernv_init);
+
+static void __exit nx842_powernv_exit(void)
+{
+	struct nx842_coproc *coproc, *n;
+
+	nx842_unregister_driver(&nx842_powernv_driver);
+
+	del_timer(&nx842_monitor);
+
+	list_for_each_entry_safe(coproc, n, &nx842_coprocs, list) {
+		list_del(&coproc->list);
+		kfree(coproc);
+	}
+
+	pr_info("unloaded\n");
+}
+module_exit(nx842_powernv_exit);
diff --git a/drivers/crypto/nx/nx-842-pseries.c b/drivers/crypto/nx/nx-842-pseries.c
index baa2e52..3773e36 100644
--- a/drivers/crypto/nx/nx-842-pseries.c
+++ b/drivers/crypto/nx/nx-842-pseries.c
@@ -160,15 +160,6 @@ static inline unsigned long nx842_get_scatterlist_size(
 	return sl->entry_nr * sizeof(struct nx842_slentry);
 }
 
-static inline unsigned long nx842_get_pa(void *addr)
-{
-	if (is_vmalloc_addr(addr))
-		return page_to_phys(vmalloc_to_page(addr))
-		       + offset_in_page(addr);
-	else
-		return __pa(addr);
-}
-
 static int nx842_build_scatterlist(unsigned long buf, int len,
 			struct nx842_scatterlist *sl)
 {
diff --git a/drivers/crypto/nx/nx-842-xscom.h b/drivers/crypto/nx/nx-842-xscom.h
new file mode 100644
index 0000000..8e38fc1
--- /dev/null
+++ b/drivers/crypto/nx/nx-842-xscom.h
@@ -0,0 +1,265 @@
+
+#ifndef __NX_842_XSCOM_H__
+#define __NX_842_XSCOM_H__
+
+#include <asm/opal.h>
+
+/* TODO - add P7+ support, regs are different */
+
+/* XSCOM register addresses for NX Coprocessor
+ * NX P8 workbook, section 5.1, table 5.1
+ */
+/* Engine Status/Enables and DMA Configuration */
+#define NX_STATUS			(0x02013040)
+#define NX_ENGINE_ENABLE		(0x02013041)
+#define NX_DMA_CONF			(0x02013042)
+/* Abort and Kill */
+#define NX_CH0_ABORT_CSB		(0x02013043)
+#define NX_CH0_ABORT_STATUS		(0x02013044)
+#define NX_CH1_ABORT_CSB		(0x02013045)
+#define NX_CH1_ABORT_STATUS		(0x02013046)
+#define NX_CH2_ABORT_CSB		(0x02013047)
+#define NX_CH2_ABORT_STATUS		(0x02013048)
+#define NX_CH3_ABORT_CSB		(0x02013049)
+#define NX_CH3_ABORT_STATUS		(0x0201304A)
+#define NX_CH4_ABORT_CSB		(0x0201304B)
+#define NX_CH4_ABORT_STATUS		(0x0201304C)
+#define NX_CH5_ABORT_CSB		(0x0201304D)
+#define NX_CH5_ABORT_STATUS		(0x0201304E)
+#define NX_CH6_ABORT_CSB		(0x0201304F)
+#define NX_CH6_ABORT_STATUS		(0x02013050)
+#define NX_CH7_ABORT_CSB		(0x02013051)
+#define NX_CH7_ABORT_STATUS		(0x02013052)
+#define NX_CRB_KILL			(0x02013053)
+/* Engine and Interrupt Configuration */
+#define NX_SYM_CONF			(0x0201308A)
+#define NX_ASYM_CONF			(0x0201308B)
+#define NX_842_CONF			(0x0201308C)
+#define NX_ICS_LITE_CONF		(0x02013093)
+/* PowerBus Interface Configuration */
+#define NX_CRB_INPUT_QUEUE_CONF		(0x0201308F)
+#define NX_MISC_CONF			(0x020130A8)
+/* DMA and Engine FIR */
+#define NX_DMA_ENGINE_FIR_DATA		(0x02013100)
+#define NX_DMA_ENGINE_FIR_DATA_CLEAR	(0x02013101)
+#define NX_DMA_ENGINE_FIR_DATA_SET	(0x02013102)
+#define NX_DMA_ENGINE_FIR_MASK		(0x02013103)
+#define NX_DMA_ENGINE_FIR_MASK_CLEAR	(0x02013104)
+#define NX_DMA_ENGINE_FIR_MASK_SET	(0x02013105)
+#define NX_DMA_ENGINE_FIR_ACTION0	(0x02013106)
+#define NX_DMA_ENGINE_FIR_ACTION1	(0x02013107)
+#define NX_DMA_ENGINE_FIR_WOF		(0x02013108)
+/* PowerBus Interface FIR */
+#define NX_POWERBUS_FIR_DATA		(0x02013080)
+#define NX_POWERBUS_FIR_DATA_CLEAR	(0x02013081)
+#define NX_POWERBUS_FIR_DATA_SET	(0x02013082)
+#define NX_POWERBUS_FIR_MASK		(0x02013083)
+#define NX_POWERBUS_FIR_MASK_CLEAR	(0x02013084)
+#define NX_POWERBUS_FIR_MASK_SET	(0x02013085)
+#define NX_POWERBUS_FIR_ACTION0		(0x02013086)
+#define NX_POWERBUS_FIR_ACTION1		(0x02013087)
+#define NX_POWERBUS_FIR_WOF		(0x02013088)
+/* Debug Facilities */
+#define NX_DEBUG_MUX_CTRL		(0x0201310A)
+#define NX_DEBUG_TRIGGER_CTRL		(0x0201310B)
+#define NX_DMA_ENGINE_ERROR_INJ_CTRL	(0x0201310C)
+#define NX_TRACE_DEBUG_MACRO_STATUS	(0x0201310D)
+#define NX_POWERBUS_DEBUG_MUX_CTRL	(0x02013090)
+#define NX_POWERBUS_ERROR_INJ_CTRL	(0x02013091)
+#define NX_DEBUG_BUS_READ_HIGH		(0x020130A4)
+#define NX_DEBUG_BUS_READ_LOW		(0x020130A5)
+#define NX_DMA_ERROR_REPORT0		(0x02013057)
+#define NX_DMA_ERROR_REPORT1		(0x02013058)
+#define NX_POWERBUS_ERROR_REPORT0	(0x020130A2)
+#define NX_POWERBUS_ERROR_REPORT1	(0x020130A3)
+/* Performance Monitor */
+#define NX_PERF_MONITOR_CTRL0		(0x02013054)
+#define NX_PERF_MONITOR_CTRL1		(0x02013055)
+#define NX_PMU_CTRL			(0x020130A6)
+#define NX_PMU_COUNTERS			(0x020130A7)
+/* Marker Trace */
+#define NX_MARKER_TRACE_CTRL		(0x02013056)
+
+
+static inline int64_t __xscom_read(uint32_t gcid, uint64_t reg, uint64_t *val,
+			char *name)
+{
+	int64_t ret;
+	__be64 v;
+
+	ret = opal_xscom_read(gcid, reg, &v);
+	if (unlikely(ret))
+		pr_err("chip %u %s read failed %ld\n", gcid, name, (long)ret);
+	*val = be64_to_cpu(v);
+	return ret;
+}
+
+static inline int64_t __xscom_write(uint32_t gcid, uint64_t reg, uint64_t val,
+			char *name)
+{
+	int64_t ret;
+
+	ret = opal_xscom_write(gcid, reg, val);
+	if (unlikely(ret))
+		pr_err("chip %u %s write failed %ld\n", gcid, name, (long)ret);
+	return ret;
+}
+
+#define xscom_read(gcid, reg, val)	\
+	__xscom_read((gcid), (reg), (val), #reg)
+
+#define xscom_write(gcid, reg, val)	\
+	__xscom_write((gcid), (reg), (val), #reg)
+
+#define xscom_debug(gcid, reg)	do {				\
+	uint64_t val;						\
+	if (!xscom_read((gcid), (reg), &val))			\
+		pr_debug("chip %u " #reg " %lx\n", gcid, val);	\
+} while (0)
+
+static inline int xscom_read_field(uint32_t gcid, uint64_t reg, uint64_t *val,
+			unsigned int mask)
+{
+	if (xscom_read(gcid, reg, val))
+		return -1;
+
+	*val = *val & mask;
+	return 0;
+}
+
+
+/* Channel Status and Abort controls
+ * NX P8 workbook, section 5.3.2
+ * "Channel 0-7 Abort Status Register"
+ */
+#define NX_CH_ABORT_STATUS_ABORT	(0x8000000000000000)
+#define NX_CH_ABORT_STATUS_CCB_VALID	(0x0800000000000000)
+#define NX_CH_ABORT_STATUS_CM		(0x0700000000000000)
+#define NX_CH_ABORT_STATUS_PRIORITY	(0x00ff000000000000)
+#define NX_CH_ABORT_STATUS_SERVER_NUM	(0x0000ffff00000000)
+#define NX_CH_ABORT_STATUS_VALID	(0x0000000080000000)
+#define NX_CH_ABORT_STATUS_LPID		(0x0000000003ff0000)
+#define NX_CH_ABORT_STATUS_INT_SRC_NUM	(0x0000000000003fff)
+#define NX_CH_ABORT_STATUS_SJT		(0x0000000000003fff)
+
+
+static inline uint64_t __xscom_ch_status(int ch)
+{
+	switch (ch) {
+	case 0:
+		return NX_CH0_ABORT_STATUS;
+	case 1:
+		return NX_CH1_ABORT_STATUS;
+	case 2:
+		return NX_CH2_ABORT_STATUS;
+	case 3:
+		return NX_CH3_ABORT_STATUS;
+	case 4:
+		return NX_CH4_ABORT_STATUS;
+	case 5:
+		return NX_CH5_ABORT_STATUS;
+	case 6:
+		return NX_CH6_ABORT_STATUS;
+	case 7:
+		return NX_CH7_ABORT_STATUS;
+	default:
+		BUG();
+		return -1;
+	}
+}
+
+#define xscom_read_ch_status(gcid, ch, val)			\
+	xscom_read((gcid), __xscom_ch_status(ch), (val))
+#define xscom_write_ch_status(gcid, ch, val)			\
+	xscom_write((gcid), __xscom_ch_status(ch), (val))
+
+#define xscom_read_ch_status_valid(gcid, ch, val)		\
+	xscom_read_field((gcid), __xscom_ch_status(ch), (val),	\
+		NX_CH_ABORT_STATUS_VALID)
+#define xscom_write_ch_status_valid(gcid, ch)			\
+	xscom_write((gcid), __xscom_ch_status(ch),		\
+		NX_CH_ABORT_STATUS_VALID)
+
+
+/* DMA and Engine FIR
+ * NX P8 workbook, section 5.10.1
+ * "DMA & Engine FIR Data Register"
+ */
+#define NX_ENGINE_FIR_SHM_INVALID_STATE		(0x4000000000000000)
+#define NX_ENGINE_FIR_CH0_ECC_CE		(0x0800000000000000)
+#define NX_ENGINE_FIR_CH0_ECC_UE		(0x0400000000000000)
+#define NX_ENGINE_FIR_CH1_ECC_CE		(0x0200000000000000)
+#define NX_ENGINE_FIR_CH1_ECC_UE		(0x0100000000000000)
+#define NX_ENGINE_FIR_DMA_NONZERO_CSB_CC	(0x0080000000000000)
+#define NX_ENGINE_FIR_DMA_ARRAY_ECC_CE		(0x0040000000000000)
+#define NX_ENGINE_FIR_DMA_RW_ECC_CE		(0x0020000000000000)
+#define NX_ENGINE_FIR_CH5_ECC_CE		(0x0010000000000000)
+#define NX_ENGINE_FIR_CH6_ECC_CE		(0x0008000000000000)
+#define NX_ENGINE_FIR_CH7_ECC_CE		(0x0004000000000000)
+#define NX_ENGINE_FIR_FROM_OTHER_SCOM		(0x0002000000000000)
+#define NX_ENGINE_FIR_DMA_INVALID_STATE		(0x0001800000000000)
+#define NX_ENGINE_FIR_DMA_INVALID_STATE1	(0x0001000000000000)
+#define NX_ENGINE_FIR_DMA_INVALID_STATE2	(0x0000800000000000)
+#define NX_ENGINE_FIR_DMA_ARRAY_ECC_UE		(0x0000400000000000)
+#define NX_ENGINE_FIR_DMA_RW_ECC_UE		(0x0000200000000000)
+#define NX_ENGINE_FIR_DMA_RD_DONE		(0x0000100000000000)
+#define NX_ENGINE_FIR_CH0_INVALID_STATE		(0x0000800000000000)
+#define NX_ENGINE_FIR_CH1_INVALID_STATE		(0x0000400000000000)
+#define NX_ENGINE_FIR_CH2_INVALID_STATE		(0x0000200000000000)
+#define NX_ENGINE_FIR_CH3_INVALID_STATE		(0x0000100000000000)
+#define NX_ENGINE_FIR_CH4_INVALID_STATE		(0x0000080000000000)
+#define NX_ENGINE_FIR_CH5_INVALID_STATE		(0x0000040000000000)
+#define NX_ENGINE_FIR_CH6_INVALID_STATE		(0x0000020000000000)
+#define NX_ENGINE_FIR_CH7_INVALID_STATE		(0x0000010000000000)
+#define NX_ENGINE_FIR_CH5_ECC_UE		(0x0000008000000000)
+#define NX_ENGINE_FIR_CH6_ECC_UE		(0x0000004000000000)
+#define NX_ENGINE_FIR_CH7_ECC_UE		(0x0000002000000000)
+#define NX_ENGINE_FIR_CRB_UE			(0x0000001000000000)
+#define NX_ENGINE_FIR_CRB_SUE			(0x0000000800000000)
+#define NX_ENGINE_FIR_DMA_RW_ECC_SUE		(0x0000000400000000)
+#define NX_ENGINE_FIR_CH4_ECC_CE		(0x0000000080000000)
+#define NX_ENGINE_FIR_CH4_ECC_UE		(0x0000000040000000)
+#define NX_ENGINE_FIR_SCOM_PARITY		(0x00000000000c0000)
+#define NX_ENGINE_FIR_SCOM_PARITY1		(0x0000000000080000)
+#define NX_ENGINE_FIR_SCOM_PARITY2		(0x0000000000040000)
+
+#define xscom_read_engine_fir(gcid, val)				\
+	xscom_read((gcid), NX_DMA_ENGINE_FIR_DATA, (val))
+
+#define xscom_clear_engine_fir(gcid, val)				\
+	xscom_write((gcid), NX_DMA_ENGINE_FIR_DATA_CLEAR, (val))
+
+static inline uint64_t __xscom_fir_ch_invalid(int ch)
+{
+	switch (ch) {
+	case 0:
+		return NX_ENGINE_FIR_CH0_INVALID_STATE;
+	case 1:
+		return NX_ENGINE_FIR_CH1_INVALID_STATE;
+	case 2:
+		return NX_ENGINE_FIR_CH2_INVALID_STATE;
+	case 3:
+		return NX_ENGINE_FIR_CH3_INVALID_STATE;
+	case 4:
+		return NX_ENGINE_FIR_CH4_INVALID_STATE;
+	case 5:
+		return NX_ENGINE_FIR_CH5_INVALID_STATE;
+	case 6:
+		return NX_ENGINE_FIR_CH6_INVALID_STATE;
+	case 7:
+		return NX_ENGINE_FIR_CH7_INVALID_STATE;
+	default:
+		BUG();
+		return -1;
+	}
+}
+
+#define xscom_read_fir_ch_invalid(gcid, ch, val)		\
+	xscom_read_field((gcid), NX_DMA_ENGINE_FIR_DATA, (val),	\
+		__xscom_fir_ch_invalid(ch))
+#define xscom_clear_fir_ch_invalid(gcid, ch)			\
+	xscom_write((gcid), NX_DMA_ENGINE_FIR_DATA_CLEAR,	\
+		__xscom_fir_ch_invalid(ch))
+
+
+#endif /* __NX_842_XSCOM_H__ */
diff --git a/drivers/crypto/nx/nx-842.c b/drivers/crypto/nx/nx-842.c
index 279a38e..6187bcc 100644
--- a/drivers/crypto/nx/nx-842.c
+++ b/drivers/crypto/nx/nx-842.c
@@ -164,7 +164,9 @@ static __init int nx842_init(void)
 {
 	pr_info("loading\n");
 
-	if (of_find_compatible_node(NULL, NULL, NX842_PSERIES_COMPAT_NAME))
+	if (of_find_compatible_node(NULL, NULL, NX842_POWERNV_COMPAT_NAME))
+		request_module_nowait(NX842_POWERNV_MODULE_NAME);
+	else if (of_find_compatible_node(NULL, NULL, NX842_PSERIES_COMPAT_NAME))
 		request_module_nowait(NX842_PSERIES_MODULE_NAME);
 	else
 		pr_err("no nx842 driver found.\n");
diff --git a/drivers/crypto/nx/nx-842.h b/drivers/crypto/nx/nx-842.h
index c6ceb0f..6724a2a 100644
--- a/drivers/crypto/nx/nx-842.h
+++ b/drivers/crypto/nx/nx-842.h
@@ -5,9 +5,104 @@
 #include <linux/kernel.h>
 #include <linux/module.h>
 #include <linux/nx842.h>
+#include <linux/sw842.h>
 #include <linux/of.h>
 #include <linux/slab.h>
 #include <linux/io.h>
+#include <linux/mm.h>
+#include <linux/ratelimit.h>
+
+/* Restrictions on Data Descriptor List (DDL) and Entry (DDE) buffers
+ *
+ * From NX P8 workbook, sec 4.9.1 "842 details"
+ *   Each DDE buffer is 128 byte aligned
+ *   Each DDE buffer size is a multiple of 32 bytes (except the last)
+ *   The last DDE buffer size is a multiple of 8 bytes
+ */
+#define DDE_BUFFER_ALIGN	(128)
+#define DDE_BUFFER_SIZE_MULT	(32)
+#define DDE_BUFFER_LAST_MULT	(8)
+
+/* Arbitrary DDL length limit
+ * Allows max buffer size of MAX-1 to MAX pages
+ * (depending on alignment)
+ */
+#define DDL_LEN_MAX		(17)
+
+/* 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)
+
+/* CCW Function Codes (FC) for 842
+ * NX P8 workbook, section 4.9, table 4-28
+ * "Function Code Definitions for 842 Memory Compression"
+ */
+#define CCW_FC_842_COMP_NOCRC	(0)
+#define CCW_FC_842_COMP_CRC	(1)
+#define CCW_FC_842_DECOMP_NOCRC	(2)
+#define CCW_FC_842_DECOMP_CRC	(3)
+#define CCW_FC_842_MOVE		(4)
+
+/* CSB CC Error Types for 842
+ * NX P8 workbook, section 4.10.3, table 4-30
+ * "Reported Error Types Summary Table"
+ */
+/* These are all duplicates of existing codes defined in icswx.h. */
+#define CSB_CC_TRANSLATION_DUP1	(80)
+#define CSB_CC_TRANSLATION_DUP2	(82)
+#define CSB_CC_TRANSLATION_DUP3	(84)
+#define CSB_CC_TRANSLATION_DUP4	(86)
+#define CSB_CC_TRANSLATION_DUP5	(92)
+#define CSB_CC_TRANSLATION_DUP6	(94)
+#define CSB_CC_PROTECTION_DUP1	(81)
+#define CSB_CC_PROTECTION_DUP2	(83)
+#define CSB_CC_PROTECTION_DUP3	(85)
+#define CSB_CC_PROTECTION_DUP4	(87)
+#define CSB_CC_PROTECTION_DUP5	(93)
+#define CSB_CC_PROTECTION_DUP6	(95)
+#define CSB_CC_RD_EXTERNAL_DUP1	(89)
+#define CSB_CC_RD_EXTERNAL_DUP2	(90)
+#define CSB_CC_RD_EXTERNAL_DUP3	(91)
+/* These are specific to NX */
+/* 842 codes */
+#define CSB_CC_TPBC_GT_SPBC	(64) /* no error, but >1 comp ratio */
+#define CSB_CC_CRC_MISMATCH	(65) /* decomp crc mismatch */
+#define CSB_CC_TEMPL_INVALID	(66) /* decomp invalid template value */
+#define CSB_CC_TEMPL_OVERFLOW	(67) /* decomp template shows data after end */
+/* sym crypt codes */
+#define CSB_CC_DECRYPT_OVERFLOW	(64)
+/* asym crypt codes */
+#define CSB_CC_MINV_OVERFLOW	(128)
+/* These are reserved for hypervisor use */
+#define CSB_CC_HYP_RESERVE_START	(240)
+#define CSB_CC_HYP_RESERVE_END		(253)
+#define CSB_CC_HYP_NO_HW		(254)
+#define CSB_CC_HYP_HANG_ABORTED		(255)
+
+/* CCB Completion Modes (CM) for 842
+ * NX P8 workbook, section 4.3, figure 4-5
+ * "CRB Details - Normal Cop_Req (CL=00, C=1)"
+ */
+#define CCB_CM_EXTRA_WRITE	(CCB_CM0_ALL_COMPLETIONS & CCB_CM12_STORE)
+#define CCB_CM_INTERRUPT	(CCB_CM0_ALL_COMPLETIONS & CCB_CM12_INTERRUPT)
+
+#define LEN_ON_PAGE(pa)		(PAGE_SIZE - ((pa) & ~PAGE_MASK))
+
+static inline unsigned long nx842_get_pa(void *addr)
+{
+	if (!is_vmalloc_addr(addr))
+		return __pa(addr);
+
+	return page_to_phys(vmalloc_to_page(addr)) + offset_in_page(addr);
+}
+
+/* Get/Set bit fields */
+#define MASK_LSH(m)		(__builtin_ffsl(m) - 1)
+#define GET_FIELD(v, m)		(((v) & (m)) >> MASK_LSH(m))
+#define SET_FIELD(v, m, val)	(((v) & ~(m)) | (((val) << MASK_LSH(m)) & (m)))
 
 struct nx842_driver {
 	struct module *owner;
@@ -27,6 +122,8 @@ void nx842_unregister_driver(struct nx842_driver *driver);
 
 
 /* To allow the main nx-compress module to load platform module */
+#define NX842_POWERNV_MODULE_NAME	"nx-compress-powernv"
+#define NX842_POWERNV_COMPAT_NAME	"ibm,nx842-powernv"
 #define NX842_PSERIES_MODULE_NAME	"nx-compress-pseries"
 #define NX842_PSERIES_COMPAT_NAME	"ibm,compression"
 
diff --git a/include/linux/nx842.h b/include/linux/nx842.h
index 883b474..966d4d5 100644
--- a/include/linux/nx842.h
+++ b/include/linux/nx842.h
@@ -1,9 +1,11 @@
 #ifndef __NX842_H__
 #define __NX842_H__
 
-#define __NX842_PSERIES_MEM_COMPRESS	(PAGE_SIZE * 2 + 10240)
+#define __NX842_PSERIES_MEM_COMPRESS	(10240)
+#define __NX842_POWERNV_MEM_COMPRESS	(1024)
 
-#define NX842_MEM_COMPRESS	__NX842_PSERIES_MEM_COMPRESS
+#define NX842_MEM_COMPRESS	(max_t(unsigned int,			\
+	__NX842_PSERIES_MEM_COMPRESS, __NX842_POWERNV_MEM_COMPRESS))
 
 struct nx842_constraints {
 	int alignment;
-- 
2.1.0



More information about the Skiboot mailing list