[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