162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * Driver for IBM PowerNV compression accelerator 462306a36Sopenharmony_ci * 562306a36Sopenharmony_ci * Copyright (C) 2015 Dan Streetman, IBM Corp 662306a36Sopenharmony_ci */ 762306a36Sopenharmony_ci 862306a36Sopenharmony_ci#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt 962306a36Sopenharmony_ci 1062306a36Sopenharmony_ci#include "nx-842.h" 1162306a36Sopenharmony_ci 1262306a36Sopenharmony_ci#include <linux/timer.h> 1362306a36Sopenharmony_ci 1462306a36Sopenharmony_ci#include <asm/prom.h> 1562306a36Sopenharmony_ci#include <asm/icswx.h> 1662306a36Sopenharmony_ci#include <asm/vas.h> 1762306a36Sopenharmony_ci#include <asm/reg.h> 1862306a36Sopenharmony_ci#include <asm/opal-api.h> 1962306a36Sopenharmony_ci#include <asm/opal.h> 2062306a36Sopenharmony_ci 2162306a36Sopenharmony_ciMODULE_LICENSE("GPL"); 2262306a36Sopenharmony_ciMODULE_AUTHOR("Dan Streetman <ddstreet@ieee.org>"); 2362306a36Sopenharmony_ciMODULE_DESCRIPTION("H/W Compression driver for IBM PowerNV processors"); 2462306a36Sopenharmony_ciMODULE_ALIAS_CRYPTO("842"); 2562306a36Sopenharmony_ciMODULE_ALIAS_CRYPTO("842-nx"); 2662306a36Sopenharmony_ci 2762306a36Sopenharmony_ci#define WORKMEM_ALIGN (CRB_ALIGN) 2862306a36Sopenharmony_ci#define CSB_WAIT_MAX (5000) /* ms */ 2962306a36Sopenharmony_ci#define VAS_RETRIES (10) 3062306a36Sopenharmony_ci 3162306a36Sopenharmony_cistruct nx842_workmem { 3262306a36Sopenharmony_ci /* Below fields must be properly aligned */ 3362306a36Sopenharmony_ci struct coprocessor_request_block crb; /* CRB_ALIGN align */ 3462306a36Sopenharmony_ci struct data_descriptor_entry ddl_in[DDL_LEN_MAX]; /* DDE_ALIGN align */ 3562306a36Sopenharmony_ci struct data_descriptor_entry ddl_out[DDL_LEN_MAX]; /* DDE_ALIGN align */ 3662306a36Sopenharmony_ci /* Above fields must be properly aligned */ 3762306a36Sopenharmony_ci 3862306a36Sopenharmony_ci ktime_t start; 3962306a36Sopenharmony_ci 4062306a36Sopenharmony_ci char padding[WORKMEM_ALIGN]; /* unused, to allow alignment */ 4162306a36Sopenharmony_ci} __packed __aligned(WORKMEM_ALIGN); 4262306a36Sopenharmony_ci 4362306a36Sopenharmony_cistruct nx_coproc { 4462306a36Sopenharmony_ci unsigned int chip_id; 4562306a36Sopenharmony_ci unsigned int ct; /* Can be 842 or GZIP high/normal*/ 4662306a36Sopenharmony_ci unsigned int ci; /* Coprocessor instance, used with icswx */ 4762306a36Sopenharmony_ci struct { 4862306a36Sopenharmony_ci struct vas_window *rxwin; 4962306a36Sopenharmony_ci int id; 5062306a36Sopenharmony_ci } vas; 5162306a36Sopenharmony_ci struct list_head list; 5262306a36Sopenharmony_ci}; 5362306a36Sopenharmony_ci 5462306a36Sopenharmony_ci/* 5562306a36Sopenharmony_ci * Send the request to NX engine on the chip for the corresponding CPU 5662306a36Sopenharmony_ci * where the process is executing. Use with VAS function. 5762306a36Sopenharmony_ci */ 5862306a36Sopenharmony_cistatic DEFINE_PER_CPU(struct vas_window *, cpu_txwin); 5962306a36Sopenharmony_ci 6062306a36Sopenharmony_ci/* no cpu hotplug on powernv, so this list never changes after init */ 6162306a36Sopenharmony_cistatic LIST_HEAD(nx_coprocs); 6262306a36Sopenharmony_cistatic unsigned int nx842_ct; /* used in icswx function */ 6362306a36Sopenharmony_ci 6462306a36Sopenharmony_ci/* 6562306a36Sopenharmony_ci * Using same values as in skiboot or coprocessor type representing 6662306a36Sopenharmony_ci * in NX workbook. 6762306a36Sopenharmony_ci */ 6862306a36Sopenharmony_ci#define NX_CT_GZIP (2) /* on P9 and later */ 6962306a36Sopenharmony_ci#define NX_CT_842 (3) 7062306a36Sopenharmony_ci 7162306a36Sopenharmony_cistatic int (*nx842_powernv_exec)(const unsigned char *in, 7262306a36Sopenharmony_ci unsigned int inlen, unsigned char *out, 7362306a36Sopenharmony_ci unsigned int *outlenp, void *workmem, int fc); 7462306a36Sopenharmony_ci 7562306a36Sopenharmony_ci/* 7662306a36Sopenharmony_ci * setup_indirect_dde - Setup an indirect DDE 7762306a36Sopenharmony_ci * 7862306a36Sopenharmony_ci * The DDE is setup with the DDE count, byte count, and address of 7962306a36Sopenharmony_ci * first direct DDE in the list. 8062306a36Sopenharmony_ci */ 8162306a36Sopenharmony_cistatic void setup_indirect_dde(struct data_descriptor_entry *dde, 8262306a36Sopenharmony_ci struct data_descriptor_entry *ddl, 8362306a36Sopenharmony_ci unsigned int dde_count, unsigned int byte_count) 8462306a36Sopenharmony_ci{ 8562306a36Sopenharmony_ci dde->flags = 0; 8662306a36Sopenharmony_ci dde->count = dde_count; 8762306a36Sopenharmony_ci dde->index = 0; 8862306a36Sopenharmony_ci dde->length = cpu_to_be32(byte_count); 8962306a36Sopenharmony_ci dde->address = cpu_to_be64(nx842_get_pa(ddl)); 9062306a36Sopenharmony_ci} 9162306a36Sopenharmony_ci 9262306a36Sopenharmony_ci/* 9362306a36Sopenharmony_ci * setup_direct_dde - Setup single DDE from buffer 9462306a36Sopenharmony_ci * 9562306a36Sopenharmony_ci * The DDE is setup with the buffer and length. The buffer must be properly 9662306a36Sopenharmony_ci * aligned. The used length is returned. 9762306a36Sopenharmony_ci * Returns: 9862306a36Sopenharmony_ci * N Successfully set up DDE with N bytes 9962306a36Sopenharmony_ci */ 10062306a36Sopenharmony_cistatic unsigned int setup_direct_dde(struct data_descriptor_entry *dde, 10162306a36Sopenharmony_ci unsigned long pa, unsigned int len) 10262306a36Sopenharmony_ci{ 10362306a36Sopenharmony_ci unsigned int l = min_t(unsigned int, len, LEN_ON_PAGE(pa)); 10462306a36Sopenharmony_ci 10562306a36Sopenharmony_ci dde->flags = 0; 10662306a36Sopenharmony_ci dde->count = 0; 10762306a36Sopenharmony_ci dde->index = 0; 10862306a36Sopenharmony_ci dde->length = cpu_to_be32(l); 10962306a36Sopenharmony_ci dde->address = cpu_to_be64(pa); 11062306a36Sopenharmony_ci 11162306a36Sopenharmony_ci return l; 11262306a36Sopenharmony_ci} 11362306a36Sopenharmony_ci 11462306a36Sopenharmony_ci/* 11562306a36Sopenharmony_ci * setup_ddl - Setup DDL from buffer 11662306a36Sopenharmony_ci * 11762306a36Sopenharmony_ci * Returns: 11862306a36Sopenharmony_ci * 0 Successfully set up DDL 11962306a36Sopenharmony_ci */ 12062306a36Sopenharmony_cistatic int setup_ddl(struct data_descriptor_entry *dde, 12162306a36Sopenharmony_ci struct data_descriptor_entry *ddl, 12262306a36Sopenharmony_ci unsigned char *buf, unsigned int len, 12362306a36Sopenharmony_ci bool in) 12462306a36Sopenharmony_ci{ 12562306a36Sopenharmony_ci unsigned long pa = nx842_get_pa(buf); 12662306a36Sopenharmony_ci int i, ret, total_len = len; 12762306a36Sopenharmony_ci 12862306a36Sopenharmony_ci if (!IS_ALIGNED(pa, DDE_BUFFER_ALIGN)) { 12962306a36Sopenharmony_ci pr_debug("%s buffer pa 0x%lx not 0x%x-byte aligned\n", 13062306a36Sopenharmony_ci in ? "input" : "output", pa, DDE_BUFFER_ALIGN); 13162306a36Sopenharmony_ci return -EINVAL; 13262306a36Sopenharmony_ci } 13362306a36Sopenharmony_ci 13462306a36Sopenharmony_ci /* only need to check last mult; since buffer must be 13562306a36Sopenharmony_ci * DDE_BUFFER_ALIGN aligned, and that is a multiple of 13662306a36Sopenharmony_ci * DDE_BUFFER_SIZE_MULT, and pre-last page DDE buffers 13762306a36Sopenharmony_ci * are guaranteed a multiple of DDE_BUFFER_SIZE_MULT. 13862306a36Sopenharmony_ci */ 13962306a36Sopenharmony_ci if (len % DDE_BUFFER_LAST_MULT) { 14062306a36Sopenharmony_ci pr_debug("%s buffer len 0x%x not a multiple of 0x%x\n", 14162306a36Sopenharmony_ci in ? "input" : "output", len, DDE_BUFFER_LAST_MULT); 14262306a36Sopenharmony_ci if (in) 14362306a36Sopenharmony_ci return -EINVAL; 14462306a36Sopenharmony_ci len = round_down(len, DDE_BUFFER_LAST_MULT); 14562306a36Sopenharmony_ci } 14662306a36Sopenharmony_ci 14762306a36Sopenharmony_ci /* use a single direct DDE */ 14862306a36Sopenharmony_ci if (len <= LEN_ON_PAGE(pa)) { 14962306a36Sopenharmony_ci ret = setup_direct_dde(dde, pa, len); 15062306a36Sopenharmony_ci WARN_ON(ret < len); 15162306a36Sopenharmony_ci return 0; 15262306a36Sopenharmony_ci } 15362306a36Sopenharmony_ci 15462306a36Sopenharmony_ci /* use the DDL */ 15562306a36Sopenharmony_ci for (i = 0; i < DDL_LEN_MAX && len > 0; i++) { 15662306a36Sopenharmony_ci ret = setup_direct_dde(&ddl[i], pa, len); 15762306a36Sopenharmony_ci buf += ret; 15862306a36Sopenharmony_ci len -= ret; 15962306a36Sopenharmony_ci pa = nx842_get_pa(buf); 16062306a36Sopenharmony_ci } 16162306a36Sopenharmony_ci 16262306a36Sopenharmony_ci if (len > 0) { 16362306a36Sopenharmony_ci pr_debug("0x%x total %s bytes 0x%x too many for DDL.\n", 16462306a36Sopenharmony_ci total_len, in ? "input" : "output", len); 16562306a36Sopenharmony_ci if (in) 16662306a36Sopenharmony_ci return -EMSGSIZE; 16762306a36Sopenharmony_ci total_len -= len; 16862306a36Sopenharmony_ci } 16962306a36Sopenharmony_ci setup_indirect_dde(dde, ddl, i, total_len); 17062306a36Sopenharmony_ci 17162306a36Sopenharmony_ci return 0; 17262306a36Sopenharmony_ci} 17362306a36Sopenharmony_ci 17462306a36Sopenharmony_ci#define CSB_ERR(csb, msg, ...) \ 17562306a36Sopenharmony_ci pr_err("ERROR: " msg " : %02x %02x %02x %02x %08x\n", \ 17662306a36Sopenharmony_ci ##__VA_ARGS__, (csb)->flags, \ 17762306a36Sopenharmony_ci (csb)->cs, (csb)->cc, (csb)->ce, \ 17862306a36Sopenharmony_ci be32_to_cpu((csb)->count)) 17962306a36Sopenharmony_ci 18062306a36Sopenharmony_ci#define CSB_ERR_ADDR(csb, msg, ...) \ 18162306a36Sopenharmony_ci CSB_ERR(csb, msg " at %lx", ##__VA_ARGS__, \ 18262306a36Sopenharmony_ci (unsigned long)be64_to_cpu((csb)->address)) 18362306a36Sopenharmony_ci 18462306a36Sopenharmony_cistatic int wait_for_csb(struct nx842_workmem *wmem, 18562306a36Sopenharmony_ci struct coprocessor_status_block *csb) 18662306a36Sopenharmony_ci{ 18762306a36Sopenharmony_ci ktime_t start = wmem->start, now = ktime_get(); 18862306a36Sopenharmony_ci ktime_t timeout = ktime_add_ms(start, CSB_WAIT_MAX); 18962306a36Sopenharmony_ci 19062306a36Sopenharmony_ci while (!(READ_ONCE(csb->flags) & CSB_V)) { 19162306a36Sopenharmony_ci cpu_relax(); 19262306a36Sopenharmony_ci now = ktime_get(); 19362306a36Sopenharmony_ci if (ktime_after(now, timeout)) 19462306a36Sopenharmony_ci break; 19562306a36Sopenharmony_ci } 19662306a36Sopenharmony_ci 19762306a36Sopenharmony_ci /* hw has updated csb and output buffer */ 19862306a36Sopenharmony_ci barrier(); 19962306a36Sopenharmony_ci 20062306a36Sopenharmony_ci /* check CSB flags */ 20162306a36Sopenharmony_ci if (!(csb->flags & CSB_V)) { 20262306a36Sopenharmony_ci CSB_ERR(csb, "CSB still not valid after %ld us, giving up", 20362306a36Sopenharmony_ci (long)ktime_us_delta(now, start)); 20462306a36Sopenharmony_ci return -ETIMEDOUT; 20562306a36Sopenharmony_ci } 20662306a36Sopenharmony_ci if (csb->flags & CSB_F) { 20762306a36Sopenharmony_ci CSB_ERR(csb, "Invalid CSB format"); 20862306a36Sopenharmony_ci return -EPROTO; 20962306a36Sopenharmony_ci } 21062306a36Sopenharmony_ci if (csb->flags & CSB_CH) { 21162306a36Sopenharmony_ci CSB_ERR(csb, "Invalid CSB chaining state"); 21262306a36Sopenharmony_ci return -EPROTO; 21362306a36Sopenharmony_ci } 21462306a36Sopenharmony_ci 21562306a36Sopenharmony_ci /* verify CSB completion sequence is 0 */ 21662306a36Sopenharmony_ci if (csb->cs) { 21762306a36Sopenharmony_ci CSB_ERR(csb, "Invalid CSB completion sequence"); 21862306a36Sopenharmony_ci return -EPROTO; 21962306a36Sopenharmony_ci } 22062306a36Sopenharmony_ci 22162306a36Sopenharmony_ci /* check CSB Completion Code */ 22262306a36Sopenharmony_ci switch (csb->cc) { 22362306a36Sopenharmony_ci /* no error */ 22462306a36Sopenharmony_ci case CSB_CC_SUCCESS: 22562306a36Sopenharmony_ci break; 22662306a36Sopenharmony_ci case CSB_CC_TPBC_GT_SPBC: 22762306a36Sopenharmony_ci /* not an error, but the compressed data is 22862306a36Sopenharmony_ci * larger than the uncompressed data :( 22962306a36Sopenharmony_ci */ 23062306a36Sopenharmony_ci break; 23162306a36Sopenharmony_ci 23262306a36Sopenharmony_ci /* input data errors */ 23362306a36Sopenharmony_ci case CSB_CC_OPERAND_OVERLAP: 23462306a36Sopenharmony_ci /* input and output buffers overlap */ 23562306a36Sopenharmony_ci CSB_ERR(csb, "Operand Overlap error"); 23662306a36Sopenharmony_ci return -EINVAL; 23762306a36Sopenharmony_ci case CSB_CC_INVALID_OPERAND: 23862306a36Sopenharmony_ci CSB_ERR(csb, "Invalid operand"); 23962306a36Sopenharmony_ci return -EINVAL; 24062306a36Sopenharmony_ci case CSB_CC_NOSPC: 24162306a36Sopenharmony_ci /* output buffer too small */ 24262306a36Sopenharmony_ci return -ENOSPC; 24362306a36Sopenharmony_ci case CSB_CC_ABORT: 24462306a36Sopenharmony_ci CSB_ERR(csb, "Function aborted"); 24562306a36Sopenharmony_ci return -EINTR; 24662306a36Sopenharmony_ci case CSB_CC_CRC_MISMATCH: 24762306a36Sopenharmony_ci CSB_ERR(csb, "CRC mismatch"); 24862306a36Sopenharmony_ci return -EINVAL; 24962306a36Sopenharmony_ci case CSB_CC_TEMPL_INVALID: 25062306a36Sopenharmony_ci CSB_ERR(csb, "Compressed data template invalid"); 25162306a36Sopenharmony_ci return -EINVAL; 25262306a36Sopenharmony_ci case CSB_CC_TEMPL_OVERFLOW: 25362306a36Sopenharmony_ci CSB_ERR(csb, "Compressed data template shows data past end"); 25462306a36Sopenharmony_ci return -EINVAL; 25562306a36Sopenharmony_ci case CSB_CC_EXCEED_BYTE_COUNT: /* P9 or later */ 25662306a36Sopenharmony_ci /* 25762306a36Sopenharmony_ci * DDE byte count exceeds the limit specified in Maximum 25862306a36Sopenharmony_ci * byte count register. 25962306a36Sopenharmony_ci */ 26062306a36Sopenharmony_ci CSB_ERR(csb, "DDE byte count exceeds the limit"); 26162306a36Sopenharmony_ci return -EINVAL; 26262306a36Sopenharmony_ci 26362306a36Sopenharmony_ci /* these should not happen */ 26462306a36Sopenharmony_ci case CSB_CC_INVALID_ALIGN: 26562306a36Sopenharmony_ci /* setup_ddl should have detected this */ 26662306a36Sopenharmony_ci CSB_ERR_ADDR(csb, "Invalid alignment"); 26762306a36Sopenharmony_ci return -EINVAL; 26862306a36Sopenharmony_ci case CSB_CC_DATA_LENGTH: 26962306a36Sopenharmony_ci /* setup_ddl should have detected this */ 27062306a36Sopenharmony_ci CSB_ERR(csb, "Invalid data length"); 27162306a36Sopenharmony_ci return -EINVAL; 27262306a36Sopenharmony_ci case CSB_CC_WR_TRANSLATION: 27362306a36Sopenharmony_ci case CSB_CC_TRANSLATION: 27462306a36Sopenharmony_ci case CSB_CC_TRANSLATION_DUP1: 27562306a36Sopenharmony_ci case CSB_CC_TRANSLATION_DUP2: 27662306a36Sopenharmony_ci case CSB_CC_TRANSLATION_DUP3: 27762306a36Sopenharmony_ci case CSB_CC_TRANSLATION_DUP4: 27862306a36Sopenharmony_ci case CSB_CC_TRANSLATION_DUP5: 27962306a36Sopenharmony_ci case CSB_CC_TRANSLATION_DUP6: 28062306a36Sopenharmony_ci /* should not happen, we use physical addrs */ 28162306a36Sopenharmony_ci CSB_ERR_ADDR(csb, "Translation error"); 28262306a36Sopenharmony_ci return -EPROTO; 28362306a36Sopenharmony_ci case CSB_CC_WR_PROTECTION: 28462306a36Sopenharmony_ci case CSB_CC_PROTECTION: 28562306a36Sopenharmony_ci case CSB_CC_PROTECTION_DUP1: 28662306a36Sopenharmony_ci case CSB_CC_PROTECTION_DUP2: 28762306a36Sopenharmony_ci case CSB_CC_PROTECTION_DUP3: 28862306a36Sopenharmony_ci case CSB_CC_PROTECTION_DUP4: 28962306a36Sopenharmony_ci case CSB_CC_PROTECTION_DUP5: 29062306a36Sopenharmony_ci case CSB_CC_PROTECTION_DUP6: 29162306a36Sopenharmony_ci /* should not happen, we use physical addrs */ 29262306a36Sopenharmony_ci CSB_ERR_ADDR(csb, "Protection error"); 29362306a36Sopenharmony_ci return -EPROTO; 29462306a36Sopenharmony_ci case CSB_CC_PRIVILEGE: 29562306a36Sopenharmony_ci /* shouldn't happen, we're in HYP mode */ 29662306a36Sopenharmony_ci CSB_ERR(csb, "Insufficient Privilege error"); 29762306a36Sopenharmony_ci return -EPROTO; 29862306a36Sopenharmony_ci case CSB_CC_EXCESSIVE_DDE: 29962306a36Sopenharmony_ci /* shouldn't happen, setup_ddl doesn't use many dde's */ 30062306a36Sopenharmony_ci CSB_ERR(csb, "Too many DDEs in DDL"); 30162306a36Sopenharmony_ci return -EINVAL; 30262306a36Sopenharmony_ci case CSB_CC_TRANSPORT: 30362306a36Sopenharmony_ci case CSB_CC_INVALID_CRB: /* P9 or later */ 30462306a36Sopenharmony_ci /* shouldn't happen, we setup CRB correctly */ 30562306a36Sopenharmony_ci CSB_ERR(csb, "Invalid CRB"); 30662306a36Sopenharmony_ci return -EINVAL; 30762306a36Sopenharmony_ci case CSB_CC_INVALID_DDE: /* P9 or later */ 30862306a36Sopenharmony_ci /* 30962306a36Sopenharmony_ci * shouldn't happen, setup_direct/indirect_dde creates 31062306a36Sopenharmony_ci * DDE right 31162306a36Sopenharmony_ci */ 31262306a36Sopenharmony_ci CSB_ERR(csb, "Invalid DDE"); 31362306a36Sopenharmony_ci return -EINVAL; 31462306a36Sopenharmony_ci case CSB_CC_SEGMENTED_DDL: 31562306a36Sopenharmony_ci /* shouldn't happen, setup_ddl creates DDL right */ 31662306a36Sopenharmony_ci CSB_ERR(csb, "Segmented DDL error"); 31762306a36Sopenharmony_ci return -EINVAL; 31862306a36Sopenharmony_ci case CSB_CC_DDE_OVERFLOW: 31962306a36Sopenharmony_ci /* shouldn't happen, setup_ddl creates DDL right */ 32062306a36Sopenharmony_ci CSB_ERR(csb, "DDE overflow error"); 32162306a36Sopenharmony_ci return -EINVAL; 32262306a36Sopenharmony_ci case CSB_CC_SESSION: 32362306a36Sopenharmony_ci /* should not happen with ICSWX */ 32462306a36Sopenharmony_ci CSB_ERR(csb, "Session violation error"); 32562306a36Sopenharmony_ci return -EPROTO; 32662306a36Sopenharmony_ci case CSB_CC_CHAIN: 32762306a36Sopenharmony_ci /* should not happen, we don't use chained CRBs */ 32862306a36Sopenharmony_ci CSB_ERR(csb, "Chained CRB error"); 32962306a36Sopenharmony_ci return -EPROTO; 33062306a36Sopenharmony_ci case CSB_CC_SEQUENCE: 33162306a36Sopenharmony_ci /* should not happen, we don't use chained CRBs */ 33262306a36Sopenharmony_ci CSB_ERR(csb, "CRB sequence number error"); 33362306a36Sopenharmony_ci return -EPROTO; 33462306a36Sopenharmony_ci case CSB_CC_UNKNOWN_CODE: 33562306a36Sopenharmony_ci CSB_ERR(csb, "Unknown subfunction code"); 33662306a36Sopenharmony_ci return -EPROTO; 33762306a36Sopenharmony_ci 33862306a36Sopenharmony_ci /* hardware errors */ 33962306a36Sopenharmony_ci case CSB_CC_RD_EXTERNAL: 34062306a36Sopenharmony_ci case CSB_CC_RD_EXTERNAL_DUP1: 34162306a36Sopenharmony_ci case CSB_CC_RD_EXTERNAL_DUP2: 34262306a36Sopenharmony_ci case CSB_CC_RD_EXTERNAL_DUP3: 34362306a36Sopenharmony_ci CSB_ERR_ADDR(csb, "Read error outside coprocessor"); 34462306a36Sopenharmony_ci return -EPROTO; 34562306a36Sopenharmony_ci case CSB_CC_WR_EXTERNAL: 34662306a36Sopenharmony_ci CSB_ERR_ADDR(csb, "Write error outside coprocessor"); 34762306a36Sopenharmony_ci return -EPROTO; 34862306a36Sopenharmony_ci case CSB_CC_INTERNAL: 34962306a36Sopenharmony_ci CSB_ERR(csb, "Internal error in coprocessor"); 35062306a36Sopenharmony_ci return -EPROTO; 35162306a36Sopenharmony_ci case CSB_CC_PROVISION: 35262306a36Sopenharmony_ci CSB_ERR(csb, "Storage provision error"); 35362306a36Sopenharmony_ci return -EPROTO; 35462306a36Sopenharmony_ci case CSB_CC_HW: 35562306a36Sopenharmony_ci CSB_ERR(csb, "Correctable hardware error"); 35662306a36Sopenharmony_ci return -EPROTO; 35762306a36Sopenharmony_ci case CSB_CC_HW_EXPIRED_TIMER: /* P9 or later */ 35862306a36Sopenharmony_ci CSB_ERR(csb, "Job did not finish within allowed time"); 35962306a36Sopenharmony_ci return -EPROTO; 36062306a36Sopenharmony_ci 36162306a36Sopenharmony_ci default: 36262306a36Sopenharmony_ci CSB_ERR(csb, "Invalid CC %d", csb->cc); 36362306a36Sopenharmony_ci return -EPROTO; 36462306a36Sopenharmony_ci } 36562306a36Sopenharmony_ci 36662306a36Sopenharmony_ci /* check Completion Extension state */ 36762306a36Sopenharmony_ci if (csb->ce & CSB_CE_TERMINATION) { 36862306a36Sopenharmony_ci CSB_ERR(csb, "CSB request was terminated"); 36962306a36Sopenharmony_ci return -EPROTO; 37062306a36Sopenharmony_ci } 37162306a36Sopenharmony_ci if (csb->ce & CSB_CE_INCOMPLETE) { 37262306a36Sopenharmony_ci CSB_ERR(csb, "CSB request not complete"); 37362306a36Sopenharmony_ci return -EPROTO; 37462306a36Sopenharmony_ci } 37562306a36Sopenharmony_ci if (!(csb->ce & CSB_CE_TPBC)) { 37662306a36Sopenharmony_ci CSB_ERR(csb, "TPBC not provided, unknown target length"); 37762306a36Sopenharmony_ci return -EPROTO; 37862306a36Sopenharmony_ci } 37962306a36Sopenharmony_ci 38062306a36Sopenharmony_ci /* successful completion */ 38162306a36Sopenharmony_ci pr_debug_ratelimited("Processed %u bytes in %lu us\n", 38262306a36Sopenharmony_ci be32_to_cpu(csb->count), 38362306a36Sopenharmony_ci (unsigned long)ktime_us_delta(now, start)); 38462306a36Sopenharmony_ci 38562306a36Sopenharmony_ci return 0; 38662306a36Sopenharmony_ci} 38762306a36Sopenharmony_ci 38862306a36Sopenharmony_cistatic int nx842_config_crb(const unsigned char *in, unsigned int inlen, 38962306a36Sopenharmony_ci unsigned char *out, unsigned int outlen, 39062306a36Sopenharmony_ci struct nx842_workmem *wmem) 39162306a36Sopenharmony_ci{ 39262306a36Sopenharmony_ci struct coprocessor_request_block *crb; 39362306a36Sopenharmony_ci struct coprocessor_status_block *csb; 39462306a36Sopenharmony_ci u64 csb_addr; 39562306a36Sopenharmony_ci int ret; 39662306a36Sopenharmony_ci 39762306a36Sopenharmony_ci crb = &wmem->crb; 39862306a36Sopenharmony_ci csb = &crb->csb; 39962306a36Sopenharmony_ci 40062306a36Sopenharmony_ci /* Clear any previous values */ 40162306a36Sopenharmony_ci memset(crb, 0, sizeof(*crb)); 40262306a36Sopenharmony_ci 40362306a36Sopenharmony_ci /* set up DDLs */ 40462306a36Sopenharmony_ci ret = setup_ddl(&crb->source, wmem->ddl_in, 40562306a36Sopenharmony_ci (unsigned char *)in, inlen, true); 40662306a36Sopenharmony_ci if (ret) 40762306a36Sopenharmony_ci return ret; 40862306a36Sopenharmony_ci 40962306a36Sopenharmony_ci ret = setup_ddl(&crb->target, wmem->ddl_out, 41062306a36Sopenharmony_ci out, outlen, false); 41162306a36Sopenharmony_ci if (ret) 41262306a36Sopenharmony_ci return ret; 41362306a36Sopenharmony_ci 41462306a36Sopenharmony_ci /* set up CRB's CSB addr */ 41562306a36Sopenharmony_ci csb_addr = nx842_get_pa(csb) & CRB_CSB_ADDRESS; 41662306a36Sopenharmony_ci csb_addr |= CRB_CSB_AT; /* Addrs are phys */ 41762306a36Sopenharmony_ci crb->csb_addr = cpu_to_be64(csb_addr); 41862306a36Sopenharmony_ci 41962306a36Sopenharmony_ci return 0; 42062306a36Sopenharmony_ci} 42162306a36Sopenharmony_ci 42262306a36Sopenharmony_ci/** 42362306a36Sopenharmony_ci * nx842_exec_icswx - compress/decompress data using the 842 algorithm 42462306a36Sopenharmony_ci * 42562306a36Sopenharmony_ci * (De)compression provided by the NX842 coprocessor on IBM PowerNV systems. 42662306a36Sopenharmony_ci * This compresses or decompresses the provided input buffer into the provided 42762306a36Sopenharmony_ci * output buffer. 42862306a36Sopenharmony_ci * 42962306a36Sopenharmony_ci * Upon return from this function @outlen contains the length of the 43062306a36Sopenharmony_ci * output data. If there is an error then @outlen will be 0 and an 43162306a36Sopenharmony_ci * error will be specified by the return code from this function. 43262306a36Sopenharmony_ci * 43362306a36Sopenharmony_ci * The @workmem buffer should only be used by one function call at a time. 43462306a36Sopenharmony_ci * 43562306a36Sopenharmony_ci * @in: input buffer pointer 43662306a36Sopenharmony_ci * @inlen: input buffer size 43762306a36Sopenharmony_ci * @out: output buffer pointer 43862306a36Sopenharmony_ci * @outlenp: output buffer size pointer 43962306a36Sopenharmony_ci * @workmem: working memory buffer pointer, size determined by 44062306a36Sopenharmony_ci * nx842_powernv_driver.workmem_size 44162306a36Sopenharmony_ci * @fc: function code, see CCW Function Codes in nx-842.h 44262306a36Sopenharmony_ci * 44362306a36Sopenharmony_ci * Returns: 44462306a36Sopenharmony_ci * 0 Success, output of length @outlenp stored in the buffer at @out 44562306a36Sopenharmony_ci * -ENODEV Hardware unavailable 44662306a36Sopenharmony_ci * -ENOSPC Output buffer is to small 44762306a36Sopenharmony_ci * -EMSGSIZE Input buffer too large 44862306a36Sopenharmony_ci * -EINVAL buffer constraints do not fix nx842_constraints 44962306a36Sopenharmony_ci * -EPROTO hardware error during operation 45062306a36Sopenharmony_ci * -ETIMEDOUT hardware did not complete operation in reasonable time 45162306a36Sopenharmony_ci * -EINTR operation was aborted 45262306a36Sopenharmony_ci */ 45362306a36Sopenharmony_cistatic int nx842_exec_icswx(const unsigned char *in, unsigned int inlen, 45462306a36Sopenharmony_ci unsigned char *out, unsigned int *outlenp, 45562306a36Sopenharmony_ci void *workmem, int fc) 45662306a36Sopenharmony_ci{ 45762306a36Sopenharmony_ci struct coprocessor_request_block *crb; 45862306a36Sopenharmony_ci struct coprocessor_status_block *csb; 45962306a36Sopenharmony_ci struct nx842_workmem *wmem; 46062306a36Sopenharmony_ci int ret; 46162306a36Sopenharmony_ci u32 ccw; 46262306a36Sopenharmony_ci unsigned int outlen = *outlenp; 46362306a36Sopenharmony_ci 46462306a36Sopenharmony_ci wmem = PTR_ALIGN(workmem, WORKMEM_ALIGN); 46562306a36Sopenharmony_ci 46662306a36Sopenharmony_ci *outlenp = 0; 46762306a36Sopenharmony_ci 46862306a36Sopenharmony_ci /* shoudn't happen, we don't load without a coproc */ 46962306a36Sopenharmony_ci if (!nx842_ct) { 47062306a36Sopenharmony_ci pr_err_ratelimited("coprocessor CT is 0"); 47162306a36Sopenharmony_ci return -ENODEV; 47262306a36Sopenharmony_ci } 47362306a36Sopenharmony_ci 47462306a36Sopenharmony_ci ret = nx842_config_crb(in, inlen, out, outlen, wmem); 47562306a36Sopenharmony_ci if (ret) 47662306a36Sopenharmony_ci return ret; 47762306a36Sopenharmony_ci 47862306a36Sopenharmony_ci crb = &wmem->crb; 47962306a36Sopenharmony_ci csb = &crb->csb; 48062306a36Sopenharmony_ci 48162306a36Sopenharmony_ci /* set up CCW */ 48262306a36Sopenharmony_ci ccw = 0; 48362306a36Sopenharmony_ci ccw = SET_FIELD(CCW_CT, ccw, nx842_ct); 48462306a36Sopenharmony_ci ccw = SET_FIELD(CCW_CI_842, ccw, 0); /* use 0 for hw auto-selection */ 48562306a36Sopenharmony_ci ccw = SET_FIELD(CCW_FC_842, ccw, fc); 48662306a36Sopenharmony_ci 48762306a36Sopenharmony_ci wmem->start = ktime_get(); 48862306a36Sopenharmony_ci 48962306a36Sopenharmony_ci /* do ICSWX */ 49062306a36Sopenharmony_ci ret = icswx(cpu_to_be32(ccw), crb); 49162306a36Sopenharmony_ci 49262306a36Sopenharmony_ci pr_debug_ratelimited("icswx CR %x ccw %x crb->ccw %x\n", ret, 49362306a36Sopenharmony_ci (unsigned int)ccw, 49462306a36Sopenharmony_ci (unsigned int)be32_to_cpu(crb->ccw)); 49562306a36Sopenharmony_ci 49662306a36Sopenharmony_ci /* 49762306a36Sopenharmony_ci * NX842 coprocessor sets 3rd bit in CR register with XER[S0]. 49862306a36Sopenharmony_ci * XER[S0] is the integer summary overflow bit which is nothing 49962306a36Sopenharmony_ci * to do NX. Since this bit can be set with other return values, 50062306a36Sopenharmony_ci * mask this bit. 50162306a36Sopenharmony_ci */ 50262306a36Sopenharmony_ci ret &= ~ICSWX_XERS0; 50362306a36Sopenharmony_ci 50462306a36Sopenharmony_ci switch (ret) { 50562306a36Sopenharmony_ci case ICSWX_INITIATED: 50662306a36Sopenharmony_ci ret = wait_for_csb(wmem, csb); 50762306a36Sopenharmony_ci break; 50862306a36Sopenharmony_ci case ICSWX_BUSY: 50962306a36Sopenharmony_ci pr_debug_ratelimited("842 Coprocessor busy\n"); 51062306a36Sopenharmony_ci ret = -EBUSY; 51162306a36Sopenharmony_ci break; 51262306a36Sopenharmony_ci case ICSWX_REJECTED: 51362306a36Sopenharmony_ci pr_err_ratelimited("ICSWX rejected\n"); 51462306a36Sopenharmony_ci ret = -EPROTO; 51562306a36Sopenharmony_ci break; 51662306a36Sopenharmony_ci } 51762306a36Sopenharmony_ci 51862306a36Sopenharmony_ci if (!ret) 51962306a36Sopenharmony_ci *outlenp = be32_to_cpu(csb->count); 52062306a36Sopenharmony_ci 52162306a36Sopenharmony_ci return ret; 52262306a36Sopenharmony_ci} 52362306a36Sopenharmony_ci 52462306a36Sopenharmony_ci/** 52562306a36Sopenharmony_ci * nx842_exec_vas - compress/decompress data using the 842 algorithm 52662306a36Sopenharmony_ci * 52762306a36Sopenharmony_ci * (De)compression provided by the NX842 coprocessor on IBM PowerNV systems. 52862306a36Sopenharmony_ci * This compresses or decompresses the provided input buffer into the provided 52962306a36Sopenharmony_ci * output buffer. 53062306a36Sopenharmony_ci * 53162306a36Sopenharmony_ci * Upon return from this function @outlen contains the length of the 53262306a36Sopenharmony_ci * output data. If there is an error then @outlen will be 0 and an 53362306a36Sopenharmony_ci * error will be specified by the return code from this function. 53462306a36Sopenharmony_ci * 53562306a36Sopenharmony_ci * The @workmem buffer should only be used by one function call at a time. 53662306a36Sopenharmony_ci * 53762306a36Sopenharmony_ci * @in: input buffer pointer 53862306a36Sopenharmony_ci * @inlen: input buffer size 53962306a36Sopenharmony_ci * @out: output buffer pointer 54062306a36Sopenharmony_ci * @outlenp: output buffer size pointer 54162306a36Sopenharmony_ci * @workmem: working memory buffer pointer, size determined by 54262306a36Sopenharmony_ci * nx842_powernv_driver.workmem_size 54362306a36Sopenharmony_ci * @fc: function code, see CCW Function Codes in nx-842.h 54462306a36Sopenharmony_ci * 54562306a36Sopenharmony_ci * Returns: 54662306a36Sopenharmony_ci * 0 Success, output of length @outlenp stored in the buffer 54762306a36Sopenharmony_ci * at @out 54862306a36Sopenharmony_ci * -ENODEV Hardware unavailable 54962306a36Sopenharmony_ci * -ENOSPC Output buffer is to small 55062306a36Sopenharmony_ci * -EMSGSIZE Input buffer too large 55162306a36Sopenharmony_ci * -EINVAL buffer constraints do not fix nx842_constraints 55262306a36Sopenharmony_ci * -EPROTO hardware error during operation 55362306a36Sopenharmony_ci * -ETIMEDOUT hardware did not complete operation in reasonable time 55462306a36Sopenharmony_ci * -EINTR operation was aborted 55562306a36Sopenharmony_ci */ 55662306a36Sopenharmony_cistatic int nx842_exec_vas(const unsigned char *in, unsigned int inlen, 55762306a36Sopenharmony_ci unsigned char *out, unsigned int *outlenp, 55862306a36Sopenharmony_ci void *workmem, int fc) 55962306a36Sopenharmony_ci{ 56062306a36Sopenharmony_ci struct coprocessor_request_block *crb; 56162306a36Sopenharmony_ci struct coprocessor_status_block *csb; 56262306a36Sopenharmony_ci struct nx842_workmem *wmem; 56362306a36Sopenharmony_ci struct vas_window *txwin; 56462306a36Sopenharmony_ci int ret, i = 0; 56562306a36Sopenharmony_ci u32 ccw; 56662306a36Sopenharmony_ci unsigned int outlen = *outlenp; 56762306a36Sopenharmony_ci 56862306a36Sopenharmony_ci wmem = PTR_ALIGN(workmem, WORKMEM_ALIGN); 56962306a36Sopenharmony_ci 57062306a36Sopenharmony_ci *outlenp = 0; 57162306a36Sopenharmony_ci 57262306a36Sopenharmony_ci crb = &wmem->crb; 57362306a36Sopenharmony_ci csb = &crb->csb; 57462306a36Sopenharmony_ci 57562306a36Sopenharmony_ci ret = nx842_config_crb(in, inlen, out, outlen, wmem); 57662306a36Sopenharmony_ci if (ret) 57762306a36Sopenharmony_ci return ret; 57862306a36Sopenharmony_ci 57962306a36Sopenharmony_ci ccw = 0; 58062306a36Sopenharmony_ci ccw = SET_FIELD(CCW_FC_842, ccw, fc); 58162306a36Sopenharmony_ci crb->ccw = cpu_to_be32(ccw); 58262306a36Sopenharmony_ci 58362306a36Sopenharmony_ci do { 58462306a36Sopenharmony_ci wmem->start = ktime_get(); 58562306a36Sopenharmony_ci preempt_disable(); 58662306a36Sopenharmony_ci txwin = this_cpu_read(cpu_txwin); 58762306a36Sopenharmony_ci 58862306a36Sopenharmony_ci /* 58962306a36Sopenharmony_ci * VAS copy CRB into L2 cache. Refer <asm/vas.h>. 59062306a36Sopenharmony_ci * @crb and @offset. 59162306a36Sopenharmony_ci */ 59262306a36Sopenharmony_ci vas_copy_crb(crb, 0); 59362306a36Sopenharmony_ci 59462306a36Sopenharmony_ci /* 59562306a36Sopenharmony_ci * VAS paste previously copied CRB to NX. 59662306a36Sopenharmony_ci * @txwin, @offset and @last (must be true). 59762306a36Sopenharmony_ci */ 59862306a36Sopenharmony_ci ret = vas_paste_crb(txwin, 0, 1); 59962306a36Sopenharmony_ci preempt_enable(); 60062306a36Sopenharmony_ci /* 60162306a36Sopenharmony_ci * Retry copy/paste function for VAS failures. 60262306a36Sopenharmony_ci */ 60362306a36Sopenharmony_ci } while (ret && (i++ < VAS_RETRIES)); 60462306a36Sopenharmony_ci 60562306a36Sopenharmony_ci if (ret) { 60662306a36Sopenharmony_ci pr_err_ratelimited("VAS copy/paste failed\n"); 60762306a36Sopenharmony_ci return ret; 60862306a36Sopenharmony_ci } 60962306a36Sopenharmony_ci 61062306a36Sopenharmony_ci ret = wait_for_csb(wmem, csb); 61162306a36Sopenharmony_ci if (!ret) 61262306a36Sopenharmony_ci *outlenp = be32_to_cpu(csb->count); 61362306a36Sopenharmony_ci 61462306a36Sopenharmony_ci return ret; 61562306a36Sopenharmony_ci} 61662306a36Sopenharmony_ci 61762306a36Sopenharmony_ci/** 61862306a36Sopenharmony_ci * nx842_powernv_compress - Compress data using the 842 algorithm 61962306a36Sopenharmony_ci * 62062306a36Sopenharmony_ci * Compression provided by the NX842 coprocessor on IBM PowerNV systems. 62162306a36Sopenharmony_ci * The input buffer is compressed and the result is stored in the 62262306a36Sopenharmony_ci * provided output buffer. 62362306a36Sopenharmony_ci * 62462306a36Sopenharmony_ci * Upon return from this function @outlen contains the length of the 62562306a36Sopenharmony_ci * compressed data. If there is an error then @outlen will be 0 and an 62662306a36Sopenharmony_ci * error will be specified by the return code from this function. 62762306a36Sopenharmony_ci * 62862306a36Sopenharmony_ci * @in: input buffer pointer 62962306a36Sopenharmony_ci * @inlen: input buffer size 63062306a36Sopenharmony_ci * @out: output buffer pointer 63162306a36Sopenharmony_ci * @outlenp: output buffer size pointer 63262306a36Sopenharmony_ci * @wmem: working memory buffer pointer, size determined by 63362306a36Sopenharmony_ci * nx842_powernv_driver.workmem_size 63462306a36Sopenharmony_ci * 63562306a36Sopenharmony_ci * Returns: see @nx842_powernv_exec() 63662306a36Sopenharmony_ci */ 63762306a36Sopenharmony_cistatic int nx842_powernv_compress(const unsigned char *in, unsigned int inlen, 63862306a36Sopenharmony_ci unsigned char *out, unsigned int *outlenp, 63962306a36Sopenharmony_ci void *wmem) 64062306a36Sopenharmony_ci{ 64162306a36Sopenharmony_ci return nx842_powernv_exec(in, inlen, out, outlenp, 64262306a36Sopenharmony_ci wmem, CCW_FC_842_COMP_CRC); 64362306a36Sopenharmony_ci} 64462306a36Sopenharmony_ci 64562306a36Sopenharmony_ci/** 64662306a36Sopenharmony_ci * nx842_powernv_decompress - Decompress data using the 842 algorithm 64762306a36Sopenharmony_ci * 64862306a36Sopenharmony_ci * Decompression provided by the NX842 coprocessor on IBM PowerNV systems. 64962306a36Sopenharmony_ci * The input buffer is decompressed and the result is stored in the 65062306a36Sopenharmony_ci * provided output buffer. 65162306a36Sopenharmony_ci * 65262306a36Sopenharmony_ci * Upon return from this function @outlen contains the length of the 65362306a36Sopenharmony_ci * decompressed data. If there is an error then @outlen will be 0 and an 65462306a36Sopenharmony_ci * error will be specified by the return code from this function. 65562306a36Sopenharmony_ci * 65662306a36Sopenharmony_ci * @in: input buffer pointer 65762306a36Sopenharmony_ci * @inlen: input buffer size 65862306a36Sopenharmony_ci * @out: output buffer pointer 65962306a36Sopenharmony_ci * @outlenp: output buffer size pointer 66062306a36Sopenharmony_ci * @wmem: working memory buffer pointer, size determined by 66162306a36Sopenharmony_ci * nx842_powernv_driver.workmem_size 66262306a36Sopenharmony_ci * 66362306a36Sopenharmony_ci * Returns: see @nx842_powernv_exec() 66462306a36Sopenharmony_ci */ 66562306a36Sopenharmony_cistatic int nx842_powernv_decompress(const unsigned char *in, unsigned int inlen, 66662306a36Sopenharmony_ci unsigned char *out, unsigned int *outlenp, 66762306a36Sopenharmony_ci void *wmem) 66862306a36Sopenharmony_ci{ 66962306a36Sopenharmony_ci return nx842_powernv_exec(in, inlen, out, outlenp, 67062306a36Sopenharmony_ci wmem, CCW_FC_842_DECOMP_CRC); 67162306a36Sopenharmony_ci} 67262306a36Sopenharmony_ci 67362306a36Sopenharmony_cistatic inline void nx_add_coprocs_list(struct nx_coproc *coproc, 67462306a36Sopenharmony_ci int chipid) 67562306a36Sopenharmony_ci{ 67662306a36Sopenharmony_ci coproc->chip_id = chipid; 67762306a36Sopenharmony_ci INIT_LIST_HEAD(&coproc->list); 67862306a36Sopenharmony_ci list_add(&coproc->list, &nx_coprocs); 67962306a36Sopenharmony_ci} 68062306a36Sopenharmony_ci 68162306a36Sopenharmony_cistatic struct vas_window *nx_alloc_txwin(struct nx_coproc *coproc) 68262306a36Sopenharmony_ci{ 68362306a36Sopenharmony_ci struct vas_window *txwin = NULL; 68462306a36Sopenharmony_ci struct vas_tx_win_attr txattr; 68562306a36Sopenharmony_ci 68662306a36Sopenharmony_ci /* 68762306a36Sopenharmony_ci * Kernel requests will be high priority. So open send 68862306a36Sopenharmony_ci * windows only for high priority RxFIFO entries. 68962306a36Sopenharmony_ci */ 69062306a36Sopenharmony_ci vas_init_tx_win_attr(&txattr, coproc->ct); 69162306a36Sopenharmony_ci txattr.lpid = 0; /* lpid is 0 for kernel requests */ 69262306a36Sopenharmony_ci 69362306a36Sopenharmony_ci /* 69462306a36Sopenharmony_ci * Open a VAS send window which is used to send request to NX. 69562306a36Sopenharmony_ci */ 69662306a36Sopenharmony_ci txwin = vas_tx_win_open(coproc->vas.id, coproc->ct, &txattr); 69762306a36Sopenharmony_ci if (IS_ERR(txwin)) 69862306a36Sopenharmony_ci pr_err("ibm,nx-842: Can not open TX window: %ld\n", 69962306a36Sopenharmony_ci PTR_ERR(txwin)); 70062306a36Sopenharmony_ci 70162306a36Sopenharmony_ci return txwin; 70262306a36Sopenharmony_ci} 70362306a36Sopenharmony_ci 70462306a36Sopenharmony_ci/* 70562306a36Sopenharmony_ci * Identify chip ID for each CPU, open send wndow for the corresponding NX 70662306a36Sopenharmony_ci * engine and save txwin in percpu cpu_txwin. 70762306a36Sopenharmony_ci * cpu_txwin is used in copy/paste operation for each compression / 70862306a36Sopenharmony_ci * decompression request. 70962306a36Sopenharmony_ci */ 71062306a36Sopenharmony_cistatic int nx_open_percpu_txwins(void) 71162306a36Sopenharmony_ci{ 71262306a36Sopenharmony_ci struct nx_coproc *coproc, *n; 71362306a36Sopenharmony_ci unsigned int i, chip_id; 71462306a36Sopenharmony_ci 71562306a36Sopenharmony_ci for_each_possible_cpu(i) { 71662306a36Sopenharmony_ci struct vas_window *txwin = NULL; 71762306a36Sopenharmony_ci 71862306a36Sopenharmony_ci chip_id = cpu_to_chip_id(i); 71962306a36Sopenharmony_ci 72062306a36Sopenharmony_ci list_for_each_entry_safe(coproc, n, &nx_coprocs, list) { 72162306a36Sopenharmony_ci /* 72262306a36Sopenharmony_ci * Kernel requests use only high priority FIFOs. So 72362306a36Sopenharmony_ci * open send windows for these FIFOs. 72462306a36Sopenharmony_ci * GZIP is not supported in kernel right now. 72562306a36Sopenharmony_ci */ 72662306a36Sopenharmony_ci 72762306a36Sopenharmony_ci if (coproc->ct != VAS_COP_TYPE_842_HIPRI) 72862306a36Sopenharmony_ci continue; 72962306a36Sopenharmony_ci 73062306a36Sopenharmony_ci if (coproc->chip_id == chip_id) { 73162306a36Sopenharmony_ci txwin = nx_alloc_txwin(coproc); 73262306a36Sopenharmony_ci if (IS_ERR(txwin)) 73362306a36Sopenharmony_ci return PTR_ERR(txwin); 73462306a36Sopenharmony_ci 73562306a36Sopenharmony_ci per_cpu(cpu_txwin, i) = txwin; 73662306a36Sopenharmony_ci break; 73762306a36Sopenharmony_ci } 73862306a36Sopenharmony_ci } 73962306a36Sopenharmony_ci 74062306a36Sopenharmony_ci if (!per_cpu(cpu_txwin, i)) { 74162306a36Sopenharmony_ci /* shouldn't happen, Each chip will have NX engine */ 74262306a36Sopenharmony_ci pr_err("NX engine is not available for CPU %d\n", i); 74362306a36Sopenharmony_ci return -EINVAL; 74462306a36Sopenharmony_ci } 74562306a36Sopenharmony_ci } 74662306a36Sopenharmony_ci 74762306a36Sopenharmony_ci return 0; 74862306a36Sopenharmony_ci} 74962306a36Sopenharmony_ci 75062306a36Sopenharmony_cistatic int __init nx_set_ct(struct nx_coproc *coproc, const char *priority, 75162306a36Sopenharmony_ci int high, int normal) 75262306a36Sopenharmony_ci{ 75362306a36Sopenharmony_ci if (!strcmp(priority, "High")) 75462306a36Sopenharmony_ci coproc->ct = high; 75562306a36Sopenharmony_ci else if (!strcmp(priority, "Normal")) 75662306a36Sopenharmony_ci coproc->ct = normal; 75762306a36Sopenharmony_ci else { 75862306a36Sopenharmony_ci pr_err("Invalid RxFIFO priority value\n"); 75962306a36Sopenharmony_ci return -EINVAL; 76062306a36Sopenharmony_ci } 76162306a36Sopenharmony_ci 76262306a36Sopenharmony_ci return 0; 76362306a36Sopenharmony_ci} 76462306a36Sopenharmony_ci 76562306a36Sopenharmony_cistatic int __init vas_cfg_coproc_info(struct device_node *dn, int chip_id, 76662306a36Sopenharmony_ci int vasid, int type, int *ct) 76762306a36Sopenharmony_ci{ 76862306a36Sopenharmony_ci struct vas_window *rxwin = NULL; 76962306a36Sopenharmony_ci struct vas_rx_win_attr rxattr; 77062306a36Sopenharmony_ci u32 lpid, pid, tid, fifo_size; 77162306a36Sopenharmony_ci struct nx_coproc *coproc; 77262306a36Sopenharmony_ci u64 rx_fifo; 77362306a36Sopenharmony_ci const char *priority; 77462306a36Sopenharmony_ci int ret; 77562306a36Sopenharmony_ci 77662306a36Sopenharmony_ci ret = of_property_read_u64(dn, "rx-fifo-address", &rx_fifo); 77762306a36Sopenharmony_ci if (ret) { 77862306a36Sopenharmony_ci pr_err("Missing rx-fifo-address property\n"); 77962306a36Sopenharmony_ci return ret; 78062306a36Sopenharmony_ci } 78162306a36Sopenharmony_ci 78262306a36Sopenharmony_ci ret = of_property_read_u32(dn, "rx-fifo-size", &fifo_size); 78362306a36Sopenharmony_ci if (ret) { 78462306a36Sopenharmony_ci pr_err("Missing rx-fifo-size property\n"); 78562306a36Sopenharmony_ci return ret; 78662306a36Sopenharmony_ci } 78762306a36Sopenharmony_ci 78862306a36Sopenharmony_ci ret = of_property_read_u32(dn, "lpid", &lpid); 78962306a36Sopenharmony_ci if (ret) { 79062306a36Sopenharmony_ci pr_err("Missing lpid property\n"); 79162306a36Sopenharmony_ci return ret; 79262306a36Sopenharmony_ci } 79362306a36Sopenharmony_ci 79462306a36Sopenharmony_ci ret = of_property_read_u32(dn, "pid", &pid); 79562306a36Sopenharmony_ci if (ret) { 79662306a36Sopenharmony_ci pr_err("Missing pid property\n"); 79762306a36Sopenharmony_ci return ret; 79862306a36Sopenharmony_ci } 79962306a36Sopenharmony_ci 80062306a36Sopenharmony_ci ret = of_property_read_u32(dn, "tid", &tid); 80162306a36Sopenharmony_ci if (ret) { 80262306a36Sopenharmony_ci pr_err("Missing tid property\n"); 80362306a36Sopenharmony_ci return ret; 80462306a36Sopenharmony_ci } 80562306a36Sopenharmony_ci 80662306a36Sopenharmony_ci ret = of_property_read_string(dn, "priority", &priority); 80762306a36Sopenharmony_ci if (ret) { 80862306a36Sopenharmony_ci pr_err("Missing priority property\n"); 80962306a36Sopenharmony_ci return ret; 81062306a36Sopenharmony_ci } 81162306a36Sopenharmony_ci 81262306a36Sopenharmony_ci coproc = kzalloc(sizeof(*coproc), GFP_KERNEL); 81362306a36Sopenharmony_ci if (!coproc) 81462306a36Sopenharmony_ci return -ENOMEM; 81562306a36Sopenharmony_ci 81662306a36Sopenharmony_ci if (type == NX_CT_842) 81762306a36Sopenharmony_ci ret = nx_set_ct(coproc, priority, VAS_COP_TYPE_842_HIPRI, 81862306a36Sopenharmony_ci VAS_COP_TYPE_842); 81962306a36Sopenharmony_ci else if (type == NX_CT_GZIP) 82062306a36Sopenharmony_ci ret = nx_set_ct(coproc, priority, VAS_COP_TYPE_GZIP_HIPRI, 82162306a36Sopenharmony_ci VAS_COP_TYPE_GZIP); 82262306a36Sopenharmony_ci 82362306a36Sopenharmony_ci if (ret) 82462306a36Sopenharmony_ci goto err_out; 82562306a36Sopenharmony_ci 82662306a36Sopenharmony_ci vas_init_rx_win_attr(&rxattr, coproc->ct); 82762306a36Sopenharmony_ci rxattr.rx_fifo = rx_fifo; 82862306a36Sopenharmony_ci rxattr.rx_fifo_size = fifo_size; 82962306a36Sopenharmony_ci rxattr.lnotify_lpid = lpid; 83062306a36Sopenharmony_ci rxattr.lnotify_pid = pid; 83162306a36Sopenharmony_ci rxattr.lnotify_tid = tid; 83262306a36Sopenharmony_ci /* 83362306a36Sopenharmony_ci * Maximum RX window credits can not be more than #CRBs in 83462306a36Sopenharmony_ci * RxFIFO. Otherwise, can get checkstop if RxFIFO overruns. 83562306a36Sopenharmony_ci */ 83662306a36Sopenharmony_ci rxattr.wcreds_max = fifo_size / CRB_SIZE; 83762306a36Sopenharmony_ci 83862306a36Sopenharmony_ci /* 83962306a36Sopenharmony_ci * Open a VAS receice window which is used to configure RxFIFO 84062306a36Sopenharmony_ci * for NX. 84162306a36Sopenharmony_ci */ 84262306a36Sopenharmony_ci rxwin = vas_rx_win_open(vasid, coproc->ct, &rxattr); 84362306a36Sopenharmony_ci if (IS_ERR(rxwin)) { 84462306a36Sopenharmony_ci ret = PTR_ERR(rxwin); 84562306a36Sopenharmony_ci pr_err("setting RxFIFO with VAS failed: %d\n", 84662306a36Sopenharmony_ci ret); 84762306a36Sopenharmony_ci goto err_out; 84862306a36Sopenharmony_ci } 84962306a36Sopenharmony_ci 85062306a36Sopenharmony_ci coproc->vas.rxwin = rxwin; 85162306a36Sopenharmony_ci coproc->vas.id = vasid; 85262306a36Sopenharmony_ci nx_add_coprocs_list(coproc, chip_id); 85362306a36Sopenharmony_ci 85462306a36Sopenharmony_ci /* 85562306a36Sopenharmony_ci * (lpid, pid, tid) combination has to be unique for each 85662306a36Sopenharmony_ci * coprocessor instance in the system. So to make it 85762306a36Sopenharmony_ci * unique, skiboot uses coprocessor type such as 842 or 85862306a36Sopenharmony_ci * GZIP for pid and provides this value to kernel in pid 85962306a36Sopenharmony_ci * device-tree property. 86062306a36Sopenharmony_ci */ 86162306a36Sopenharmony_ci *ct = pid; 86262306a36Sopenharmony_ci 86362306a36Sopenharmony_ci return 0; 86462306a36Sopenharmony_ci 86562306a36Sopenharmony_cierr_out: 86662306a36Sopenharmony_ci kfree(coproc); 86762306a36Sopenharmony_ci return ret; 86862306a36Sopenharmony_ci} 86962306a36Sopenharmony_ci 87062306a36Sopenharmony_cistatic int __init nx_coproc_init(int chip_id, int ct_842, int ct_gzip) 87162306a36Sopenharmony_ci{ 87262306a36Sopenharmony_ci int ret = 0; 87362306a36Sopenharmony_ci 87462306a36Sopenharmony_ci if (opal_check_token(OPAL_NX_COPROC_INIT)) { 87562306a36Sopenharmony_ci ret = opal_nx_coproc_init(chip_id, ct_842); 87662306a36Sopenharmony_ci 87762306a36Sopenharmony_ci if (!ret) 87862306a36Sopenharmony_ci ret = opal_nx_coproc_init(chip_id, ct_gzip); 87962306a36Sopenharmony_ci 88062306a36Sopenharmony_ci if (ret) { 88162306a36Sopenharmony_ci ret = opal_error_code(ret); 88262306a36Sopenharmony_ci pr_err("Failed to initialize NX for chip(%d): %d\n", 88362306a36Sopenharmony_ci chip_id, ret); 88462306a36Sopenharmony_ci } 88562306a36Sopenharmony_ci } else 88662306a36Sopenharmony_ci pr_warn("Firmware doesn't support NX initialization\n"); 88762306a36Sopenharmony_ci 88862306a36Sopenharmony_ci return ret; 88962306a36Sopenharmony_ci} 89062306a36Sopenharmony_ci 89162306a36Sopenharmony_cistatic int __init find_nx_device_tree(struct device_node *dn, int chip_id, 89262306a36Sopenharmony_ci int vasid, int type, char *devname, 89362306a36Sopenharmony_ci int *ct) 89462306a36Sopenharmony_ci{ 89562306a36Sopenharmony_ci int ret = 0; 89662306a36Sopenharmony_ci 89762306a36Sopenharmony_ci if (of_device_is_compatible(dn, devname)) { 89862306a36Sopenharmony_ci ret = vas_cfg_coproc_info(dn, chip_id, vasid, type, ct); 89962306a36Sopenharmony_ci if (ret) 90062306a36Sopenharmony_ci of_node_put(dn); 90162306a36Sopenharmony_ci } 90262306a36Sopenharmony_ci 90362306a36Sopenharmony_ci return ret; 90462306a36Sopenharmony_ci} 90562306a36Sopenharmony_ci 90662306a36Sopenharmony_cistatic int __init nx_powernv_probe_vas(struct device_node *pn) 90762306a36Sopenharmony_ci{ 90862306a36Sopenharmony_ci int chip_id, vasid, ret = 0; 90962306a36Sopenharmony_ci int ct_842 = 0, ct_gzip = 0; 91062306a36Sopenharmony_ci struct device_node *dn; 91162306a36Sopenharmony_ci 91262306a36Sopenharmony_ci chip_id = of_get_ibm_chip_id(pn); 91362306a36Sopenharmony_ci if (chip_id < 0) { 91462306a36Sopenharmony_ci pr_err("ibm,chip-id missing\n"); 91562306a36Sopenharmony_ci return -EINVAL; 91662306a36Sopenharmony_ci } 91762306a36Sopenharmony_ci 91862306a36Sopenharmony_ci vasid = chip_to_vas_id(chip_id); 91962306a36Sopenharmony_ci if (vasid < 0) { 92062306a36Sopenharmony_ci pr_err("Unable to map chip_id %d to vasid\n", chip_id); 92162306a36Sopenharmony_ci return -EINVAL; 92262306a36Sopenharmony_ci } 92362306a36Sopenharmony_ci 92462306a36Sopenharmony_ci for_each_child_of_node(pn, dn) { 92562306a36Sopenharmony_ci ret = find_nx_device_tree(dn, chip_id, vasid, NX_CT_842, 92662306a36Sopenharmony_ci "ibm,p9-nx-842", &ct_842); 92762306a36Sopenharmony_ci 92862306a36Sopenharmony_ci if (!ret) 92962306a36Sopenharmony_ci ret = find_nx_device_tree(dn, chip_id, vasid, 93062306a36Sopenharmony_ci NX_CT_GZIP, "ibm,p9-nx-gzip", &ct_gzip); 93162306a36Sopenharmony_ci 93262306a36Sopenharmony_ci if (ret) { 93362306a36Sopenharmony_ci of_node_put(dn); 93462306a36Sopenharmony_ci return ret; 93562306a36Sopenharmony_ci } 93662306a36Sopenharmony_ci } 93762306a36Sopenharmony_ci 93862306a36Sopenharmony_ci if (!ct_842 || !ct_gzip) { 93962306a36Sopenharmony_ci pr_err("NX FIFO nodes are missing\n"); 94062306a36Sopenharmony_ci return -EINVAL; 94162306a36Sopenharmony_ci } 94262306a36Sopenharmony_ci 94362306a36Sopenharmony_ci /* 94462306a36Sopenharmony_ci * Initialize NX instance for both high and normal priority FIFOs. 94562306a36Sopenharmony_ci */ 94662306a36Sopenharmony_ci ret = nx_coproc_init(chip_id, ct_842, ct_gzip); 94762306a36Sopenharmony_ci 94862306a36Sopenharmony_ci return ret; 94962306a36Sopenharmony_ci} 95062306a36Sopenharmony_ci 95162306a36Sopenharmony_cistatic int __init nx842_powernv_probe(struct device_node *dn) 95262306a36Sopenharmony_ci{ 95362306a36Sopenharmony_ci struct nx_coproc *coproc; 95462306a36Sopenharmony_ci unsigned int ct, ci; 95562306a36Sopenharmony_ci int chip_id; 95662306a36Sopenharmony_ci 95762306a36Sopenharmony_ci chip_id = of_get_ibm_chip_id(dn); 95862306a36Sopenharmony_ci if (chip_id < 0) { 95962306a36Sopenharmony_ci pr_err("ibm,chip-id missing\n"); 96062306a36Sopenharmony_ci return -EINVAL; 96162306a36Sopenharmony_ci } 96262306a36Sopenharmony_ci 96362306a36Sopenharmony_ci if (of_property_read_u32(dn, "ibm,842-coprocessor-type", &ct)) { 96462306a36Sopenharmony_ci pr_err("ibm,842-coprocessor-type missing\n"); 96562306a36Sopenharmony_ci return -EINVAL; 96662306a36Sopenharmony_ci } 96762306a36Sopenharmony_ci 96862306a36Sopenharmony_ci if (of_property_read_u32(dn, "ibm,842-coprocessor-instance", &ci)) { 96962306a36Sopenharmony_ci pr_err("ibm,842-coprocessor-instance missing\n"); 97062306a36Sopenharmony_ci return -EINVAL; 97162306a36Sopenharmony_ci } 97262306a36Sopenharmony_ci 97362306a36Sopenharmony_ci coproc = kzalloc(sizeof(*coproc), GFP_KERNEL); 97462306a36Sopenharmony_ci if (!coproc) 97562306a36Sopenharmony_ci return -ENOMEM; 97662306a36Sopenharmony_ci 97762306a36Sopenharmony_ci coproc->ct = ct; 97862306a36Sopenharmony_ci coproc->ci = ci; 97962306a36Sopenharmony_ci nx_add_coprocs_list(coproc, chip_id); 98062306a36Sopenharmony_ci 98162306a36Sopenharmony_ci pr_info("coprocessor found on chip %d, CT %d CI %d\n", chip_id, ct, ci); 98262306a36Sopenharmony_ci 98362306a36Sopenharmony_ci if (!nx842_ct) 98462306a36Sopenharmony_ci nx842_ct = ct; 98562306a36Sopenharmony_ci else if (nx842_ct != ct) 98662306a36Sopenharmony_ci pr_err("NX842 chip %d, CT %d != first found CT %d\n", 98762306a36Sopenharmony_ci chip_id, ct, nx842_ct); 98862306a36Sopenharmony_ci 98962306a36Sopenharmony_ci return 0; 99062306a36Sopenharmony_ci} 99162306a36Sopenharmony_ci 99262306a36Sopenharmony_cistatic void nx_delete_coprocs(void) 99362306a36Sopenharmony_ci{ 99462306a36Sopenharmony_ci struct nx_coproc *coproc, *n; 99562306a36Sopenharmony_ci struct vas_window *txwin; 99662306a36Sopenharmony_ci int i; 99762306a36Sopenharmony_ci 99862306a36Sopenharmony_ci /* 99962306a36Sopenharmony_ci * close percpu txwins that are opened for the corresponding coproc. 100062306a36Sopenharmony_ci */ 100162306a36Sopenharmony_ci for_each_possible_cpu(i) { 100262306a36Sopenharmony_ci txwin = per_cpu(cpu_txwin, i); 100362306a36Sopenharmony_ci if (txwin) 100462306a36Sopenharmony_ci vas_win_close(txwin); 100562306a36Sopenharmony_ci 100662306a36Sopenharmony_ci per_cpu(cpu_txwin, i) = NULL; 100762306a36Sopenharmony_ci } 100862306a36Sopenharmony_ci 100962306a36Sopenharmony_ci list_for_each_entry_safe(coproc, n, &nx_coprocs, list) { 101062306a36Sopenharmony_ci if (coproc->vas.rxwin) 101162306a36Sopenharmony_ci vas_win_close(coproc->vas.rxwin); 101262306a36Sopenharmony_ci 101362306a36Sopenharmony_ci list_del(&coproc->list); 101462306a36Sopenharmony_ci kfree(coproc); 101562306a36Sopenharmony_ci } 101662306a36Sopenharmony_ci} 101762306a36Sopenharmony_ci 101862306a36Sopenharmony_cistatic struct nx842_constraints nx842_powernv_constraints = { 101962306a36Sopenharmony_ci .alignment = DDE_BUFFER_ALIGN, 102062306a36Sopenharmony_ci .multiple = DDE_BUFFER_LAST_MULT, 102162306a36Sopenharmony_ci .minimum = DDE_BUFFER_LAST_MULT, 102262306a36Sopenharmony_ci .maximum = (DDL_LEN_MAX - 1) * PAGE_SIZE, 102362306a36Sopenharmony_ci}; 102462306a36Sopenharmony_ci 102562306a36Sopenharmony_cistatic struct nx842_driver nx842_powernv_driver = { 102662306a36Sopenharmony_ci .name = KBUILD_MODNAME, 102762306a36Sopenharmony_ci .owner = THIS_MODULE, 102862306a36Sopenharmony_ci .workmem_size = sizeof(struct nx842_workmem), 102962306a36Sopenharmony_ci .constraints = &nx842_powernv_constraints, 103062306a36Sopenharmony_ci .compress = nx842_powernv_compress, 103162306a36Sopenharmony_ci .decompress = nx842_powernv_decompress, 103262306a36Sopenharmony_ci}; 103362306a36Sopenharmony_ci 103462306a36Sopenharmony_cistatic int nx842_powernv_crypto_init(struct crypto_tfm *tfm) 103562306a36Sopenharmony_ci{ 103662306a36Sopenharmony_ci return nx842_crypto_init(tfm, &nx842_powernv_driver); 103762306a36Sopenharmony_ci} 103862306a36Sopenharmony_ci 103962306a36Sopenharmony_cistatic struct crypto_alg nx842_powernv_alg = { 104062306a36Sopenharmony_ci .cra_name = "842", 104162306a36Sopenharmony_ci .cra_driver_name = "842-nx", 104262306a36Sopenharmony_ci .cra_priority = 300, 104362306a36Sopenharmony_ci .cra_flags = CRYPTO_ALG_TYPE_COMPRESS, 104462306a36Sopenharmony_ci .cra_ctxsize = sizeof(struct nx842_crypto_ctx), 104562306a36Sopenharmony_ci .cra_module = THIS_MODULE, 104662306a36Sopenharmony_ci .cra_init = nx842_powernv_crypto_init, 104762306a36Sopenharmony_ci .cra_exit = nx842_crypto_exit, 104862306a36Sopenharmony_ci .cra_u = { .compress = { 104962306a36Sopenharmony_ci .coa_compress = nx842_crypto_compress, 105062306a36Sopenharmony_ci .coa_decompress = nx842_crypto_decompress } } 105162306a36Sopenharmony_ci}; 105262306a36Sopenharmony_ci 105362306a36Sopenharmony_cistatic __init int nx_compress_powernv_init(void) 105462306a36Sopenharmony_ci{ 105562306a36Sopenharmony_ci struct device_node *dn; 105662306a36Sopenharmony_ci int ret; 105762306a36Sopenharmony_ci 105862306a36Sopenharmony_ci /* verify workmem size/align restrictions */ 105962306a36Sopenharmony_ci BUILD_BUG_ON(WORKMEM_ALIGN % CRB_ALIGN); 106062306a36Sopenharmony_ci BUILD_BUG_ON(CRB_ALIGN % DDE_ALIGN); 106162306a36Sopenharmony_ci BUILD_BUG_ON(CRB_SIZE % DDE_ALIGN); 106262306a36Sopenharmony_ci /* verify buffer size/align restrictions */ 106362306a36Sopenharmony_ci BUILD_BUG_ON(PAGE_SIZE % DDE_BUFFER_ALIGN); 106462306a36Sopenharmony_ci BUILD_BUG_ON(DDE_BUFFER_ALIGN % DDE_BUFFER_SIZE_MULT); 106562306a36Sopenharmony_ci BUILD_BUG_ON(DDE_BUFFER_SIZE_MULT % DDE_BUFFER_LAST_MULT); 106662306a36Sopenharmony_ci 106762306a36Sopenharmony_ci for_each_compatible_node(dn, NULL, "ibm,power9-nx") { 106862306a36Sopenharmony_ci ret = nx_powernv_probe_vas(dn); 106962306a36Sopenharmony_ci if (ret) { 107062306a36Sopenharmony_ci nx_delete_coprocs(); 107162306a36Sopenharmony_ci of_node_put(dn); 107262306a36Sopenharmony_ci return ret; 107362306a36Sopenharmony_ci } 107462306a36Sopenharmony_ci } 107562306a36Sopenharmony_ci 107662306a36Sopenharmony_ci if (list_empty(&nx_coprocs)) { 107762306a36Sopenharmony_ci for_each_compatible_node(dn, NULL, "ibm,power-nx") 107862306a36Sopenharmony_ci nx842_powernv_probe(dn); 107962306a36Sopenharmony_ci 108062306a36Sopenharmony_ci if (!nx842_ct) 108162306a36Sopenharmony_ci return -ENODEV; 108262306a36Sopenharmony_ci 108362306a36Sopenharmony_ci nx842_powernv_exec = nx842_exec_icswx; 108462306a36Sopenharmony_ci } else { 108562306a36Sopenharmony_ci /* 108662306a36Sopenharmony_ci * Register VAS user space API for NX GZIP so 108762306a36Sopenharmony_ci * that user space can use GZIP engine. 108862306a36Sopenharmony_ci * Using high FIFO priority for kernel requests and 108962306a36Sopenharmony_ci * normal FIFO priority is assigned for userspace. 109062306a36Sopenharmony_ci * 842 compression is supported only in kernel. 109162306a36Sopenharmony_ci */ 109262306a36Sopenharmony_ci ret = vas_register_api_powernv(THIS_MODULE, VAS_COP_TYPE_GZIP, 109362306a36Sopenharmony_ci "nx-gzip"); 109462306a36Sopenharmony_ci 109562306a36Sopenharmony_ci /* 109662306a36Sopenharmony_ci * GZIP is not supported in kernel right now. 109762306a36Sopenharmony_ci * So open tx windows only for 842. 109862306a36Sopenharmony_ci */ 109962306a36Sopenharmony_ci if (!ret) 110062306a36Sopenharmony_ci ret = nx_open_percpu_txwins(); 110162306a36Sopenharmony_ci 110262306a36Sopenharmony_ci if (ret) { 110362306a36Sopenharmony_ci nx_delete_coprocs(); 110462306a36Sopenharmony_ci return ret; 110562306a36Sopenharmony_ci } 110662306a36Sopenharmony_ci 110762306a36Sopenharmony_ci nx842_powernv_exec = nx842_exec_vas; 110862306a36Sopenharmony_ci } 110962306a36Sopenharmony_ci 111062306a36Sopenharmony_ci ret = crypto_register_alg(&nx842_powernv_alg); 111162306a36Sopenharmony_ci if (ret) { 111262306a36Sopenharmony_ci nx_delete_coprocs(); 111362306a36Sopenharmony_ci return ret; 111462306a36Sopenharmony_ci } 111562306a36Sopenharmony_ci 111662306a36Sopenharmony_ci return 0; 111762306a36Sopenharmony_ci} 111862306a36Sopenharmony_cimodule_init(nx_compress_powernv_init); 111962306a36Sopenharmony_ci 112062306a36Sopenharmony_cistatic void __exit nx_compress_powernv_exit(void) 112162306a36Sopenharmony_ci{ 112262306a36Sopenharmony_ci /* 112362306a36Sopenharmony_ci * GZIP engine is supported only in power9 or later and nx842_ct 112462306a36Sopenharmony_ci * is used on power8 (icswx). 112562306a36Sopenharmony_ci * VAS API for NX GZIP is registered during init for user space 112662306a36Sopenharmony_ci * use. So delete this API use for GZIP engine. 112762306a36Sopenharmony_ci */ 112862306a36Sopenharmony_ci if (!nx842_ct) 112962306a36Sopenharmony_ci vas_unregister_api_powernv(); 113062306a36Sopenharmony_ci 113162306a36Sopenharmony_ci crypto_unregister_alg(&nx842_powernv_alg); 113262306a36Sopenharmony_ci 113362306a36Sopenharmony_ci nx_delete_coprocs(); 113462306a36Sopenharmony_ci} 113562306a36Sopenharmony_cimodule_exit(nx_compress_powernv_exit); 1136