From patchwork Tue Mar 10 03:58:38 2015 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Dan Streetman X-Patchwork-Id: 448337 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Received: from lists.ozlabs.org (lists.ozlabs.org [IPv6:2401:3900:2:1::3]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by ozlabs.org (Postfix) with ESMTPS id 96F1214008F for ; Tue, 10 Mar 2015 15:00:04 +1100 (AEDT) Authentication-Results: ozlabs.org; dkim=fail reason="verification failed; unprotected key" header.d=gmail.com header.i=@gmail.com header.b=R00NxkwL; dkim-adsp=none (unprotected policy); dkim-atps=neutral Received: from lists.ozlabs.org (lists.ozlabs.org [IPv6:2401:3900:2:1::3]) by lists.ozlabs.org (Postfix) with ESMTP id 727E11A03BC for ; Tue, 10 Mar 2015 15:00:04 +1100 (AEDT) Authentication-Results: lists.ozlabs.org; dkim=fail reason="verification failed; unprotected key" header.d=gmail.com header.i=@gmail.com header.b=R00NxkwL; dkim-adsp=none (unprotected policy); dkim-atps=neutral X-Original-To: skiboot@lists.ozlabs.org Delivered-To: skiboot@lists.ozlabs.org Received: from mail-ig0-x233.google.com (mail-ig0-x233.google.com [IPv6:2607:f8b0:4001:c05::233]) (using TLSv1.2 with cipher ECDHE-RSA-AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by lists.ozlabs.org (Postfix) with ESMTPS id 804481A03B6 for ; Tue, 10 Mar 2015 14:59:40 +1100 (AEDT) Authentication-Results: lists.ozlabs.org; dkim=pass reason="2048-bit key; unprotected key" header.d=gmail.com header.i=@gmail.com header.b=R00NxkwL; dkim-adsp=none (unprotected policy); dkim-atps=neutral Received: by igdh15 with SMTP id h15so27752234igd.3 for ; Mon, 09 Mar 2015 20:59:38 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20120113; h=sender:from:to:cc:subject:date:message-id:in-reply-to:references; bh=YPgyk+/TdFsKQhd3gF4NvK4F0Vpz2dUhnCcEkrRcETA=; b=R00NxkwLBWpobCk9c82vlqFeRbnkivIAzSIyFYkxBvclF+Ezicn5Y3bEhmvMVL2pMa Li55jwF93USLcLwVpttQd+eSaf/I9U+6if2t5+y5ItRoirL1DJ+apBvXgTNVunlXVMrm 6dnYoFxAiUCNvpHyJNXHYOuMg98lDG3KPFnsgACmBqSwTQia0CGtX7nYuTgK9keUECg7 feXlm3P2u4LrD0qqE0kOf4VDJrc0NbnOBUDSW/75dXVi5J75nIzX+mGArNuGT1efUV/q I/+UOlI5iqrgg1ya9r19j4bMo1S17Xrneh/nC3Q2FQDU3DS8uyLBwoEBWC2k28iczb/a czNA== X-Received: by 10.50.79.166 with SMTP id k6mr53771676igx.27.1425959978414; Mon, 09 Mar 2015 20:59:38 -0700 (PDT) Received: from toughbook.com (user-0c8hjgg.cable.mindspring.com. [24.136.206.16]) by mx.google.com with ESMTPSA id v15sm945964igd.15.2015.03.09.20.59.37 (version=TLSv1.2 cipher=ECDHE-RSA-AES128-GCM-SHA256 bits=128/128); Mon, 09 Mar 2015 20:59:37 -0700 (PDT) From: Dan Streetman To: skiboot@lists.ozlabs.org Date: Mon, 9 Mar 2015 23:58:38 -0400 Message-Id: <1425959922-4629-9-git-send-email-ddstreet@ieee.org> X-Mailer: git-send-email 2.1.0 In-Reply-To: <1425959922-4629-1-git-send-email-ddstreet@ieee.org> References: <1425959922-4629-1-git-send-email-ddstreet@ieee.org> Subject: [Skiboot] [RFC 08/12] add PowerNV platform NX-842 driver X-BeenThere: skiboot@lists.ozlabs.org X-Mailman-Version: 2.1.18 Precedence: list List-Id: Mailing list for skiboot development List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , MIME-Version: 1.0 Errors-To: skiboot-bounces+incoming=patchwork.ozlabs.org@lists.ozlabs.org Sender: "Skiboot" 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 --- 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 + +#include +#include + +#define MODULE_NAME NX842_POWERNV_MODULE_NAME +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("Dan Streetman "); +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 + +/* 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 #include #include +#include #include #include #include +#include +#include + +/* 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;