Path: blob/master/drivers/crypto/nx/nx-common-powernv.c
26282 views
// SPDX-License-Identifier: GPL-2.0-or-later1/*2* Driver for IBM PowerNV compression accelerator3*4* Copyright (C) 2015 Dan Streetman, IBM Corp5*/67#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt89#include "nx-842.h"1011#include <crypto/internal/scompress.h>12#include <linux/timer.h>1314#include <asm/prom.h>15#include <asm/icswx.h>16#include <asm/vas.h>17#include <asm/reg.h>18#include <asm/opal-api.h>19#include <asm/opal.h>2021MODULE_LICENSE("GPL");22MODULE_AUTHOR("Dan Streetman <[email protected]>");23MODULE_DESCRIPTION("H/W Compression driver for IBM PowerNV processors");24MODULE_ALIAS_CRYPTO("842");25MODULE_ALIAS_CRYPTO("842-nx");2627#define WORKMEM_ALIGN (CRB_ALIGN)28#define CSB_WAIT_MAX (5000) /* ms */29#define VAS_RETRIES (10)3031struct nx842_workmem {32/* Below fields must be properly aligned */33struct coprocessor_request_block crb; /* CRB_ALIGN align */34struct data_descriptor_entry ddl_in[DDL_LEN_MAX]; /* DDE_ALIGN align */35struct data_descriptor_entry ddl_out[DDL_LEN_MAX]; /* DDE_ALIGN align */36/* Above fields must be properly aligned */3738ktime_t start;3940char padding[WORKMEM_ALIGN]; /* unused, to allow alignment */41} __packed __aligned(WORKMEM_ALIGN);4243struct nx_coproc {44unsigned int chip_id;45unsigned int ct; /* Can be 842 or GZIP high/normal*/46unsigned int ci; /* Coprocessor instance, used with icswx */47struct {48struct vas_window *rxwin;49int id;50} vas;51struct list_head list;52};5354/*55* Send the request to NX engine on the chip for the corresponding CPU56* where the process is executing. Use with VAS function.57*/58static DEFINE_PER_CPU(struct vas_window *, cpu_txwin);5960/* no cpu hotplug on powernv, so this list never changes after init */61static LIST_HEAD(nx_coprocs);62static unsigned int nx842_ct; /* used in icswx function */6364/*65* Using same values as in skiboot or coprocessor type representing66* in NX workbook.67*/68#define NX_CT_GZIP (2) /* on P9 and later */69#define NX_CT_842 (3)7071static int (*nx842_powernv_exec)(const unsigned char *in,72unsigned int inlen, unsigned char *out,73unsigned int *outlenp, void *workmem, int fc);7475/*76* setup_indirect_dde - Setup an indirect DDE77*78* The DDE is setup with the DDE count, byte count, and address of79* first direct DDE in the list.80*/81static void setup_indirect_dde(struct data_descriptor_entry *dde,82struct data_descriptor_entry *ddl,83unsigned int dde_count, unsigned int byte_count)84{85dde->flags = 0;86dde->count = dde_count;87dde->index = 0;88dde->length = cpu_to_be32(byte_count);89dde->address = cpu_to_be64(nx842_get_pa(ddl));90}9192/*93* setup_direct_dde - Setup single DDE from buffer94*95* The DDE is setup with the buffer and length. The buffer must be properly96* aligned. The used length is returned.97* Returns:98* N Successfully set up DDE with N bytes99*/100static unsigned int setup_direct_dde(struct data_descriptor_entry *dde,101unsigned long pa, unsigned int len)102{103unsigned int l = min_t(unsigned int, len, LEN_ON_PAGE(pa));104105dde->flags = 0;106dde->count = 0;107dde->index = 0;108dde->length = cpu_to_be32(l);109dde->address = cpu_to_be64(pa);110111return l;112}113114/*115* setup_ddl - Setup DDL from buffer116*117* Returns:118* 0 Successfully set up DDL119*/120static int setup_ddl(struct data_descriptor_entry *dde,121struct data_descriptor_entry *ddl,122unsigned char *buf, unsigned int len,123bool in)124{125unsigned long pa = nx842_get_pa(buf);126int i, ret, total_len = len;127128if (!IS_ALIGNED(pa, DDE_BUFFER_ALIGN)) {129pr_debug("%s buffer pa 0x%lx not 0x%x-byte aligned\n",130in ? "input" : "output", pa, DDE_BUFFER_ALIGN);131return -EINVAL;132}133134/* only need to check last mult; since buffer must be135* DDE_BUFFER_ALIGN aligned, and that is a multiple of136* DDE_BUFFER_SIZE_MULT, and pre-last page DDE buffers137* are guaranteed a multiple of DDE_BUFFER_SIZE_MULT.138*/139if (len % DDE_BUFFER_LAST_MULT) {140pr_debug("%s buffer len 0x%x not a multiple of 0x%x\n",141in ? "input" : "output", len, DDE_BUFFER_LAST_MULT);142if (in)143return -EINVAL;144len = round_down(len, DDE_BUFFER_LAST_MULT);145}146147/* use a single direct DDE */148if (len <= LEN_ON_PAGE(pa)) {149ret = setup_direct_dde(dde, pa, len);150WARN_ON(ret < len);151return 0;152}153154/* use the DDL */155for (i = 0; i < DDL_LEN_MAX && len > 0; i++) {156ret = setup_direct_dde(&ddl[i], pa, len);157buf += ret;158len -= ret;159pa = nx842_get_pa(buf);160}161162if (len > 0) {163pr_debug("0x%x total %s bytes 0x%x too many for DDL.\n",164total_len, in ? "input" : "output", len);165if (in)166return -EMSGSIZE;167total_len -= len;168}169setup_indirect_dde(dde, ddl, i, total_len);170171return 0;172}173174#define CSB_ERR(csb, msg, ...) \175pr_err("ERROR: " msg " : %02x %02x %02x %02x %08x\n", \176##__VA_ARGS__, (csb)->flags, \177(csb)->cs, (csb)->cc, (csb)->ce, \178be32_to_cpu((csb)->count))179180#define CSB_ERR_ADDR(csb, msg, ...) \181CSB_ERR(csb, msg " at %lx", ##__VA_ARGS__, \182(unsigned long)be64_to_cpu((csb)->address))183184static int wait_for_csb(struct nx842_workmem *wmem,185struct coprocessor_status_block *csb)186{187ktime_t start = wmem->start, now = ktime_get();188ktime_t timeout = ktime_add_ms(start, CSB_WAIT_MAX);189190while (!(READ_ONCE(csb->flags) & CSB_V)) {191cpu_relax();192now = ktime_get();193if (ktime_after(now, timeout))194break;195}196197/* hw has updated csb and output buffer */198barrier();199200/* check CSB flags */201if (!(csb->flags & CSB_V)) {202CSB_ERR(csb, "CSB still not valid after %ld us, giving up",203(long)ktime_us_delta(now, start));204return -ETIMEDOUT;205}206if (csb->flags & CSB_F) {207CSB_ERR(csb, "Invalid CSB format");208return -EPROTO;209}210if (csb->flags & CSB_CH) {211CSB_ERR(csb, "Invalid CSB chaining state");212return -EPROTO;213}214215/* verify CSB completion sequence is 0 */216if (csb->cs) {217CSB_ERR(csb, "Invalid CSB completion sequence");218return -EPROTO;219}220221/* check CSB Completion Code */222switch (csb->cc) {223/* no error */224case CSB_CC_SUCCESS:225break;226case CSB_CC_TPBC_GT_SPBC:227/* not an error, but the compressed data is228* larger than the uncompressed data :(229*/230break;231232/* input data errors */233case CSB_CC_OPERAND_OVERLAP:234/* input and output buffers overlap */235CSB_ERR(csb, "Operand Overlap error");236return -EINVAL;237case CSB_CC_INVALID_OPERAND:238CSB_ERR(csb, "Invalid operand");239return -EINVAL;240case CSB_CC_NOSPC:241/* output buffer too small */242return -ENOSPC;243case CSB_CC_ABORT:244CSB_ERR(csb, "Function aborted");245return -EINTR;246case CSB_CC_CRC_MISMATCH:247CSB_ERR(csb, "CRC mismatch");248return -EINVAL;249case CSB_CC_TEMPL_INVALID:250CSB_ERR(csb, "Compressed data template invalid");251return -EINVAL;252case CSB_CC_TEMPL_OVERFLOW:253CSB_ERR(csb, "Compressed data template shows data past end");254return -EINVAL;255case CSB_CC_EXCEED_BYTE_COUNT: /* P9 or later */256/*257* DDE byte count exceeds the limit specified in Maximum258* byte count register.259*/260CSB_ERR(csb, "DDE byte count exceeds the limit");261return -EINVAL;262263/* these should not happen */264case CSB_CC_INVALID_ALIGN:265/* setup_ddl should have detected this */266CSB_ERR_ADDR(csb, "Invalid alignment");267return -EINVAL;268case CSB_CC_DATA_LENGTH:269/* setup_ddl should have detected this */270CSB_ERR(csb, "Invalid data length");271return -EINVAL;272case CSB_CC_WR_TRANSLATION:273case CSB_CC_TRANSLATION:274case CSB_CC_TRANSLATION_DUP1:275case CSB_CC_TRANSLATION_DUP2:276case CSB_CC_TRANSLATION_DUP3:277case CSB_CC_TRANSLATION_DUP4:278case CSB_CC_TRANSLATION_DUP5:279case CSB_CC_TRANSLATION_DUP6:280/* should not happen, we use physical addrs */281CSB_ERR_ADDR(csb, "Translation error");282return -EPROTO;283case CSB_CC_WR_PROTECTION:284case CSB_CC_PROTECTION:285case CSB_CC_PROTECTION_DUP1:286case CSB_CC_PROTECTION_DUP2:287case CSB_CC_PROTECTION_DUP3:288case CSB_CC_PROTECTION_DUP4:289case CSB_CC_PROTECTION_DUP5:290case CSB_CC_PROTECTION_DUP6:291/* should not happen, we use physical addrs */292CSB_ERR_ADDR(csb, "Protection error");293return -EPROTO;294case CSB_CC_PRIVILEGE:295/* shouldn't happen, we're in HYP mode */296CSB_ERR(csb, "Insufficient Privilege error");297return -EPROTO;298case CSB_CC_EXCESSIVE_DDE:299/* shouldn't happen, setup_ddl doesn't use many dde's */300CSB_ERR(csb, "Too many DDEs in DDL");301return -EINVAL;302case CSB_CC_TRANSPORT:303case CSB_CC_INVALID_CRB: /* P9 or later */304/* shouldn't happen, we setup CRB correctly */305CSB_ERR(csb, "Invalid CRB");306return -EINVAL;307case CSB_CC_INVALID_DDE: /* P9 or later */308/*309* shouldn't happen, setup_direct/indirect_dde creates310* DDE right311*/312CSB_ERR(csb, "Invalid DDE");313return -EINVAL;314case CSB_CC_SEGMENTED_DDL:315/* shouldn't happen, setup_ddl creates DDL right */316CSB_ERR(csb, "Segmented DDL error");317return -EINVAL;318case CSB_CC_DDE_OVERFLOW:319/* shouldn't happen, setup_ddl creates DDL right */320CSB_ERR(csb, "DDE overflow error");321return -EINVAL;322case CSB_CC_SESSION:323/* should not happen with ICSWX */324CSB_ERR(csb, "Session violation error");325return -EPROTO;326case CSB_CC_CHAIN:327/* should not happen, we don't use chained CRBs */328CSB_ERR(csb, "Chained CRB error");329return -EPROTO;330case CSB_CC_SEQUENCE:331/* should not happen, we don't use chained CRBs */332CSB_ERR(csb, "CRB sequence number error");333return -EPROTO;334case CSB_CC_UNKNOWN_CODE:335CSB_ERR(csb, "Unknown subfunction code");336return -EPROTO;337338/* hardware errors */339case CSB_CC_RD_EXTERNAL:340case CSB_CC_RD_EXTERNAL_DUP1:341case CSB_CC_RD_EXTERNAL_DUP2:342case CSB_CC_RD_EXTERNAL_DUP3:343CSB_ERR_ADDR(csb, "Read error outside coprocessor");344return -EPROTO;345case CSB_CC_WR_EXTERNAL:346CSB_ERR_ADDR(csb, "Write error outside coprocessor");347return -EPROTO;348case CSB_CC_INTERNAL:349CSB_ERR(csb, "Internal error in coprocessor");350return -EPROTO;351case CSB_CC_PROVISION:352CSB_ERR(csb, "Storage provision error");353return -EPROTO;354case CSB_CC_HW:355CSB_ERR(csb, "Correctable hardware error");356return -EPROTO;357case CSB_CC_HW_EXPIRED_TIMER: /* P9 or later */358CSB_ERR(csb, "Job did not finish within allowed time");359return -EPROTO;360361default:362CSB_ERR(csb, "Invalid CC %d", csb->cc);363return -EPROTO;364}365366/* check Completion Extension state */367if (csb->ce & CSB_CE_TERMINATION) {368CSB_ERR(csb, "CSB request was terminated");369return -EPROTO;370}371if (csb->ce & CSB_CE_INCOMPLETE) {372CSB_ERR(csb, "CSB request not complete");373return -EPROTO;374}375if (!(csb->ce & CSB_CE_TPBC)) {376CSB_ERR(csb, "TPBC not provided, unknown target length");377return -EPROTO;378}379380/* successful completion */381pr_debug_ratelimited("Processed %u bytes in %lu us\n",382be32_to_cpu(csb->count),383(unsigned long)ktime_us_delta(now, start));384385return 0;386}387388static int nx842_config_crb(const unsigned char *in, unsigned int inlen,389unsigned char *out, unsigned int outlen,390struct nx842_workmem *wmem)391{392struct coprocessor_request_block *crb;393struct coprocessor_status_block *csb;394u64 csb_addr;395int ret;396397crb = &wmem->crb;398csb = &crb->csb;399400/* Clear any previous values */401memset(crb, 0, sizeof(*crb));402403/* set up DDLs */404ret = setup_ddl(&crb->source, wmem->ddl_in,405(unsigned char *)in, inlen, true);406if (ret)407return ret;408409ret = setup_ddl(&crb->target, wmem->ddl_out,410out, outlen, false);411if (ret)412return ret;413414/* set up CRB's CSB addr */415csb_addr = nx842_get_pa(csb) & CRB_CSB_ADDRESS;416csb_addr |= CRB_CSB_AT; /* Addrs are phys */417crb->csb_addr = cpu_to_be64(csb_addr);418419return 0;420}421422/**423* nx842_exec_icswx - compress/decompress data using the 842 algorithm424*425* (De)compression provided by the NX842 coprocessor on IBM PowerNV systems.426* This compresses or decompresses the provided input buffer into the provided427* output buffer.428*429* Upon return from this function @outlen contains the length of the430* output data. If there is an error then @outlen will be 0 and an431* error will be specified by the return code from this function.432*433* The @workmem buffer should only be used by one function call at a time.434*435* @in: input buffer pointer436* @inlen: input buffer size437* @out: output buffer pointer438* @outlenp: output buffer size pointer439* @workmem: working memory buffer pointer, size determined by440* nx842_powernv_driver.workmem_size441* @fc: function code, see CCW Function Codes in nx-842.h442*443* Returns:444* 0 Success, output of length @outlenp stored in the buffer at @out445* -ENODEV Hardware unavailable446* -ENOSPC Output buffer is to small447* -EMSGSIZE Input buffer too large448* -EINVAL buffer constraints do not fix nx842_constraints449* -EPROTO hardware error during operation450* -ETIMEDOUT hardware did not complete operation in reasonable time451* -EINTR operation was aborted452*/453static int nx842_exec_icswx(const unsigned char *in, unsigned int inlen,454unsigned char *out, unsigned int *outlenp,455void *workmem, int fc)456{457struct coprocessor_request_block *crb;458struct coprocessor_status_block *csb;459struct nx842_workmem *wmem;460int ret;461u32 ccw;462unsigned int outlen = *outlenp;463464wmem = PTR_ALIGN(workmem, WORKMEM_ALIGN);465466*outlenp = 0;467468/* shoudn't happen, we don't load without a coproc */469if (!nx842_ct) {470pr_err_ratelimited("coprocessor CT is 0");471return -ENODEV;472}473474ret = nx842_config_crb(in, inlen, out, outlen, wmem);475if (ret)476return ret;477478crb = &wmem->crb;479csb = &crb->csb;480481/* set up CCW */482ccw = 0;483ccw = SET_FIELD(CCW_CT, ccw, nx842_ct);484ccw = SET_FIELD(CCW_CI_842, ccw, 0); /* use 0 for hw auto-selection */485ccw = SET_FIELD(CCW_FC_842, ccw, fc);486487wmem->start = ktime_get();488489/* do ICSWX */490ret = icswx(cpu_to_be32(ccw), crb);491492pr_debug_ratelimited("icswx CR %x ccw %x crb->ccw %x\n", ret,493(unsigned int)ccw,494(unsigned int)be32_to_cpu(crb->ccw));495496/*497* NX842 coprocessor sets 3rd bit in CR register with XER[S0].498* XER[S0] is the integer summary overflow bit which is nothing499* to do NX. Since this bit can be set with other return values,500* mask this bit.501*/502ret &= ~ICSWX_XERS0;503504switch (ret) {505case ICSWX_INITIATED:506ret = wait_for_csb(wmem, csb);507break;508case ICSWX_BUSY:509pr_debug_ratelimited("842 Coprocessor busy\n");510ret = -EBUSY;511break;512case ICSWX_REJECTED:513pr_err_ratelimited("ICSWX rejected\n");514ret = -EPROTO;515break;516}517518if (!ret)519*outlenp = be32_to_cpu(csb->count);520521return ret;522}523524/**525* nx842_exec_vas - compress/decompress data using the 842 algorithm526*527* (De)compression provided by the NX842 coprocessor on IBM PowerNV systems.528* This compresses or decompresses the provided input buffer into the provided529* output buffer.530*531* Upon return from this function @outlen contains the length of the532* output data. If there is an error then @outlen will be 0 and an533* error will be specified by the return code from this function.534*535* The @workmem buffer should only be used by one function call at a time.536*537* @in: input buffer pointer538* @inlen: input buffer size539* @out: output buffer pointer540* @outlenp: output buffer size pointer541* @workmem: working memory buffer pointer, size determined by542* nx842_powernv_driver.workmem_size543* @fc: function code, see CCW Function Codes in nx-842.h544*545* Returns:546* 0 Success, output of length @outlenp stored in the buffer547* at @out548* -ENODEV Hardware unavailable549* -ENOSPC Output buffer is to small550* -EMSGSIZE Input buffer too large551* -EINVAL buffer constraints do not fix nx842_constraints552* -EPROTO hardware error during operation553* -ETIMEDOUT hardware did not complete operation in reasonable time554* -EINTR operation was aborted555*/556static int nx842_exec_vas(const unsigned char *in, unsigned int inlen,557unsigned char *out, unsigned int *outlenp,558void *workmem, int fc)559{560struct coprocessor_request_block *crb;561struct coprocessor_status_block *csb;562struct nx842_workmem *wmem;563struct vas_window *txwin;564int ret, i = 0;565u32 ccw;566unsigned int outlen = *outlenp;567568wmem = PTR_ALIGN(workmem, WORKMEM_ALIGN);569570*outlenp = 0;571572crb = &wmem->crb;573csb = &crb->csb;574575ret = nx842_config_crb(in, inlen, out, outlen, wmem);576if (ret)577return ret;578579ccw = 0;580ccw = SET_FIELD(CCW_FC_842, ccw, fc);581crb->ccw = cpu_to_be32(ccw);582583do {584wmem->start = ktime_get();585preempt_disable();586txwin = this_cpu_read(cpu_txwin);587588/*589* VAS copy CRB into L2 cache. Refer <asm/vas.h>.590* @crb and @offset.591*/592vas_copy_crb(crb, 0);593594/*595* VAS paste previously copied CRB to NX.596* @txwin, @offset and @last (must be true).597*/598ret = vas_paste_crb(txwin, 0, 1);599preempt_enable();600/*601* Retry copy/paste function for VAS failures.602*/603} while (ret && (i++ < VAS_RETRIES));604605if (ret) {606pr_err_ratelimited("VAS copy/paste failed\n");607return ret;608}609610ret = wait_for_csb(wmem, csb);611if (!ret)612*outlenp = be32_to_cpu(csb->count);613614return ret;615}616617/**618* nx842_powernv_compress - Compress data using the 842 algorithm619*620* Compression provided by the NX842 coprocessor on IBM PowerNV systems.621* The input buffer is compressed and the result is stored in the622* provided output buffer.623*624* Upon return from this function @outlen contains the length of the625* compressed data. If there is an error then @outlen will be 0 and an626* error will be specified by the return code from this function.627*628* @in: input buffer pointer629* @inlen: input buffer size630* @out: output buffer pointer631* @outlenp: output buffer size pointer632* @wmem: working memory buffer pointer, size determined by633* nx842_powernv_driver.workmem_size634*635* Returns: see @nx842_powernv_exec()636*/637static int nx842_powernv_compress(const unsigned char *in, unsigned int inlen,638unsigned char *out, unsigned int *outlenp,639void *wmem)640{641return nx842_powernv_exec(in, inlen, out, outlenp,642wmem, CCW_FC_842_COMP_CRC);643}644645/**646* nx842_powernv_decompress - Decompress data using the 842 algorithm647*648* Decompression provided by the NX842 coprocessor on IBM PowerNV systems.649* The input buffer is decompressed and the result is stored in the650* provided output buffer.651*652* Upon return from this function @outlen contains the length of the653* decompressed data. If there is an error then @outlen will be 0 and an654* error will be specified by the return code from this function.655*656* @in: input buffer pointer657* @inlen: input buffer size658* @out: output buffer pointer659* @outlenp: output buffer size pointer660* @wmem: working memory buffer pointer, size determined by661* nx842_powernv_driver.workmem_size662*663* Returns: see @nx842_powernv_exec()664*/665static int nx842_powernv_decompress(const unsigned char *in, unsigned int inlen,666unsigned char *out, unsigned int *outlenp,667void *wmem)668{669return nx842_powernv_exec(in, inlen, out, outlenp,670wmem, CCW_FC_842_DECOMP_CRC);671}672673static inline void nx_add_coprocs_list(struct nx_coproc *coproc,674int chipid)675{676coproc->chip_id = chipid;677INIT_LIST_HEAD(&coproc->list);678list_add(&coproc->list, &nx_coprocs);679}680681static struct vas_window *nx_alloc_txwin(struct nx_coproc *coproc)682{683struct vas_window *txwin = NULL;684struct vas_tx_win_attr txattr;685686/*687* Kernel requests will be high priority. So open send688* windows only for high priority RxFIFO entries.689*/690vas_init_tx_win_attr(&txattr, coproc->ct);691txattr.lpid = 0; /* lpid is 0 for kernel requests */692693/*694* Open a VAS send window which is used to send request to NX.695*/696txwin = vas_tx_win_open(coproc->vas.id, coproc->ct, &txattr);697if (IS_ERR(txwin))698pr_err("ibm,nx-842: Can not open TX window: %ld\n",699PTR_ERR(txwin));700701return txwin;702}703704/*705* Identify chip ID for each CPU, open send wndow for the corresponding NX706* engine and save txwin in percpu cpu_txwin.707* cpu_txwin is used in copy/paste operation for each compression /708* decompression request.709*/710static int nx_open_percpu_txwins(void)711{712struct nx_coproc *coproc, *n;713unsigned int i, chip_id;714715for_each_possible_cpu(i) {716struct vas_window *txwin = NULL;717718chip_id = cpu_to_chip_id(i);719720list_for_each_entry_safe(coproc, n, &nx_coprocs, list) {721/*722* Kernel requests use only high priority FIFOs. So723* open send windows for these FIFOs.724* GZIP is not supported in kernel right now.725*/726727if (coproc->ct != VAS_COP_TYPE_842_HIPRI)728continue;729730if (coproc->chip_id == chip_id) {731txwin = nx_alloc_txwin(coproc);732if (IS_ERR(txwin))733return PTR_ERR(txwin);734735per_cpu(cpu_txwin, i) = txwin;736break;737}738}739740if (!per_cpu(cpu_txwin, i)) {741/* shouldn't happen, Each chip will have NX engine */742pr_err("NX engine is not available for CPU %d\n", i);743return -EINVAL;744}745}746747return 0;748}749750static int __init nx_set_ct(struct nx_coproc *coproc, const char *priority,751int high, int normal)752{753if (!strcmp(priority, "High"))754coproc->ct = high;755else if (!strcmp(priority, "Normal"))756coproc->ct = normal;757else {758pr_err("Invalid RxFIFO priority value\n");759return -EINVAL;760}761762return 0;763}764765static int __init vas_cfg_coproc_info(struct device_node *dn, int chip_id,766int vasid, int type, int *ct)767{768struct vas_window *rxwin = NULL;769struct vas_rx_win_attr rxattr;770u32 lpid, pid, tid, fifo_size;771struct nx_coproc *coproc;772u64 rx_fifo;773const char *priority;774int ret;775776ret = of_property_read_u64(dn, "rx-fifo-address", &rx_fifo);777if (ret) {778pr_err("Missing rx-fifo-address property\n");779return ret;780}781782ret = of_property_read_u32(dn, "rx-fifo-size", &fifo_size);783if (ret) {784pr_err("Missing rx-fifo-size property\n");785return ret;786}787788ret = of_property_read_u32(dn, "lpid", &lpid);789if (ret) {790pr_err("Missing lpid property\n");791return ret;792}793794ret = of_property_read_u32(dn, "pid", &pid);795if (ret) {796pr_err("Missing pid property\n");797return ret;798}799800ret = of_property_read_u32(dn, "tid", &tid);801if (ret) {802pr_err("Missing tid property\n");803return ret;804}805806ret = of_property_read_string(dn, "priority", &priority);807if (ret) {808pr_err("Missing priority property\n");809return ret;810}811812coproc = kzalloc(sizeof(*coproc), GFP_KERNEL);813if (!coproc)814return -ENOMEM;815816if (type == NX_CT_842)817ret = nx_set_ct(coproc, priority, VAS_COP_TYPE_842_HIPRI,818VAS_COP_TYPE_842);819else if (type == NX_CT_GZIP)820ret = nx_set_ct(coproc, priority, VAS_COP_TYPE_GZIP_HIPRI,821VAS_COP_TYPE_GZIP);822823if (ret)824goto err_out;825826vas_init_rx_win_attr(&rxattr, coproc->ct);827rxattr.rx_fifo = rx_fifo;828rxattr.rx_fifo_size = fifo_size;829rxattr.lnotify_lpid = lpid;830rxattr.lnotify_pid = pid;831rxattr.lnotify_tid = tid;832/*833* Maximum RX window credits can not be more than #CRBs in834* RxFIFO. Otherwise, can get checkstop if RxFIFO overruns.835*/836rxattr.wcreds_max = fifo_size / CRB_SIZE;837838/*839* Open a VAS receice window which is used to configure RxFIFO840* for NX.841*/842rxwin = vas_rx_win_open(vasid, coproc->ct, &rxattr);843if (IS_ERR(rxwin)) {844ret = PTR_ERR(rxwin);845pr_err("setting RxFIFO with VAS failed: %d\n",846ret);847goto err_out;848}849850coproc->vas.rxwin = rxwin;851coproc->vas.id = vasid;852nx_add_coprocs_list(coproc, chip_id);853854/*855* (lpid, pid, tid) combination has to be unique for each856* coprocessor instance in the system. So to make it857* unique, skiboot uses coprocessor type such as 842 or858* GZIP for pid and provides this value to kernel in pid859* device-tree property.860*/861*ct = pid;862863return 0;864865err_out:866kfree(coproc);867return ret;868}869870static int __init nx_coproc_init(int chip_id, int ct_842, int ct_gzip)871{872int ret = 0;873874if (opal_check_token(OPAL_NX_COPROC_INIT)) {875ret = opal_nx_coproc_init(chip_id, ct_842);876877if (!ret)878ret = opal_nx_coproc_init(chip_id, ct_gzip);879880if (ret) {881ret = opal_error_code(ret);882pr_err("Failed to initialize NX for chip(%d): %d\n",883chip_id, ret);884}885} else886pr_warn("Firmware doesn't support NX initialization\n");887888return ret;889}890891static int __init find_nx_device_tree(struct device_node *dn, int chip_id,892int vasid, int type, char *devname,893int *ct)894{895int ret = 0;896897if (of_device_is_compatible(dn, devname)) {898ret = vas_cfg_coproc_info(dn, chip_id, vasid, type, ct);899if (ret)900of_node_put(dn);901}902903return ret;904}905906static int __init nx_powernv_probe_vas(struct device_node *pn)907{908int chip_id, vasid, ret = 0;909int ct_842 = 0, ct_gzip = 0;910struct device_node *dn;911912chip_id = of_get_ibm_chip_id(pn);913if (chip_id < 0) {914pr_err("ibm,chip-id missing\n");915return -EINVAL;916}917918vasid = chip_to_vas_id(chip_id);919if (vasid < 0) {920pr_err("Unable to map chip_id %d to vasid\n", chip_id);921return -EINVAL;922}923924for_each_child_of_node(pn, dn) {925ret = find_nx_device_tree(dn, chip_id, vasid, NX_CT_842,926"ibm,p9-nx-842", &ct_842);927928if (!ret)929ret = find_nx_device_tree(dn, chip_id, vasid,930NX_CT_GZIP, "ibm,p9-nx-gzip", &ct_gzip);931932if (ret) {933of_node_put(dn);934return ret;935}936}937938if (!ct_842 || !ct_gzip) {939pr_err("NX FIFO nodes are missing\n");940return -EINVAL;941}942943/*944* Initialize NX instance for both high and normal priority FIFOs.945*/946ret = nx_coproc_init(chip_id, ct_842, ct_gzip);947948return ret;949}950951static int __init nx842_powernv_probe(struct device_node *dn)952{953struct nx_coproc *coproc;954unsigned int ct, ci;955int chip_id;956957chip_id = of_get_ibm_chip_id(dn);958if (chip_id < 0) {959pr_err("ibm,chip-id missing\n");960return -EINVAL;961}962963if (of_property_read_u32(dn, "ibm,842-coprocessor-type", &ct)) {964pr_err("ibm,842-coprocessor-type missing\n");965return -EINVAL;966}967968if (of_property_read_u32(dn, "ibm,842-coprocessor-instance", &ci)) {969pr_err("ibm,842-coprocessor-instance missing\n");970return -EINVAL;971}972973coproc = kzalloc(sizeof(*coproc), GFP_KERNEL);974if (!coproc)975return -ENOMEM;976977coproc->ct = ct;978coproc->ci = ci;979nx_add_coprocs_list(coproc, chip_id);980981pr_info("coprocessor found on chip %d, CT %d CI %d\n", chip_id, ct, ci);982983if (!nx842_ct)984nx842_ct = ct;985else if (nx842_ct != ct)986pr_err("NX842 chip %d, CT %d != first found CT %d\n",987chip_id, ct, nx842_ct);988989return 0;990}991992static void nx_delete_coprocs(void)993{994struct nx_coproc *coproc, *n;995struct vas_window *txwin;996int i;997998/*999* close percpu txwins that are opened for the corresponding coproc.1000*/1001for_each_possible_cpu(i) {1002txwin = per_cpu(cpu_txwin, i);1003if (txwin)1004vas_win_close(txwin);10051006per_cpu(cpu_txwin, i) = NULL;1007}10081009list_for_each_entry_safe(coproc, n, &nx_coprocs, list) {1010if (coproc->vas.rxwin)1011vas_win_close(coproc->vas.rxwin);10121013list_del(&coproc->list);1014kfree(coproc);1015}1016}10171018static struct nx842_constraints nx842_powernv_constraints = {1019.alignment = DDE_BUFFER_ALIGN,1020.multiple = DDE_BUFFER_LAST_MULT,1021.minimum = DDE_BUFFER_LAST_MULT,1022.maximum = (DDL_LEN_MAX - 1) * PAGE_SIZE,1023};10241025static struct nx842_driver nx842_powernv_driver = {1026.name = KBUILD_MODNAME,1027.owner = THIS_MODULE,1028.workmem_size = sizeof(struct nx842_workmem),1029.constraints = &nx842_powernv_constraints,1030.compress = nx842_powernv_compress,1031.decompress = nx842_powernv_decompress,1032};10331034static void *nx842_powernv_crypto_alloc_ctx(void)1035{1036return nx842_crypto_alloc_ctx(&nx842_powernv_driver);1037}10381039static struct scomp_alg nx842_powernv_alg = {1040.base.cra_name = "842",1041.base.cra_driver_name = "842-nx",1042.base.cra_priority = 300,1043.base.cra_module = THIS_MODULE,10441045.alloc_ctx = nx842_powernv_crypto_alloc_ctx,1046.free_ctx = nx842_crypto_free_ctx,1047.compress = nx842_crypto_compress,1048.decompress = nx842_crypto_decompress,1049};10501051static __init int nx_compress_powernv_init(void)1052{1053struct device_node *dn;1054int ret;10551056/* verify workmem size/align restrictions */1057BUILD_BUG_ON(WORKMEM_ALIGN % CRB_ALIGN);1058BUILD_BUG_ON(CRB_ALIGN % DDE_ALIGN);1059BUILD_BUG_ON(CRB_SIZE % DDE_ALIGN);1060/* verify buffer size/align restrictions */1061BUILD_BUG_ON(PAGE_SIZE % DDE_BUFFER_ALIGN);1062BUILD_BUG_ON(DDE_BUFFER_ALIGN % DDE_BUFFER_SIZE_MULT);1063BUILD_BUG_ON(DDE_BUFFER_SIZE_MULT % DDE_BUFFER_LAST_MULT);10641065for_each_compatible_node(dn, NULL, "ibm,power9-nx") {1066ret = nx_powernv_probe_vas(dn);1067if (ret) {1068nx_delete_coprocs();1069of_node_put(dn);1070return ret;1071}1072}10731074if (list_empty(&nx_coprocs)) {1075for_each_compatible_node(dn, NULL, "ibm,power-nx")1076nx842_powernv_probe(dn);10771078if (!nx842_ct)1079return -ENODEV;10801081nx842_powernv_exec = nx842_exec_icswx;1082} else {1083/*1084* Register VAS user space API for NX GZIP so1085* that user space can use GZIP engine.1086* Using high FIFO priority for kernel requests and1087* normal FIFO priority is assigned for userspace.1088* 842 compression is supported only in kernel.1089*/1090ret = vas_register_api_powernv(THIS_MODULE, VAS_COP_TYPE_GZIP,1091"nx-gzip");10921093/*1094* GZIP is not supported in kernel right now.1095* So open tx windows only for 842.1096*/1097if (!ret)1098ret = nx_open_percpu_txwins();10991100if (ret) {1101nx_delete_coprocs();1102return ret;1103}11041105nx842_powernv_exec = nx842_exec_vas;1106}11071108ret = crypto_register_scomp(&nx842_powernv_alg);1109if (ret) {1110nx_delete_coprocs();1111return ret;1112}11131114return 0;1115}1116module_init(nx_compress_powernv_init);11171118static void __exit nx_compress_powernv_exit(void)1119{1120/*1121* GZIP engine is supported only in power9 or later and nx842_ct1122* is used on power8 (icswx).1123* VAS API for NX GZIP is registered during init for user space1124* use. So delete this API use for GZIP engine.1125*/1126if (!nx842_ct)1127vas_unregister_api_powernv();11281129crypto_unregister_scomp(&nx842_powernv_alg);11301131nx_delete_coprocs();1132}1133module_exit(nx_compress_powernv_exit);113411351136