132e091a6SHaren Myneni // SPDX-License-Identifier: GPL-2.0-or-later
232e091a6SHaren Myneni /*
332e091a6SHaren Myneni  * Driver for IBM PowerNV compression accelerator
432e091a6SHaren Myneni  *
532e091a6SHaren Myneni  * Copyright (C) 2015 Dan Streetman, IBM Corp
632e091a6SHaren Myneni  */
732e091a6SHaren Myneni 
832e091a6SHaren Myneni #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
932e091a6SHaren Myneni 
1032e091a6SHaren Myneni #include "nx-842.h"
1132e091a6SHaren Myneni 
1232e091a6SHaren Myneni #include <linux/timer.h>
1332e091a6SHaren Myneni 
1432e091a6SHaren Myneni #include <asm/prom.h>
1532e091a6SHaren Myneni #include <asm/icswx.h>
1632e091a6SHaren Myneni #include <asm/vas.h>
1732e091a6SHaren Myneni #include <asm/reg.h>
1832e091a6SHaren Myneni #include <asm/opal-api.h>
1932e091a6SHaren Myneni #include <asm/opal.h>
2032e091a6SHaren Myneni 
2132e091a6SHaren Myneni MODULE_LICENSE("GPL");
2232e091a6SHaren Myneni MODULE_AUTHOR("Dan Streetman <ddstreet@ieee.org>");
2332e091a6SHaren Myneni MODULE_DESCRIPTION("H/W Compression driver for IBM PowerNV processors");
2432e091a6SHaren Myneni MODULE_ALIAS_CRYPTO("842");
2532e091a6SHaren Myneni MODULE_ALIAS_CRYPTO("842-nx");
2632e091a6SHaren Myneni 
2732e091a6SHaren Myneni #define WORKMEM_ALIGN	(CRB_ALIGN)
2832e091a6SHaren Myneni #define CSB_WAIT_MAX	(5000) /* ms */
2932e091a6SHaren Myneni #define VAS_RETRIES	(10)
3032e091a6SHaren Myneni 
3132e091a6SHaren Myneni struct nx842_workmem {
3232e091a6SHaren Myneni 	/* Below fields must be properly aligned */
3332e091a6SHaren Myneni 	struct coprocessor_request_block crb; /* CRB_ALIGN align */
3432e091a6SHaren Myneni 	struct data_descriptor_entry ddl_in[DDL_LEN_MAX]; /* DDE_ALIGN align */
3532e091a6SHaren Myneni 	struct data_descriptor_entry ddl_out[DDL_LEN_MAX]; /* DDE_ALIGN align */
3632e091a6SHaren Myneni 	/* Above fields must be properly aligned */
3732e091a6SHaren Myneni 
3832e091a6SHaren Myneni 	ktime_t start;
3932e091a6SHaren Myneni 
4032e091a6SHaren Myneni 	char padding[WORKMEM_ALIGN]; /* unused, to allow alignment */
4132e091a6SHaren Myneni } __packed __aligned(WORKMEM_ALIGN);
4232e091a6SHaren Myneni 
434aebf3ceSHaren Myneni struct nx_coproc {
4432e091a6SHaren Myneni 	unsigned int chip_id;
454aebf3ceSHaren Myneni 	unsigned int ct;	/* Can be 842 or GZIP high/normal*/
4632e091a6SHaren Myneni 	unsigned int ci;	/* Coprocessor instance, used with icswx */
4732e091a6SHaren Myneni 	struct {
4832e091a6SHaren Myneni 		struct vas_window *rxwin;
4932e091a6SHaren Myneni 		int id;
5032e091a6SHaren Myneni 	} vas;
5132e091a6SHaren Myneni 	struct list_head list;
5232e091a6SHaren Myneni };
5332e091a6SHaren Myneni 
5432e091a6SHaren Myneni /*
5532e091a6SHaren Myneni  * Send the request to NX engine on the chip for the corresponding CPU
5632e091a6SHaren Myneni  * where the process is executing. Use with VAS function.
5732e091a6SHaren Myneni  */
5832e091a6SHaren Myneni static DEFINE_PER_CPU(struct vas_window *, cpu_txwin);
5932e091a6SHaren Myneni 
6032e091a6SHaren Myneni /* no cpu hotplug on powernv, so this list never changes after init */
614aebf3ceSHaren Myneni static LIST_HEAD(nx_coprocs);
6232e091a6SHaren Myneni static unsigned int nx842_ct;	/* used in icswx function */
6332e091a6SHaren Myneni 
644aebf3ceSHaren Myneni /*
654aebf3ceSHaren Myneni  * Using same values as in skiboot or coprocessor type representing
664aebf3ceSHaren Myneni  * in NX workbook.
674aebf3ceSHaren Myneni  */
681af11ae2SHaren Myneni #define NX_CT_GZIP	(2)	/* on P9 and later */
694aebf3ceSHaren Myneni #define NX_CT_842	(3)
704aebf3ceSHaren Myneni 
7132e091a6SHaren Myneni static int (*nx842_powernv_exec)(const unsigned char *in,
7232e091a6SHaren Myneni 				unsigned int inlen, unsigned char *out,
7332e091a6SHaren Myneni 				unsigned int *outlenp, void *workmem, int fc);
7432e091a6SHaren Myneni 
75*6084466eSHerbert Xu /*
7632e091a6SHaren Myneni  * setup_indirect_dde - Setup an indirect DDE
7732e091a6SHaren Myneni  *
7854a8b680SJiang Jian  * The DDE is setup with the DDE count, byte count, and address of
7932e091a6SHaren Myneni  * first direct DDE in the list.
8032e091a6SHaren Myneni  */
setup_indirect_dde(struct data_descriptor_entry * dde,struct data_descriptor_entry * ddl,unsigned int dde_count,unsigned int byte_count)8132e091a6SHaren Myneni static void setup_indirect_dde(struct data_descriptor_entry *dde,
8232e091a6SHaren Myneni 			       struct data_descriptor_entry *ddl,
8332e091a6SHaren Myneni 			       unsigned int dde_count, unsigned int byte_count)
8432e091a6SHaren Myneni {
8532e091a6SHaren Myneni 	dde->flags = 0;
8632e091a6SHaren Myneni 	dde->count = dde_count;
8732e091a6SHaren Myneni 	dde->index = 0;
8832e091a6SHaren Myneni 	dde->length = cpu_to_be32(byte_count);
8932e091a6SHaren Myneni 	dde->address = cpu_to_be64(nx842_get_pa(ddl));
9032e091a6SHaren Myneni }
9132e091a6SHaren Myneni 
92*6084466eSHerbert Xu /*
9332e091a6SHaren Myneni  * setup_direct_dde - Setup single DDE from buffer
9432e091a6SHaren Myneni  *
9532e091a6SHaren Myneni  * The DDE is setup with the buffer and length.  The buffer must be properly
9632e091a6SHaren Myneni  * aligned.  The used length is returned.
9732e091a6SHaren Myneni  * Returns:
9832e091a6SHaren Myneni  *   N    Successfully set up DDE with N bytes
9932e091a6SHaren Myneni  */
setup_direct_dde(struct data_descriptor_entry * dde,unsigned long pa,unsigned int len)10032e091a6SHaren Myneni static unsigned int setup_direct_dde(struct data_descriptor_entry *dde,
10132e091a6SHaren Myneni 				     unsigned long pa, unsigned int len)
10232e091a6SHaren Myneni {
10332e091a6SHaren Myneni 	unsigned int l = min_t(unsigned int, len, LEN_ON_PAGE(pa));
10432e091a6SHaren Myneni 
10532e091a6SHaren Myneni 	dde->flags = 0;
10632e091a6SHaren Myneni 	dde->count = 0;
10732e091a6SHaren Myneni 	dde->index = 0;
10832e091a6SHaren Myneni 	dde->length = cpu_to_be32(l);
10932e091a6SHaren Myneni 	dde->address = cpu_to_be64(pa);
11032e091a6SHaren Myneni 
11132e091a6SHaren Myneni 	return l;
11232e091a6SHaren Myneni }
11332e091a6SHaren Myneni 
114*6084466eSHerbert Xu /*
11532e091a6SHaren Myneni  * setup_ddl - Setup DDL from buffer
11632e091a6SHaren Myneni  *
11732e091a6SHaren Myneni  * Returns:
11832e091a6SHaren Myneni  *   0		Successfully set up DDL
11932e091a6SHaren Myneni  */
setup_ddl(struct data_descriptor_entry * dde,struct data_descriptor_entry * ddl,unsigned char * buf,unsigned int len,bool in)12032e091a6SHaren Myneni static int setup_ddl(struct data_descriptor_entry *dde,
12132e091a6SHaren Myneni 		     struct data_descriptor_entry *ddl,
12232e091a6SHaren Myneni 		     unsigned char *buf, unsigned int len,
12332e091a6SHaren Myneni 		     bool in)
12432e091a6SHaren Myneni {
12532e091a6SHaren Myneni 	unsigned long pa = nx842_get_pa(buf);
12632e091a6SHaren Myneni 	int i, ret, total_len = len;
12732e091a6SHaren Myneni 
12832e091a6SHaren Myneni 	if (!IS_ALIGNED(pa, DDE_BUFFER_ALIGN)) {
12932e091a6SHaren Myneni 		pr_debug("%s buffer pa 0x%lx not 0x%x-byte aligned\n",
13032e091a6SHaren Myneni 			 in ? "input" : "output", pa, DDE_BUFFER_ALIGN);
13132e091a6SHaren Myneni 		return -EINVAL;
13232e091a6SHaren Myneni 	}
13332e091a6SHaren Myneni 
13432e091a6SHaren Myneni 	/* only need to check last mult; since buffer must be
13532e091a6SHaren Myneni 	 * DDE_BUFFER_ALIGN aligned, and that is a multiple of
13632e091a6SHaren Myneni 	 * DDE_BUFFER_SIZE_MULT, and pre-last page DDE buffers
13732e091a6SHaren Myneni 	 * are guaranteed a multiple of DDE_BUFFER_SIZE_MULT.
13832e091a6SHaren Myneni 	 */
13932e091a6SHaren Myneni 	if (len % DDE_BUFFER_LAST_MULT) {
14032e091a6SHaren Myneni 		pr_debug("%s buffer len 0x%x not a multiple of 0x%x\n",
14132e091a6SHaren Myneni 			 in ? "input" : "output", len, DDE_BUFFER_LAST_MULT);
14232e091a6SHaren Myneni 		if (in)
14332e091a6SHaren Myneni 			return -EINVAL;
14432e091a6SHaren Myneni 		len = round_down(len, DDE_BUFFER_LAST_MULT);
14532e091a6SHaren Myneni 	}
14632e091a6SHaren Myneni 
14732e091a6SHaren Myneni 	/* use a single direct DDE */
14832e091a6SHaren Myneni 	if (len <= LEN_ON_PAGE(pa)) {
14932e091a6SHaren Myneni 		ret = setup_direct_dde(dde, pa, len);
15032e091a6SHaren Myneni 		WARN_ON(ret < len);
15132e091a6SHaren Myneni 		return 0;
15232e091a6SHaren Myneni 	}
15332e091a6SHaren Myneni 
15432e091a6SHaren Myneni 	/* use the DDL */
15532e091a6SHaren Myneni 	for (i = 0; i < DDL_LEN_MAX && len > 0; i++) {
15632e091a6SHaren Myneni 		ret = setup_direct_dde(&ddl[i], pa, len);
15732e091a6SHaren Myneni 		buf += ret;
15832e091a6SHaren Myneni 		len -= ret;
15932e091a6SHaren Myneni 		pa = nx842_get_pa(buf);
16032e091a6SHaren Myneni 	}
16132e091a6SHaren Myneni 
16232e091a6SHaren Myneni 	if (len > 0) {
16332e091a6SHaren Myneni 		pr_debug("0x%x total %s bytes 0x%x too many for DDL.\n",
16432e091a6SHaren Myneni 			 total_len, in ? "input" : "output", len);
16532e091a6SHaren Myneni 		if (in)
16632e091a6SHaren Myneni 			return -EMSGSIZE;
16732e091a6SHaren Myneni 		total_len -= len;
16832e091a6SHaren Myneni 	}
16932e091a6SHaren Myneni 	setup_indirect_dde(dde, ddl, i, total_len);
17032e091a6SHaren Myneni 
17132e091a6SHaren Myneni 	return 0;
17232e091a6SHaren Myneni }
17332e091a6SHaren Myneni 
17432e091a6SHaren Myneni #define CSB_ERR(csb, msg, ...)					\
17532e091a6SHaren Myneni 	pr_err("ERROR: " msg " : %02x %02x %02x %02x %08x\n",	\
17632e091a6SHaren Myneni 	       ##__VA_ARGS__, (csb)->flags,			\
17732e091a6SHaren Myneni 	       (csb)->cs, (csb)->cc, (csb)->ce,			\
17832e091a6SHaren Myneni 	       be32_to_cpu((csb)->count))
17932e091a6SHaren Myneni 
18032e091a6SHaren Myneni #define CSB_ERR_ADDR(csb, msg, ...)				\
18132e091a6SHaren Myneni 	CSB_ERR(csb, msg " at %lx", ##__VA_ARGS__,		\
18232e091a6SHaren Myneni 		(unsigned long)be64_to_cpu((csb)->address))
18332e091a6SHaren Myneni 
wait_for_csb(struct nx842_workmem * wmem,struct coprocessor_status_block * csb)18432e091a6SHaren Myneni static int wait_for_csb(struct nx842_workmem *wmem,
18532e091a6SHaren Myneni 			struct coprocessor_status_block *csb)
18632e091a6SHaren Myneni {
18732e091a6SHaren Myneni 	ktime_t start = wmem->start, now = ktime_get();
18832e091a6SHaren Myneni 	ktime_t timeout = ktime_add_ms(start, CSB_WAIT_MAX);
18932e091a6SHaren Myneni 
19032e091a6SHaren Myneni 	while (!(READ_ONCE(csb->flags) & CSB_V)) {
19132e091a6SHaren Myneni 		cpu_relax();
19232e091a6SHaren Myneni 		now = ktime_get();
19332e091a6SHaren Myneni 		if (ktime_after(now, timeout))
19432e091a6SHaren Myneni 			break;
19532e091a6SHaren Myneni 	}
19632e091a6SHaren Myneni 
19732e091a6SHaren Myneni 	/* hw has updated csb and output buffer */
19832e091a6SHaren Myneni 	barrier();
19932e091a6SHaren Myneni 
20032e091a6SHaren Myneni 	/* check CSB flags */
20132e091a6SHaren Myneni 	if (!(csb->flags & CSB_V)) {
20232e091a6SHaren Myneni 		CSB_ERR(csb, "CSB still not valid after %ld us, giving up",
20332e091a6SHaren Myneni 			(long)ktime_us_delta(now, start));
20432e091a6SHaren Myneni 		return -ETIMEDOUT;
20532e091a6SHaren Myneni 	}
20632e091a6SHaren Myneni 	if (csb->flags & CSB_F) {
20732e091a6SHaren Myneni 		CSB_ERR(csb, "Invalid CSB format");
20832e091a6SHaren Myneni 		return -EPROTO;
20932e091a6SHaren Myneni 	}
21032e091a6SHaren Myneni 	if (csb->flags & CSB_CH) {
21132e091a6SHaren Myneni 		CSB_ERR(csb, "Invalid CSB chaining state");
21232e091a6SHaren Myneni 		return -EPROTO;
21332e091a6SHaren Myneni 	}
21432e091a6SHaren Myneni 
21532e091a6SHaren Myneni 	/* verify CSB completion sequence is 0 */
21632e091a6SHaren Myneni 	if (csb->cs) {
21732e091a6SHaren Myneni 		CSB_ERR(csb, "Invalid CSB completion sequence");
21832e091a6SHaren Myneni 		return -EPROTO;
21932e091a6SHaren Myneni 	}
22032e091a6SHaren Myneni 
22132e091a6SHaren Myneni 	/* check CSB Completion Code */
22232e091a6SHaren Myneni 	switch (csb->cc) {
22332e091a6SHaren Myneni 	/* no error */
22432e091a6SHaren Myneni 	case CSB_CC_SUCCESS:
22532e091a6SHaren Myneni 		break;
22632e091a6SHaren Myneni 	case CSB_CC_TPBC_GT_SPBC:
22732e091a6SHaren Myneni 		/* not an error, but the compressed data is
22832e091a6SHaren Myneni 		 * larger than the uncompressed data :(
22932e091a6SHaren Myneni 		 */
23032e091a6SHaren Myneni 		break;
23132e091a6SHaren Myneni 
23232e091a6SHaren Myneni 	/* input data errors */
23332e091a6SHaren Myneni 	case CSB_CC_OPERAND_OVERLAP:
23432e091a6SHaren Myneni 		/* input and output buffers overlap */
23532e091a6SHaren Myneni 		CSB_ERR(csb, "Operand Overlap error");
23632e091a6SHaren Myneni 		return -EINVAL;
23732e091a6SHaren Myneni 	case CSB_CC_INVALID_OPERAND:
23832e091a6SHaren Myneni 		CSB_ERR(csb, "Invalid operand");
23932e091a6SHaren Myneni 		return -EINVAL;
24032e091a6SHaren Myneni 	case CSB_CC_NOSPC:
24132e091a6SHaren Myneni 		/* output buffer too small */
24232e091a6SHaren Myneni 		return -ENOSPC;
24332e091a6SHaren Myneni 	case CSB_CC_ABORT:
24432e091a6SHaren Myneni 		CSB_ERR(csb, "Function aborted");
24532e091a6SHaren Myneni 		return -EINTR;
24632e091a6SHaren Myneni 	case CSB_CC_CRC_MISMATCH:
24732e091a6SHaren Myneni 		CSB_ERR(csb, "CRC mismatch");
24832e091a6SHaren Myneni 		return -EINVAL;
24932e091a6SHaren Myneni 	case CSB_CC_TEMPL_INVALID:
25032e091a6SHaren Myneni 		CSB_ERR(csb, "Compressed data template invalid");
25132e091a6SHaren Myneni 		return -EINVAL;
25232e091a6SHaren Myneni 	case CSB_CC_TEMPL_OVERFLOW:
25332e091a6SHaren Myneni 		CSB_ERR(csb, "Compressed data template shows data past end");
25432e091a6SHaren Myneni 		return -EINVAL;
25532e091a6SHaren Myneni 	case CSB_CC_EXCEED_BYTE_COUNT:	/* P9 or later */
25632e091a6SHaren Myneni 		/*
25732e091a6SHaren Myneni 		 * DDE byte count exceeds the limit specified in Maximum
25832e091a6SHaren Myneni 		 * byte count register.
25932e091a6SHaren Myneni 		 */
26032e091a6SHaren Myneni 		CSB_ERR(csb, "DDE byte count exceeds the limit");
26132e091a6SHaren Myneni 		return -EINVAL;
26232e091a6SHaren Myneni 
26332e091a6SHaren Myneni 	/* these should not happen */
26432e091a6SHaren Myneni 	case CSB_CC_INVALID_ALIGN:
26532e091a6SHaren Myneni 		/* setup_ddl should have detected this */
26632e091a6SHaren Myneni 		CSB_ERR_ADDR(csb, "Invalid alignment");
26732e091a6SHaren Myneni 		return -EINVAL;
26832e091a6SHaren Myneni 	case CSB_CC_DATA_LENGTH:
26932e091a6SHaren Myneni 		/* setup_ddl should have detected this */
27032e091a6SHaren Myneni 		CSB_ERR(csb, "Invalid data length");
27132e091a6SHaren Myneni 		return -EINVAL;
27232e091a6SHaren Myneni 	case CSB_CC_WR_TRANSLATION:
27332e091a6SHaren Myneni 	case CSB_CC_TRANSLATION:
27432e091a6SHaren Myneni 	case CSB_CC_TRANSLATION_DUP1:
27532e091a6SHaren Myneni 	case CSB_CC_TRANSLATION_DUP2:
27632e091a6SHaren Myneni 	case CSB_CC_TRANSLATION_DUP3:
27732e091a6SHaren Myneni 	case CSB_CC_TRANSLATION_DUP4:
27832e091a6SHaren Myneni 	case CSB_CC_TRANSLATION_DUP5:
27932e091a6SHaren Myneni 	case CSB_CC_TRANSLATION_DUP6:
28032e091a6SHaren Myneni 		/* should not happen, we use physical addrs */
28132e091a6SHaren Myneni 		CSB_ERR_ADDR(csb, "Translation error");
28232e091a6SHaren Myneni 		return -EPROTO;
28332e091a6SHaren Myneni 	case CSB_CC_WR_PROTECTION:
28432e091a6SHaren Myneni 	case CSB_CC_PROTECTION:
28532e091a6SHaren Myneni 	case CSB_CC_PROTECTION_DUP1:
28632e091a6SHaren Myneni 	case CSB_CC_PROTECTION_DUP2:
28732e091a6SHaren Myneni 	case CSB_CC_PROTECTION_DUP3:
28832e091a6SHaren Myneni 	case CSB_CC_PROTECTION_DUP4:
28932e091a6SHaren Myneni 	case CSB_CC_PROTECTION_DUP5:
29032e091a6SHaren Myneni 	case CSB_CC_PROTECTION_DUP6:
29132e091a6SHaren Myneni 		/* should not happen, we use physical addrs */
29232e091a6SHaren Myneni 		CSB_ERR_ADDR(csb, "Protection error");
29332e091a6SHaren Myneni 		return -EPROTO;
29432e091a6SHaren Myneni 	case CSB_CC_PRIVILEGE:
29532e091a6SHaren Myneni 		/* shouldn't happen, we're in HYP mode */
29632e091a6SHaren Myneni 		CSB_ERR(csb, "Insufficient Privilege error");
29732e091a6SHaren Myneni 		return -EPROTO;
29832e091a6SHaren Myneni 	case CSB_CC_EXCESSIVE_DDE:
29932e091a6SHaren Myneni 		/* shouldn't happen, setup_ddl doesn't use many dde's */
30032e091a6SHaren Myneni 		CSB_ERR(csb, "Too many DDEs in DDL");
30132e091a6SHaren Myneni 		return -EINVAL;
30232e091a6SHaren Myneni 	case CSB_CC_TRANSPORT:
30332e091a6SHaren Myneni 	case CSB_CC_INVALID_CRB:	/* P9 or later */
30432e091a6SHaren Myneni 		/* shouldn't happen, we setup CRB correctly */
30532e091a6SHaren Myneni 		CSB_ERR(csb, "Invalid CRB");
30632e091a6SHaren Myneni 		return -EINVAL;
30732e091a6SHaren Myneni 	case CSB_CC_INVALID_DDE:	/* P9 or later */
30832e091a6SHaren Myneni 		/*
30932e091a6SHaren Myneni 		 * shouldn't happen, setup_direct/indirect_dde creates
31032e091a6SHaren Myneni 		 * DDE right
31132e091a6SHaren Myneni 		 */
31232e091a6SHaren Myneni 		CSB_ERR(csb, "Invalid DDE");
31332e091a6SHaren Myneni 		return -EINVAL;
31432e091a6SHaren Myneni 	case CSB_CC_SEGMENTED_DDL:
31532e091a6SHaren Myneni 		/* shouldn't happen, setup_ddl creates DDL right */
31632e091a6SHaren Myneni 		CSB_ERR(csb, "Segmented DDL error");
31732e091a6SHaren Myneni 		return -EINVAL;
31832e091a6SHaren Myneni 	case CSB_CC_DDE_OVERFLOW:
31932e091a6SHaren Myneni 		/* shouldn't happen, setup_ddl creates DDL right */
32032e091a6SHaren Myneni 		CSB_ERR(csb, "DDE overflow error");
32132e091a6SHaren Myneni 		return -EINVAL;
32232e091a6SHaren Myneni 	case CSB_CC_SESSION:
32332e091a6SHaren Myneni 		/* should not happen with ICSWX */
32432e091a6SHaren Myneni 		CSB_ERR(csb, "Session violation error");
32532e091a6SHaren Myneni 		return -EPROTO;
32632e091a6SHaren Myneni 	case CSB_CC_CHAIN:
32732e091a6SHaren Myneni 		/* should not happen, we don't use chained CRBs */
32832e091a6SHaren Myneni 		CSB_ERR(csb, "Chained CRB error");
32932e091a6SHaren Myneni 		return -EPROTO;
33032e091a6SHaren Myneni 	case CSB_CC_SEQUENCE:
33132e091a6SHaren Myneni 		/* should not happen, we don't use chained CRBs */
33232e091a6SHaren Myneni 		CSB_ERR(csb, "CRB sequence number error");
33332e091a6SHaren Myneni 		return -EPROTO;
33432e091a6SHaren Myneni 	case CSB_CC_UNKNOWN_CODE:
33532e091a6SHaren Myneni 		CSB_ERR(csb, "Unknown subfunction code");
33632e091a6SHaren Myneni 		return -EPROTO;
33732e091a6SHaren Myneni 
33832e091a6SHaren Myneni 	/* hardware errors */
33932e091a6SHaren Myneni 	case CSB_CC_RD_EXTERNAL:
34032e091a6SHaren Myneni 	case CSB_CC_RD_EXTERNAL_DUP1:
34132e091a6SHaren Myneni 	case CSB_CC_RD_EXTERNAL_DUP2:
34232e091a6SHaren Myneni 	case CSB_CC_RD_EXTERNAL_DUP3:
34332e091a6SHaren Myneni 		CSB_ERR_ADDR(csb, "Read error outside coprocessor");
34432e091a6SHaren Myneni 		return -EPROTO;
34532e091a6SHaren Myneni 	case CSB_CC_WR_EXTERNAL:
34632e091a6SHaren Myneni 		CSB_ERR_ADDR(csb, "Write error outside coprocessor");
34732e091a6SHaren Myneni 		return -EPROTO;
34832e091a6SHaren Myneni 	case CSB_CC_INTERNAL:
34932e091a6SHaren Myneni 		CSB_ERR(csb, "Internal error in coprocessor");
35032e091a6SHaren Myneni 		return -EPROTO;
35132e091a6SHaren Myneni 	case CSB_CC_PROVISION:
35232e091a6SHaren Myneni 		CSB_ERR(csb, "Storage provision error");
35332e091a6SHaren Myneni 		return -EPROTO;
35432e091a6SHaren Myneni 	case CSB_CC_HW:
35532e091a6SHaren Myneni 		CSB_ERR(csb, "Correctable hardware error");
35632e091a6SHaren Myneni 		return -EPROTO;
35732e091a6SHaren Myneni 	case CSB_CC_HW_EXPIRED_TIMER:	/* P9 or later */
35832e091a6SHaren Myneni 		CSB_ERR(csb, "Job did not finish within allowed time");
35932e091a6SHaren Myneni 		return -EPROTO;
36032e091a6SHaren Myneni 
36132e091a6SHaren Myneni 	default:
36232e091a6SHaren Myneni 		CSB_ERR(csb, "Invalid CC %d", csb->cc);
36332e091a6SHaren Myneni 		return -EPROTO;
36432e091a6SHaren Myneni 	}
36532e091a6SHaren Myneni 
36632e091a6SHaren Myneni 	/* check Completion Extension state */
36732e091a6SHaren Myneni 	if (csb->ce & CSB_CE_TERMINATION) {
36832e091a6SHaren Myneni 		CSB_ERR(csb, "CSB request was terminated");
36932e091a6SHaren Myneni 		return -EPROTO;
37032e091a6SHaren Myneni 	}
37132e091a6SHaren Myneni 	if (csb->ce & CSB_CE_INCOMPLETE) {
37232e091a6SHaren Myneni 		CSB_ERR(csb, "CSB request not complete");
37332e091a6SHaren Myneni 		return -EPROTO;
37432e091a6SHaren Myneni 	}
37532e091a6SHaren Myneni 	if (!(csb->ce & CSB_CE_TPBC)) {
37632e091a6SHaren Myneni 		CSB_ERR(csb, "TPBC not provided, unknown target length");
37732e091a6SHaren Myneni 		return -EPROTO;
37832e091a6SHaren Myneni 	}
37932e091a6SHaren Myneni 
38032e091a6SHaren Myneni 	/* successful completion */
38132e091a6SHaren Myneni 	pr_debug_ratelimited("Processed %u bytes in %lu us\n",
38232e091a6SHaren Myneni 			     be32_to_cpu(csb->count),
38332e091a6SHaren Myneni 			     (unsigned long)ktime_us_delta(now, start));
38432e091a6SHaren Myneni 
38532e091a6SHaren Myneni 	return 0;
38632e091a6SHaren Myneni }
38732e091a6SHaren Myneni 
nx842_config_crb(const unsigned char * in,unsigned int inlen,unsigned char * out,unsigned int outlen,struct nx842_workmem * wmem)38832e091a6SHaren Myneni static int nx842_config_crb(const unsigned char *in, unsigned int inlen,
38932e091a6SHaren Myneni 			unsigned char *out, unsigned int outlen,
39032e091a6SHaren Myneni 			struct nx842_workmem *wmem)
39132e091a6SHaren Myneni {
39232e091a6SHaren Myneni 	struct coprocessor_request_block *crb;
39332e091a6SHaren Myneni 	struct coprocessor_status_block *csb;
39432e091a6SHaren Myneni 	u64 csb_addr;
39532e091a6SHaren Myneni 	int ret;
39632e091a6SHaren Myneni 
39732e091a6SHaren Myneni 	crb = &wmem->crb;
39832e091a6SHaren Myneni 	csb = &crb->csb;
39932e091a6SHaren Myneni 
40032e091a6SHaren Myneni 	/* Clear any previous values */
40132e091a6SHaren Myneni 	memset(crb, 0, sizeof(*crb));
40232e091a6SHaren Myneni 
40332e091a6SHaren Myneni 	/* set up DDLs */
40432e091a6SHaren Myneni 	ret = setup_ddl(&crb->source, wmem->ddl_in,
40532e091a6SHaren Myneni 			(unsigned char *)in, inlen, true);
40632e091a6SHaren Myneni 	if (ret)
40732e091a6SHaren Myneni 		return ret;
40832e091a6SHaren Myneni 
40932e091a6SHaren Myneni 	ret = setup_ddl(&crb->target, wmem->ddl_out,
41032e091a6SHaren Myneni 			out, outlen, false);
41132e091a6SHaren Myneni 	if (ret)
41232e091a6SHaren Myneni 		return ret;
41332e091a6SHaren Myneni 
41432e091a6SHaren Myneni 	/* set up CRB's CSB addr */
41532e091a6SHaren Myneni 	csb_addr = nx842_get_pa(csb) & CRB_CSB_ADDRESS;
41632e091a6SHaren Myneni 	csb_addr |= CRB_CSB_AT; /* Addrs are phys */
41732e091a6SHaren Myneni 	crb->csb_addr = cpu_to_be64(csb_addr);
41832e091a6SHaren Myneni 
41932e091a6SHaren Myneni 	return 0;
42032e091a6SHaren Myneni }
42132e091a6SHaren Myneni 
42232e091a6SHaren Myneni /**
42332e091a6SHaren Myneni  * nx842_exec_icswx - compress/decompress data using the 842 algorithm
42432e091a6SHaren Myneni  *
42532e091a6SHaren Myneni  * (De)compression provided by the NX842 coprocessor on IBM PowerNV systems.
42632e091a6SHaren Myneni  * This compresses or decompresses the provided input buffer into the provided
42732e091a6SHaren Myneni  * output buffer.
42832e091a6SHaren Myneni  *
42932e091a6SHaren Myneni  * Upon return from this function @outlen contains the length of the
43032e091a6SHaren Myneni  * output data.  If there is an error then @outlen will be 0 and an
43132e091a6SHaren Myneni  * error will be specified by the return code from this function.
43232e091a6SHaren Myneni  *
43332e091a6SHaren Myneni  * The @workmem buffer should only be used by one function call at a time.
43432e091a6SHaren Myneni  *
43532e091a6SHaren Myneni  * @in: input buffer pointer
43632e091a6SHaren Myneni  * @inlen: input buffer size
43732e091a6SHaren Myneni  * @out: output buffer pointer
43832e091a6SHaren Myneni  * @outlenp: output buffer size pointer
43932e091a6SHaren Myneni  * @workmem: working memory buffer pointer, size determined by
44032e091a6SHaren Myneni  *           nx842_powernv_driver.workmem_size
44132e091a6SHaren Myneni  * @fc: function code, see CCW Function Codes in nx-842.h
44232e091a6SHaren Myneni  *
44332e091a6SHaren Myneni  * Returns:
44432e091a6SHaren Myneni  *   0		Success, output of length @outlenp stored in the buffer at @out
44532e091a6SHaren Myneni  *   -ENODEV	Hardware unavailable
44632e091a6SHaren Myneni  *   -ENOSPC	Output buffer is to small
44732e091a6SHaren Myneni  *   -EMSGSIZE	Input buffer too large
44832e091a6SHaren Myneni  *   -EINVAL	buffer constraints do not fix nx842_constraints
44932e091a6SHaren Myneni  *   -EPROTO	hardware error during operation
45032e091a6SHaren Myneni  *   -ETIMEDOUT	hardware did not complete operation in reasonable time
45132e091a6SHaren Myneni  *   -EINTR	operation was aborted
45232e091a6SHaren Myneni  */
nx842_exec_icswx(const unsigned char * in,unsigned int inlen,unsigned char * out,unsigned int * outlenp,void * workmem,int fc)45332e091a6SHaren Myneni static int nx842_exec_icswx(const unsigned char *in, unsigned int inlen,
45432e091a6SHaren Myneni 				  unsigned char *out, unsigned int *outlenp,
45532e091a6SHaren Myneni 				  void *workmem, int fc)
45632e091a6SHaren Myneni {
45732e091a6SHaren Myneni 	struct coprocessor_request_block *crb;
45832e091a6SHaren Myneni 	struct coprocessor_status_block *csb;
45932e091a6SHaren Myneni 	struct nx842_workmem *wmem;
46032e091a6SHaren Myneni 	int ret;
46132e091a6SHaren Myneni 	u32 ccw;
46232e091a6SHaren Myneni 	unsigned int outlen = *outlenp;
46332e091a6SHaren Myneni 
46432e091a6SHaren Myneni 	wmem = PTR_ALIGN(workmem, WORKMEM_ALIGN);
46532e091a6SHaren Myneni 
46632e091a6SHaren Myneni 	*outlenp = 0;
46732e091a6SHaren Myneni 
46832e091a6SHaren Myneni 	/* shoudn't happen, we don't load without a coproc */
46932e091a6SHaren Myneni 	if (!nx842_ct) {
47032e091a6SHaren Myneni 		pr_err_ratelimited("coprocessor CT is 0");
47132e091a6SHaren Myneni 		return -ENODEV;
47232e091a6SHaren Myneni 	}
47332e091a6SHaren Myneni 
47432e091a6SHaren Myneni 	ret = nx842_config_crb(in, inlen, out, outlen, wmem);
47532e091a6SHaren Myneni 	if (ret)
47632e091a6SHaren Myneni 		return ret;
47732e091a6SHaren Myneni 
47832e091a6SHaren Myneni 	crb = &wmem->crb;
47932e091a6SHaren Myneni 	csb = &crb->csb;
48032e091a6SHaren Myneni 
48132e091a6SHaren Myneni 	/* set up CCW */
48232e091a6SHaren Myneni 	ccw = 0;
48332e091a6SHaren Myneni 	ccw = SET_FIELD(CCW_CT, ccw, nx842_ct);
48432e091a6SHaren Myneni 	ccw = SET_FIELD(CCW_CI_842, ccw, 0); /* use 0 for hw auto-selection */
48532e091a6SHaren Myneni 	ccw = SET_FIELD(CCW_FC_842, ccw, fc);
48632e091a6SHaren Myneni 
48732e091a6SHaren Myneni 	wmem->start = ktime_get();
48832e091a6SHaren Myneni 
48932e091a6SHaren Myneni 	/* do ICSWX */
49032e091a6SHaren Myneni 	ret = icswx(cpu_to_be32(ccw), crb);
49132e091a6SHaren Myneni 
49232e091a6SHaren Myneni 	pr_debug_ratelimited("icswx CR %x ccw %x crb->ccw %x\n", ret,
49332e091a6SHaren Myneni 			     (unsigned int)ccw,
49432e091a6SHaren Myneni 			     (unsigned int)be32_to_cpu(crb->ccw));
49532e091a6SHaren Myneni 
49632e091a6SHaren Myneni 	/*
49732e091a6SHaren Myneni 	 * NX842 coprocessor sets 3rd bit in CR register with XER[S0].
49832e091a6SHaren Myneni 	 * XER[S0] is the integer summary overflow bit which is nothing
49932e091a6SHaren Myneni 	 * to do NX. Since this bit can be set with other return values,
50032e091a6SHaren Myneni 	 * mask this bit.
50132e091a6SHaren Myneni 	 */
50232e091a6SHaren Myneni 	ret &= ~ICSWX_XERS0;
50332e091a6SHaren Myneni 
50432e091a6SHaren Myneni 	switch (ret) {
50532e091a6SHaren Myneni 	case ICSWX_INITIATED:
50632e091a6SHaren Myneni 		ret = wait_for_csb(wmem, csb);
50732e091a6SHaren Myneni 		break;
50832e091a6SHaren Myneni 	case ICSWX_BUSY:
50932e091a6SHaren Myneni 		pr_debug_ratelimited("842 Coprocessor busy\n");
51032e091a6SHaren Myneni 		ret = -EBUSY;
51132e091a6SHaren Myneni 		break;
51232e091a6SHaren Myneni 	case ICSWX_REJECTED:
51332e091a6SHaren Myneni 		pr_err_ratelimited("ICSWX rejected\n");
51432e091a6SHaren Myneni 		ret = -EPROTO;
51532e091a6SHaren Myneni 		break;
51632e091a6SHaren Myneni 	}
51732e091a6SHaren Myneni 
51832e091a6SHaren Myneni 	if (!ret)
51932e091a6SHaren Myneni 		*outlenp = be32_to_cpu(csb->count);
52032e091a6SHaren Myneni 
52132e091a6SHaren Myneni 	return ret;
52232e091a6SHaren Myneni }
52332e091a6SHaren Myneni 
52432e091a6SHaren Myneni /**
52532e091a6SHaren Myneni  * nx842_exec_vas - compress/decompress data using the 842 algorithm
52632e091a6SHaren Myneni  *
52732e091a6SHaren Myneni  * (De)compression provided by the NX842 coprocessor on IBM PowerNV systems.
52832e091a6SHaren Myneni  * This compresses or decompresses the provided input buffer into the provided
52932e091a6SHaren Myneni  * output buffer.
53032e091a6SHaren Myneni  *
53132e091a6SHaren Myneni  * Upon return from this function @outlen contains the length of the
53232e091a6SHaren Myneni  * output data.  If there is an error then @outlen will be 0 and an
53332e091a6SHaren Myneni  * error will be specified by the return code from this function.
53432e091a6SHaren Myneni  *
53532e091a6SHaren Myneni  * The @workmem buffer should only be used by one function call at a time.
53632e091a6SHaren Myneni  *
53732e091a6SHaren Myneni  * @in: input buffer pointer
53832e091a6SHaren Myneni  * @inlen: input buffer size
53932e091a6SHaren Myneni  * @out: output buffer pointer
54032e091a6SHaren Myneni  * @outlenp: output buffer size pointer
54132e091a6SHaren Myneni  * @workmem: working memory buffer pointer, size determined by
54232e091a6SHaren Myneni  *           nx842_powernv_driver.workmem_size
54332e091a6SHaren Myneni  * @fc: function code, see CCW Function Codes in nx-842.h
54432e091a6SHaren Myneni  *
54532e091a6SHaren Myneni  * Returns:
54632e091a6SHaren Myneni  *   0		Success, output of length @outlenp stored in the buffer
54732e091a6SHaren Myneni  *		at @out
54832e091a6SHaren Myneni  *   -ENODEV	Hardware unavailable
54932e091a6SHaren Myneni  *   -ENOSPC	Output buffer is to small
55032e091a6SHaren Myneni  *   -EMSGSIZE	Input buffer too large
55132e091a6SHaren Myneni  *   -EINVAL	buffer constraints do not fix nx842_constraints
55232e091a6SHaren Myneni  *   -EPROTO	hardware error during operation
55332e091a6SHaren Myneni  *   -ETIMEDOUT	hardware did not complete operation in reasonable time
55432e091a6SHaren Myneni  *   -EINTR	operation was aborted
55532e091a6SHaren Myneni  */
nx842_exec_vas(const unsigned char * in,unsigned int inlen,unsigned char * out,unsigned int * outlenp,void * workmem,int fc)55632e091a6SHaren Myneni static int nx842_exec_vas(const unsigned char *in, unsigned int inlen,
55732e091a6SHaren Myneni 				  unsigned char *out, unsigned int *outlenp,
55832e091a6SHaren Myneni 				  void *workmem, int fc)
55932e091a6SHaren Myneni {
56032e091a6SHaren Myneni 	struct coprocessor_request_block *crb;
56132e091a6SHaren Myneni 	struct coprocessor_status_block *csb;
56232e091a6SHaren Myneni 	struct nx842_workmem *wmem;
56332e091a6SHaren Myneni 	struct vas_window *txwin;
56432e091a6SHaren Myneni 	int ret, i = 0;
56532e091a6SHaren Myneni 	u32 ccw;
56632e091a6SHaren Myneni 	unsigned int outlen = *outlenp;
56732e091a6SHaren Myneni 
56832e091a6SHaren Myneni 	wmem = PTR_ALIGN(workmem, WORKMEM_ALIGN);
56932e091a6SHaren Myneni 
57032e091a6SHaren Myneni 	*outlenp = 0;
57132e091a6SHaren Myneni 
57232e091a6SHaren Myneni 	crb = &wmem->crb;
57332e091a6SHaren Myneni 	csb = &crb->csb;
57432e091a6SHaren Myneni 
57532e091a6SHaren Myneni 	ret = nx842_config_crb(in, inlen, out, outlen, wmem);
57632e091a6SHaren Myneni 	if (ret)
57732e091a6SHaren Myneni 		return ret;
57832e091a6SHaren Myneni 
57932e091a6SHaren Myneni 	ccw = 0;
58032e091a6SHaren Myneni 	ccw = SET_FIELD(CCW_FC_842, ccw, fc);
58132e091a6SHaren Myneni 	crb->ccw = cpu_to_be32(ccw);
58232e091a6SHaren Myneni 
58332e091a6SHaren Myneni 	do {
58432e091a6SHaren Myneni 		wmem->start = ktime_get();
58532e091a6SHaren Myneni 		preempt_disable();
58632e091a6SHaren Myneni 		txwin = this_cpu_read(cpu_txwin);
58732e091a6SHaren Myneni 
58832e091a6SHaren Myneni 		/*
58932e091a6SHaren Myneni 		 * VAS copy CRB into L2 cache. Refer <asm/vas.h>.
59032e091a6SHaren Myneni 		 * @crb and @offset.
59132e091a6SHaren Myneni 		 */
59232e091a6SHaren Myneni 		vas_copy_crb(crb, 0);
59332e091a6SHaren Myneni 
59432e091a6SHaren Myneni 		/*
59532e091a6SHaren Myneni 		 * VAS paste previously copied CRB to NX.
59632e091a6SHaren Myneni 		 * @txwin, @offset and @last (must be true).
59732e091a6SHaren Myneni 		 */
59832e091a6SHaren Myneni 		ret = vas_paste_crb(txwin, 0, 1);
59932e091a6SHaren Myneni 		preempt_enable();
60032e091a6SHaren Myneni 		/*
60132e091a6SHaren Myneni 		 * Retry copy/paste function for VAS failures.
60232e091a6SHaren Myneni 		 */
60332e091a6SHaren Myneni 	} while (ret && (i++ < VAS_RETRIES));
60432e091a6SHaren Myneni 
60532e091a6SHaren Myneni 	if (ret) {
60632e091a6SHaren Myneni 		pr_err_ratelimited("VAS copy/paste failed\n");
60732e091a6SHaren Myneni 		return ret;
60832e091a6SHaren Myneni 	}
60932e091a6SHaren Myneni 
61032e091a6SHaren Myneni 	ret = wait_for_csb(wmem, csb);
61132e091a6SHaren Myneni 	if (!ret)
61232e091a6SHaren Myneni 		*outlenp = be32_to_cpu(csb->count);
61332e091a6SHaren Myneni 
61432e091a6SHaren Myneni 	return ret;
61532e091a6SHaren Myneni }
61632e091a6SHaren Myneni 
61732e091a6SHaren Myneni /**
61832e091a6SHaren Myneni  * nx842_powernv_compress - Compress data using the 842 algorithm
61932e091a6SHaren Myneni  *
62032e091a6SHaren Myneni  * Compression provided by the NX842 coprocessor on IBM PowerNV systems.
62132e091a6SHaren Myneni  * The input buffer is compressed and the result is stored in the
62232e091a6SHaren Myneni  * provided output buffer.
62332e091a6SHaren Myneni  *
62432e091a6SHaren Myneni  * Upon return from this function @outlen contains the length of the
62532e091a6SHaren Myneni  * compressed data.  If there is an error then @outlen will be 0 and an
62632e091a6SHaren Myneni  * error will be specified by the return code from this function.
62732e091a6SHaren Myneni  *
62832e091a6SHaren Myneni  * @in: input buffer pointer
62932e091a6SHaren Myneni  * @inlen: input buffer size
63032e091a6SHaren Myneni  * @out: output buffer pointer
63132e091a6SHaren Myneni  * @outlenp: output buffer size pointer
632*6084466eSHerbert Xu  * @wmem: working memory buffer pointer, size determined by
63332e091a6SHaren Myneni  *        nx842_powernv_driver.workmem_size
63432e091a6SHaren Myneni  *
63532e091a6SHaren Myneni  * Returns: see @nx842_powernv_exec()
63632e091a6SHaren Myneni  */
nx842_powernv_compress(const unsigned char * in,unsigned int inlen,unsigned char * out,unsigned int * outlenp,void * wmem)63732e091a6SHaren Myneni static int nx842_powernv_compress(const unsigned char *in, unsigned int inlen,
63832e091a6SHaren Myneni 				  unsigned char *out, unsigned int *outlenp,
63932e091a6SHaren Myneni 				  void *wmem)
64032e091a6SHaren Myneni {
64132e091a6SHaren Myneni 	return nx842_powernv_exec(in, inlen, out, outlenp,
64232e091a6SHaren Myneni 				      wmem, CCW_FC_842_COMP_CRC);
64332e091a6SHaren Myneni }
64432e091a6SHaren Myneni 
64532e091a6SHaren Myneni /**
64632e091a6SHaren Myneni  * nx842_powernv_decompress - Decompress data using the 842 algorithm
64732e091a6SHaren Myneni  *
64832e091a6SHaren Myneni  * Decompression provided by the NX842 coprocessor on IBM PowerNV systems.
64932e091a6SHaren Myneni  * The input buffer is decompressed and the result is stored in the
65032e091a6SHaren Myneni  * provided output buffer.
65132e091a6SHaren Myneni  *
65232e091a6SHaren Myneni  * Upon return from this function @outlen contains the length of the
65332e091a6SHaren Myneni  * decompressed data.  If there is an error then @outlen will be 0 and an
65432e091a6SHaren Myneni  * error will be specified by the return code from this function.
65532e091a6SHaren Myneni  *
65632e091a6SHaren Myneni  * @in: input buffer pointer
65732e091a6SHaren Myneni  * @inlen: input buffer size
65832e091a6SHaren Myneni  * @out: output buffer pointer
65932e091a6SHaren Myneni  * @outlenp: output buffer size pointer
6603f4a8567SShaokun Zhang  * @wmem: working memory buffer pointer, size determined by
66132e091a6SHaren Myneni  *        nx842_powernv_driver.workmem_size
66232e091a6SHaren Myneni  *
66332e091a6SHaren Myneni  * Returns: see @nx842_powernv_exec()
66432e091a6SHaren Myneni  */
nx842_powernv_decompress(const unsigned char * in,unsigned int inlen,unsigned char * out,unsigned int * outlenp,void * wmem)66532e091a6SHaren Myneni static int nx842_powernv_decompress(const unsigned char *in, unsigned int inlen,
66632e091a6SHaren Myneni 				    unsigned char *out, unsigned int *outlenp,
66732e091a6SHaren Myneni 				    void *wmem)
66832e091a6SHaren Myneni {
66932e091a6SHaren Myneni 	return nx842_powernv_exec(in, inlen, out, outlenp,
67032e091a6SHaren Myneni 				      wmem, CCW_FC_842_DECOMP_CRC);
67132e091a6SHaren Myneni }
67232e091a6SHaren Myneni 
nx_add_coprocs_list(struct nx_coproc * coproc,int chipid)6734aebf3ceSHaren Myneni static inline void nx_add_coprocs_list(struct nx_coproc *coproc,
67432e091a6SHaren Myneni 					int chipid)
67532e091a6SHaren Myneni {
67632e091a6SHaren Myneni 	coproc->chip_id = chipid;
67732e091a6SHaren Myneni 	INIT_LIST_HEAD(&coproc->list);
6784aebf3ceSHaren Myneni 	list_add(&coproc->list, &nx_coprocs);
67932e091a6SHaren Myneni }
68032e091a6SHaren Myneni 
nx_alloc_txwin(struct nx_coproc * coproc)6814aebf3ceSHaren Myneni static struct vas_window *nx_alloc_txwin(struct nx_coproc *coproc)
68232e091a6SHaren Myneni {
68332e091a6SHaren Myneni 	struct vas_window *txwin = NULL;
68432e091a6SHaren Myneni 	struct vas_tx_win_attr txattr;
68532e091a6SHaren Myneni 
68632e091a6SHaren Myneni 	/*
68732e091a6SHaren Myneni 	 * Kernel requests will be high priority. So open send
68832e091a6SHaren Myneni 	 * windows only for high priority RxFIFO entries.
68932e091a6SHaren Myneni 	 */
69032e091a6SHaren Myneni 	vas_init_tx_win_attr(&txattr, coproc->ct);
69132e091a6SHaren Myneni 	txattr.lpid = 0;	/* lpid is 0 for kernel requests */
69232e091a6SHaren Myneni 
69332e091a6SHaren Myneni 	/*
69432e091a6SHaren Myneni 	 * Open a VAS send window which is used to send request to NX.
69532e091a6SHaren Myneni 	 */
69632e091a6SHaren Myneni 	txwin = vas_tx_win_open(coproc->vas.id, coproc->ct, &txattr);
69732e091a6SHaren Myneni 	if (IS_ERR(txwin))
69832e091a6SHaren Myneni 		pr_err("ibm,nx-842: Can not open TX window: %ld\n",
69932e091a6SHaren Myneni 				PTR_ERR(txwin));
70032e091a6SHaren Myneni 
70132e091a6SHaren Myneni 	return txwin;
70232e091a6SHaren Myneni }
70332e091a6SHaren Myneni 
70432e091a6SHaren Myneni /*
70532e091a6SHaren Myneni  * Identify chip ID for each CPU, open send wndow for the corresponding NX
70632e091a6SHaren Myneni  * engine and save txwin in percpu cpu_txwin.
70732e091a6SHaren Myneni  * cpu_txwin is used in copy/paste operation for each compression /
70832e091a6SHaren Myneni  * decompression request.
70932e091a6SHaren Myneni  */
nx_open_percpu_txwins(void)7104aebf3ceSHaren Myneni static int nx_open_percpu_txwins(void)
71132e091a6SHaren Myneni {
7124aebf3ceSHaren Myneni 	struct nx_coproc *coproc, *n;
71332e091a6SHaren Myneni 	unsigned int i, chip_id;
71432e091a6SHaren Myneni 
71532e091a6SHaren Myneni 	for_each_possible_cpu(i) {
71632e091a6SHaren Myneni 		struct vas_window *txwin = NULL;
71732e091a6SHaren Myneni 
71832e091a6SHaren Myneni 		chip_id = cpu_to_chip_id(i);
71932e091a6SHaren Myneni 
7204aebf3ceSHaren Myneni 		list_for_each_entry_safe(coproc, n, &nx_coprocs, list) {
72132e091a6SHaren Myneni 			/*
72232e091a6SHaren Myneni 			 * Kernel requests use only high priority FIFOs. So
72332e091a6SHaren Myneni 			 * open send windows for these FIFOs.
7244aebf3ceSHaren Myneni 			 * GZIP is not supported in kernel right now.
72532e091a6SHaren Myneni 			 */
72632e091a6SHaren Myneni 
72732e091a6SHaren Myneni 			if (coproc->ct != VAS_COP_TYPE_842_HIPRI)
72832e091a6SHaren Myneni 				continue;
72932e091a6SHaren Myneni 
73032e091a6SHaren Myneni 			if (coproc->chip_id == chip_id) {
7314aebf3ceSHaren Myneni 				txwin = nx_alloc_txwin(coproc);
73232e091a6SHaren Myneni 				if (IS_ERR(txwin))
73332e091a6SHaren Myneni 					return PTR_ERR(txwin);
73432e091a6SHaren Myneni 
73532e091a6SHaren Myneni 				per_cpu(cpu_txwin, i) = txwin;
73632e091a6SHaren Myneni 				break;
73732e091a6SHaren Myneni 			}
73832e091a6SHaren Myneni 		}
73932e091a6SHaren Myneni 
74032e091a6SHaren Myneni 		if (!per_cpu(cpu_txwin, i)) {
74132e091a6SHaren Myneni 			/* shouldn't happen, Each chip will have NX engine */
74232e091a6SHaren Myneni 			pr_err("NX engine is not available for CPU %d\n", i);
74332e091a6SHaren Myneni 			return -EINVAL;
74432e091a6SHaren Myneni 		}
74532e091a6SHaren Myneni 	}
74632e091a6SHaren Myneni 
74732e091a6SHaren Myneni 	return 0;
74832e091a6SHaren Myneni }
74932e091a6SHaren Myneni 
nx_set_ct(struct nx_coproc * coproc,const char * priority,int high,int normal)7504aebf3ceSHaren Myneni static int __init nx_set_ct(struct nx_coproc *coproc, const char *priority,
7514aebf3ceSHaren Myneni 				int high, int normal)
7524aebf3ceSHaren Myneni {
7534aebf3ceSHaren Myneni 	if (!strcmp(priority, "High"))
7544aebf3ceSHaren Myneni 		coproc->ct = high;
7554aebf3ceSHaren Myneni 	else if (!strcmp(priority, "Normal"))
7564aebf3ceSHaren Myneni 		coproc->ct = normal;
7574aebf3ceSHaren Myneni 	else {
7584aebf3ceSHaren Myneni 		pr_err("Invalid RxFIFO priority value\n");
7594aebf3ceSHaren Myneni 		return -EINVAL;
7604aebf3ceSHaren Myneni 	}
7614aebf3ceSHaren Myneni 
7624aebf3ceSHaren Myneni 	return 0;
7634aebf3ceSHaren Myneni }
7644aebf3ceSHaren Myneni 
vas_cfg_coproc_info(struct device_node * dn,int chip_id,int vasid,int type,int * ct)76532e091a6SHaren Myneni static int __init vas_cfg_coproc_info(struct device_node *dn, int chip_id,
7664aebf3ceSHaren Myneni 					int vasid, int type, int *ct)
76732e091a6SHaren Myneni {
76832e091a6SHaren Myneni 	struct vas_window *rxwin = NULL;
76932e091a6SHaren Myneni 	struct vas_rx_win_attr rxattr;
77032e091a6SHaren Myneni 	u32 lpid, pid, tid, fifo_size;
7714aebf3ceSHaren Myneni 	struct nx_coproc *coproc;
77232e091a6SHaren Myneni 	u64 rx_fifo;
77332e091a6SHaren Myneni 	const char *priority;
77432e091a6SHaren Myneni 	int ret;
77532e091a6SHaren Myneni 
77632e091a6SHaren Myneni 	ret = of_property_read_u64(dn, "rx-fifo-address", &rx_fifo);
77732e091a6SHaren Myneni 	if (ret) {
77832e091a6SHaren Myneni 		pr_err("Missing rx-fifo-address property\n");
77932e091a6SHaren Myneni 		return ret;
78032e091a6SHaren Myneni 	}
78132e091a6SHaren Myneni 
78232e091a6SHaren Myneni 	ret = of_property_read_u32(dn, "rx-fifo-size", &fifo_size);
78332e091a6SHaren Myneni 	if (ret) {
78432e091a6SHaren Myneni 		pr_err("Missing rx-fifo-size property\n");
78532e091a6SHaren Myneni 		return ret;
78632e091a6SHaren Myneni 	}
78732e091a6SHaren Myneni 
78832e091a6SHaren Myneni 	ret = of_property_read_u32(dn, "lpid", &lpid);
78932e091a6SHaren Myneni 	if (ret) {
79032e091a6SHaren Myneni 		pr_err("Missing lpid property\n");
79132e091a6SHaren Myneni 		return ret;
79232e091a6SHaren Myneni 	}
79332e091a6SHaren Myneni 
79432e091a6SHaren Myneni 	ret = of_property_read_u32(dn, "pid", &pid);
79532e091a6SHaren Myneni 	if (ret) {
79632e091a6SHaren Myneni 		pr_err("Missing pid property\n");
79732e091a6SHaren Myneni 		return ret;
79832e091a6SHaren Myneni 	}
79932e091a6SHaren Myneni 
80032e091a6SHaren Myneni 	ret = of_property_read_u32(dn, "tid", &tid);
80132e091a6SHaren Myneni 	if (ret) {
80232e091a6SHaren Myneni 		pr_err("Missing tid property\n");
80332e091a6SHaren Myneni 		return ret;
80432e091a6SHaren Myneni 	}
80532e091a6SHaren Myneni 
80632e091a6SHaren Myneni 	ret = of_property_read_string(dn, "priority", &priority);
80732e091a6SHaren Myneni 	if (ret) {
80832e091a6SHaren Myneni 		pr_err("Missing priority property\n");
80932e091a6SHaren Myneni 		return ret;
81032e091a6SHaren Myneni 	}
81132e091a6SHaren Myneni 
81232e091a6SHaren Myneni 	coproc = kzalloc(sizeof(*coproc), GFP_KERNEL);
81332e091a6SHaren Myneni 	if (!coproc)
81432e091a6SHaren Myneni 		return -ENOMEM;
81532e091a6SHaren Myneni 
8164aebf3ceSHaren Myneni 	if (type == NX_CT_842)
8174aebf3ceSHaren Myneni 		ret = nx_set_ct(coproc, priority, VAS_COP_TYPE_842_HIPRI,
8184aebf3ceSHaren Myneni 			VAS_COP_TYPE_842);
8191af11ae2SHaren Myneni 	else if (type == NX_CT_GZIP)
8201af11ae2SHaren Myneni 		ret = nx_set_ct(coproc, priority, VAS_COP_TYPE_GZIP_HIPRI,
8211af11ae2SHaren Myneni 				VAS_COP_TYPE_GZIP);
8224aebf3ceSHaren Myneni 
8234aebf3ceSHaren Myneni 	if (ret)
82432e091a6SHaren Myneni 		goto err_out;
82532e091a6SHaren Myneni 
82632e091a6SHaren Myneni 	vas_init_rx_win_attr(&rxattr, coproc->ct);
827c127d130SHaren Myneni 	rxattr.rx_fifo = rx_fifo;
82832e091a6SHaren Myneni 	rxattr.rx_fifo_size = fifo_size;
82932e091a6SHaren Myneni 	rxattr.lnotify_lpid = lpid;
83032e091a6SHaren Myneni 	rxattr.lnotify_pid = pid;
83132e091a6SHaren Myneni 	rxattr.lnotify_tid = tid;
83232e091a6SHaren Myneni 	/*
83332e091a6SHaren Myneni 	 * Maximum RX window credits can not be more than #CRBs in
83432e091a6SHaren Myneni 	 * RxFIFO. Otherwise, can get checkstop if RxFIFO overruns.
83532e091a6SHaren Myneni 	 */
83632e091a6SHaren Myneni 	rxattr.wcreds_max = fifo_size / CRB_SIZE;
83732e091a6SHaren Myneni 
83832e091a6SHaren Myneni 	/*
83932e091a6SHaren Myneni 	 * Open a VAS receice window which is used to configure RxFIFO
84032e091a6SHaren Myneni 	 * for NX.
84132e091a6SHaren Myneni 	 */
84232e091a6SHaren Myneni 	rxwin = vas_rx_win_open(vasid, coproc->ct, &rxattr);
84332e091a6SHaren Myneni 	if (IS_ERR(rxwin)) {
84432e091a6SHaren Myneni 		ret = PTR_ERR(rxwin);
84532e091a6SHaren Myneni 		pr_err("setting RxFIFO with VAS failed: %d\n",
84632e091a6SHaren Myneni 			ret);
84732e091a6SHaren Myneni 		goto err_out;
84832e091a6SHaren Myneni 	}
84932e091a6SHaren Myneni 
85032e091a6SHaren Myneni 	coproc->vas.rxwin = rxwin;
85132e091a6SHaren Myneni 	coproc->vas.id = vasid;
8524aebf3ceSHaren Myneni 	nx_add_coprocs_list(coproc, chip_id);
85332e091a6SHaren Myneni 
85432e091a6SHaren Myneni 	/*
85532e091a6SHaren Myneni 	 * (lpid, pid, tid) combination has to be unique for each
85632e091a6SHaren Myneni 	 * coprocessor instance in the system. So to make it
85732e091a6SHaren Myneni 	 * unique, skiboot uses coprocessor type such as 842 or
85832e091a6SHaren Myneni 	 * GZIP for pid and provides this value to kernel in pid
85932e091a6SHaren Myneni 	 * device-tree property.
86032e091a6SHaren Myneni 	 */
86132e091a6SHaren Myneni 	*ct = pid;
86232e091a6SHaren Myneni 
86332e091a6SHaren Myneni 	return 0;
86432e091a6SHaren Myneni 
86532e091a6SHaren Myneni err_out:
86632e091a6SHaren Myneni 	kfree(coproc);
86732e091a6SHaren Myneni 	return ret;
86832e091a6SHaren Myneni }
86932e091a6SHaren Myneni 
nx_coproc_init(int chip_id,int ct_842,int ct_gzip)8701af11ae2SHaren Myneni static int __init nx_coproc_init(int chip_id, int ct_842, int ct_gzip)
87132e091a6SHaren Myneni {
8724aebf3ceSHaren Myneni 	int ret = 0;
8734aebf3ceSHaren Myneni 
8744aebf3ceSHaren Myneni 	if (opal_check_token(OPAL_NX_COPROC_INIT)) {
8754aebf3ceSHaren Myneni 		ret = opal_nx_coproc_init(chip_id, ct_842);
8761af11ae2SHaren Myneni 
8771af11ae2SHaren Myneni 		if (!ret)
8781af11ae2SHaren Myneni 			ret = opal_nx_coproc_init(chip_id, ct_gzip);
8791af11ae2SHaren Myneni 
8804aebf3ceSHaren Myneni 		if (ret) {
8814aebf3ceSHaren Myneni 			ret = opal_error_code(ret);
8824aebf3ceSHaren Myneni 			pr_err("Failed to initialize NX for chip(%d): %d\n",
8834aebf3ceSHaren Myneni 				chip_id, ret);
8844aebf3ceSHaren Myneni 		}
8854aebf3ceSHaren Myneni 	} else
8864aebf3ceSHaren Myneni 		pr_warn("Firmware doesn't support NX initialization\n");
8874aebf3ceSHaren Myneni 
8884aebf3ceSHaren Myneni 	return ret;
8894aebf3ceSHaren Myneni }
8904aebf3ceSHaren Myneni 
find_nx_device_tree(struct device_node * dn,int chip_id,int vasid,int type,char * devname,int * ct)8914aebf3ceSHaren Myneni static int __init find_nx_device_tree(struct device_node *dn, int chip_id,
8924aebf3ceSHaren Myneni 					int vasid, int type, char *devname,
8934aebf3ceSHaren Myneni 					int *ct)
8944aebf3ceSHaren Myneni {
8954aebf3ceSHaren Myneni 	int ret = 0;
8964aebf3ceSHaren Myneni 
8974aebf3ceSHaren Myneni 	if (of_device_is_compatible(dn, devname)) {
8984aebf3ceSHaren Myneni 		ret  = vas_cfg_coproc_info(dn, chip_id, vasid, type, ct);
8994aebf3ceSHaren Myneni 		if (ret)
9004aebf3ceSHaren Myneni 			of_node_put(dn);
9014aebf3ceSHaren Myneni 	}
9024aebf3ceSHaren Myneni 
9034aebf3ceSHaren Myneni 	return ret;
9044aebf3ceSHaren Myneni }
9054aebf3ceSHaren Myneni 
nx_powernv_probe_vas(struct device_node * pn)9064aebf3ceSHaren Myneni static int __init nx_powernv_probe_vas(struct device_node *pn)
9074aebf3ceSHaren Myneni {
90832e091a6SHaren Myneni 	int chip_id, vasid, ret = 0;
9091af11ae2SHaren Myneni 	int ct_842 = 0, ct_gzip = 0;
9104aebf3ceSHaren Myneni 	struct device_node *dn;
91132e091a6SHaren Myneni 
91232e091a6SHaren Myneni 	chip_id = of_get_ibm_chip_id(pn);
91332e091a6SHaren Myneni 	if (chip_id < 0) {
91432e091a6SHaren Myneni 		pr_err("ibm,chip-id missing\n");
91532e091a6SHaren Myneni 		return -EINVAL;
91632e091a6SHaren Myneni 	}
91732e091a6SHaren Myneni 
91832e091a6SHaren Myneni 	vasid = chip_to_vas_id(chip_id);
91932e091a6SHaren Myneni 	if (vasid < 0) {
92032e091a6SHaren Myneni 		pr_err("Unable to map chip_id %d to vasid\n", chip_id);
92132e091a6SHaren Myneni 		return -EINVAL;
92232e091a6SHaren Myneni 	}
92332e091a6SHaren Myneni 
92432e091a6SHaren Myneni 	for_each_child_of_node(pn, dn) {
9254aebf3ceSHaren Myneni 		ret = find_nx_device_tree(dn, chip_id, vasid, NX_CT_842,
9264aebf3ceSHaren Myneni 					"ibm,p9-nx-842", &ct_842);
9271af11ae2SHaren Myneni 
9281af11ae2SHaren Myneni 		if (!ret)
9291af11ae2SHaren Myneni 			ret = find_nx_device_tree(dn, chip_id, vasid,
9301af11ae2SHaren Myneni 				NX_CT_GZIP, "ibm,p9-nx-gzip", &ct_gzip);
9311af11ae2SHaren Myneni 
9321406f0f3SYang Li 		if (ret) {
9331406f0f3SYang Li 			of_node_put(dn);
93432e091a6SHaren Myneni 			return ret;
93532e091a6SHaren Myneni 		}
9361406f0f3SYang Li 	}
93732e091a6SHaren Myneni 
9381af11ae2SHaren Myneni 	if (!ct_842 || !ct_gzip) {
9391af11ae2SHaren Myneni 		pr_err("NX FIFO nodes are missing\n");
94032e091a6SHaren Myneni 		return -EINVAL;
94132e091a6SHaren Myneni 	}
94232e091a6SHaren Myneni 
94332e091a6SHaren Myneni 	/*
94432e091a6SHaren Myneni 	 * Initialize NX instance for both high and normal priority FIFOs.
94532e091a6SHaren Myneni 	 */
9461af11ae2SHaren Myneni 	ret = nx_coproc_init(chip_id, ct_842, ct_gzip);
94732e091a6SHaren Myneni 
94832e091a6SHaren Myneni 	return ret;
94932e091a6SHaren Myneni }
95032e091a6SHaren Myneni 
nx842_powernv_probe(struct device_node * dn)95132e091a6SHaren Myneni static int __init nx842_powernv_probe(struct device_node *dn)
95232e091a6SHaren Myneni {
9534aebf3ceSHaren Myneni 	struct nx_coproc *coproc;
95432e091a6SHaren Myneni 	unsigned int ct, ci;
95532e091a6SHaren Myneni 	int chip_id;
95632e091a6SHaren Myneni 
95732e091a6SHaren Myneni 	chip_id = of_get_ibm_chip_id(dn);
95832e091a6SHaren Myneni 	if (chip_id < 0) {
95932e091a6SHaren Myneni 		pr_err("ibm,chip-id missing\n");
96032e091a6SHaren Myneni 		return -EINVAL;
96132e091a6SHaren Myneni 	}
96232e091a6SHaren Myneni 
96332e091a6SHaren Myneni 	if (of_property_read_u32(dn, "ibm,842-coprocessor-type", &ct)) {
96432e091a6SHaren Myneni 		pr_err("ibm,842-coprocessor-type missing\n");
96532e091a6SHaren Myneni 		return -EINVAL;
96632e091a6SHaren Myneni 	}
96732e091a6SHaren Myneni 
96832e091a6SHaren Myneni 	if (of_property_read_u32(dn, "ibm,842-coprocessor-instance", &ci)) {
96932e091a6SHaren Myneni 		pr_err("ibm,842-coprocessor-instance missing\n");
97032e091a6SHaren Myneni 		return -EINVAL;
97132e091a6SHaren Myneni 	}
97232e091a6SHaren Myneni 
97332e091a6SHaren Myneni 	coproc = kzalloc(sizeof(*coproc), GFP_KERNEL);
97432e091a6SHaren Myneni 	if (!coproc)
97532e091a6SHaren Myneni 		return -ENOMEM;
97632e091a6SHaren Myneni 
97732e091a6SHaren Myneni 	coproc->ct = ct;
97832e091a6SHaren Myneni 	coproc->ci = ci;
9794aebf3ceSHaren Myneni 	nx_add_coprocs_list(coproc, chip_id);
98032e091a6SHaren Myneni 
98132e091a6SHaren Myneni 	pr_info("coprocessor found on chip %d, CT %d CI %d\n", chip_id, ct, ci);
98232e091a6SHaren Myneni 
98332e091a6SHaren Myneni 	if (!nx842_ct)
98432e091a6SHaren Myneni 		nx842_ct = ct;
98532e091a6SHaren Myneni 	else if (nx842_ct != ct)
98632e091a6SHaren Myneni 		pr_err("NX842 chip %d, CT %d != first found CT %d\n",
98732e091a6SHaren Myneni 		       chip_id, ct, nx842_ct);
98832e091a6SHaren Myneni 
98932e091a6SHaren Myneni 	return 0;
99032e091a6SHaren Myneni }
99132e091a6SHaren Myneni 
nx_delete_coprocs(void)9924aebf3ceSHaren Myneni static void nx_delete_coprocs(void)
99332e091a6SHaren Myneni {
9944aebf3ceSHaren Myneni 	struct nx_coproc *coproc, *n;
99532e091a6SHaren Myneni 	struct vas_window *txwin;
99632e091a6SHaren Myneni 	int i;
99732e091a6SHaren Myneni 
99832e091a6SHaren Myneni 	/*
99932e091a6SHaren Myneni 	 * close percpu txwins that are opened for the corresponding coproc.
100032e091a6SHaren Myneni 	 */
100132e091a6SHaren Myneni 	for_each_possible_cpu(i) {
100232e091a6SHaren Myneni 		txwin = per_cpu(cpu_txwin, i);
100332e091a6SHaren Myneni 		if (txwin)
100432e091a6SHaren Myneni 			vas_win_close(txwin);
100532e091a6SHaren Myneni 
10064aebf3ceSHaren Myneni 		per_cpu(cpu_txwin, i) = NULL;
100732e091a6SHaren Myneni 	}
100832e091a6SHaren Myneni 
10094aebf3ceSHaren Myneni 	list_for_each_entry_safe(coproc, n, &nx_coprocs, list) {
101032e091a6SHaren Myneni 		if (coproc->vas.rxwin)
101132e091a6SHaren Myneni 			vas_win_close(coproc->vas.rxwin);
101232e091a6SHaren Myneni 
101332e091a6SHaren Myneni 		list_del(&coproc->list);
101432e091a6SHaren Myneni 		kfree(coproc);
101532e091a6SHaren Myneni 	}
101632e091a6SHaren Myneni }
101732e091a6SHaren Myneni 
101832e091a6SHaren Myneni static struct nx842_constraints nx842_powernv_constraints = {
101932e091a6SHaren Myneni 	.alignment =	DDE_BUFFER_ALIGN,
102032e091a6SHaren Myneni 	.multiple =	DDE_BUFFER_LAST_MULT,
102132e091a6SHaren Myneni 	.minimum =	DDE_BUFFER_LAST_MULT,
102232e091a6SHaren Myneni 	.maximum =	(DDL_LEN_MAX - 1) * PAGE_SIZE,
102332e091a6SHaren Myneni };
102432e091a6SHaren Myneni 
102532e091a6SHaren Myneni static struct nx842_driver nx842_powernv_driver = {
102632e091a6SHaren Myneni 	.name =		KBUILD_MODNAME,
102732e091a6SHaren Myneni 	.owner =	THIS_MODULE,
102832e091a6SHaren Myneni 	.workmem_size =	sizeof(struct nx842_workmem),
102932e091a6SHaren Myneni 	.constraints =	&nx842_powernv_constraints,
103032e091a6SHaren Myneni 	.compress =	nx842_powernv_compress,
103132e091a6SHaren Myneni 	.decompress =	nx842_powernv_decompress,
103232e091a6SHaren Myneni };
103332e091a6SHaren Myneni 
nx842_powernv_crypto_init(struct crypto_tfm * tfm)103432e091a6SHaren Myneni static int nx842_powernv_crypto_init(struct crypto_tfm *tfm)
103532e091a6SHaren Myneni {
103632e091a6SHaren Myneni 	return nx842_crypto_init(tfm, &nx842_powernv_driver);
103732e091a6SHaren Myneni }
103832e091a6SHaren Myneni 
103932e091a6SHaren Myneni static struct crypto_alg nx842_powernv_alg = {
104032e091a6SHaren Myneni 	.cra_name		= "842",
104132e091a6SHaren Myneni 	.cra_driver_name	= "842-nx",
104232e091a6SHaren Myneni 	.cra_priority		= 300,
104332e091a6SHaren Myneni 	.cra_flags		= CRYPTO_ALG_TYPE_COMPRESS,
104432e091a6SHaren Myneni 	.cra_ctxsize		= sizeof(struct nx842_crypto_ctx),
104532e091a6SHaren Myneni 	.cra_module		= THIS_MODULE,
104632e091a6SHaren Myneni 	.cra_init		= nx842_powernv_crypto_init,
104732e091a6SHaren Myneni 	.cra_exit		= nx842_crypto_exit,
104832e091a6SHaren Myneni 	.cra_u			= { .compress = {
104932e091a6SHaren Myneni 	.coa_compress		= nx842_crypto_compress,
105032e091a6SHaren Myneni 	.coa_decompress		= nx842_crypto_decompress } }
105132e091a6SHaren Myneni };
105232e091a6SHaren Myneni 
nx_compress_powernv_init(void)10534aebf3ceSHaren Myneni static __init int nx_compress_powernv_init(void)
105432e091a6SHaren Myneni {
105532e091a6SHaren Myneni 	struct device_node *dn;
105632e091a6SHaren Myneni 	int ret;
105732e091a6SHaren Myneni 
105832e091a6SHaren Myneni 	/* verify workmem size/align restrictions */
105932e091a6SHaren Myneni 	BUILD_BUG_ON(WORKMEM_ALIGN % CRB_ALIGN);
106032e091a6SHaren Myneni 	BUILD_BUG_ON(CRB_ALIGN % DDE_ALIGN);
106132e091a6SHaren Myneni 	BUILD_BUG_ON(CRB_SIZE % DDE_ALIGN);
106232e091a6SHaren Myneni 	/* verify buffer size/align restrictions */
106332e091a6SHaren Myneni 	BUILD_BUG_ON(PAGE_SIZE % DDE_BUFFER_ALIGN);
106432e091a6SHaren Myneni 	BUILD_BUG_ON(DDE_BUFFER_ALIGN % DDE_BUFFER_SIZE_MULT);
106532e091a6SHaren Myneni 	BUILD_BUG_ON(DDE_BUFFER_SIZE_MULT % DDE_BUFFER_LAST_MULT);
106632e091a6SHaren Myneni 
106732e091a6SHaren Myneni 	for_each_compatible_node(dn, NULL, "ibm,power9-nx") {
10684aebf3ceSHaren Myneni 		ret = nx_powernv_probe_vas(dn);
106932e091a6SHaren Myneni 		if (ret) {
10704aebf3ceSHaren Myneni 			nx_delete_coprocs();
107132e091a6SHaren Myneni 			of_node_put(dn);
107232e091a6SHaren Myneni 			return ret;
107332e091a6SHaren Myneni 		}
107432e091a6SHaren Myneni 	}
107532e091a6SHaren Myneni 
10764aebf3ceSHaren Myneni 	if (list_empty(&nx_coprocs)) {
107732e091a6SHaren Myneni 		for_each_compatible_node(dn, NULL, "ibm,power-nx")
107832e091a6SHaren Myneni 			nx842_powernv_probe(dn);
107932e091a6SHaren Myneni 
108032e091a6SHaren Myneni 		if (!nx842_ct)
108132e091a6SHaren Myneni 			return -ENODEV;
108232e091a6SHaren Myneni 
108332e091a6SHaren Myneni 		nx842_powernv_exec = nx842_exec_icswx;
108432e091a6SHaren Myneni 	} else {
10854aebf3ceSHaren Myneni 		/*
10861af11ae2SHaren Myneni 		 * Register VAS user space API for NX GZIP so
10871af11ae2SHaren Myneni 		 * that user space can use GZIP engine.
10881af11ae2SHaren Myneni 		 * Using high FIFO priority for kernel requests and
10891af11ae2SHaren Myneni 		 * normal FIFO priority is assigned for userspace.
10901af11ae2SHaren Myneni 		 * 842 compression is supported only in kernel.
10911af11ae2SHaren Myneni 		 */
109206c6fad9SHaren Myneni 		ret = vas_register_api_powernv(THIS_MODULE, VAS_COP_TYPE_GZIP,
10931af11ae2SHaren Myneni 					       "nx-gzip");
10941af11ae2SHaren Myneni 
10951af11ae2SHaren Myneni 		/*
10964aebf3ceSHaren Myneni 		 * GZIP is not supported in kernel right now.
10974aebf3ceSHaren Myneni 		 * So open tx windows only for 842.
10984aebf3ceSHaren Myneni 		 */
10991af11ae2SHaren Myneni 		if (!ret)
11004aebf3ceSHaren Myneni 			ret = nx_open_percpu_txwins();
11011af11ae2SHaren Myneni 
110232e091a6SHaren Myneni 		if (ret) {
11034aebf3ceSHaren Myneni 			nx_delete_coprocs();
110432e091a6SHaren Myneni 			return ret;
110532e091a6SHaren Myneni 		}
110632e091a6SHaren Myneni 
110732e091a6SHaren Myneni 		nx842_powernv_exec = nx842_exec_vas;
110832e091a6SHaren Myneni 	}
110932e091a6SHaren Myneni 
111032e091a6SHaren Myneni 	ret = crypto_register_alg(&nx842_powernv_alg);
111132e091a6SHaren Myneni 	if (ret) {
11124aebf3ceSHaren Myneni 		nx_delete_coprocs();
111332e091a6SHaren Myneni 		return ret;
111432e091a6SHaren Myneni 	}
111532e091a6SHaren Myneni 
111632e091a6SHaren Myneni 	return 0;
111732e091a6SHaren Myneni }
11184aebf3ceSHaren Myneni module_init(nx_compress_powernv_init);
111932e091a6SHaren Myneni 
nx_compress_powernv_exit(void)11204aebf3ceSHaren Myneni static void __exit nx_compress_powernv_exit(void)
112132e091a6SHaren Myneni {
11221af11ae2SHaren Myneni 	/*
11231af11ae2SHaren Myneni 	 * GZIP engine is supported only in power9 or later and nx842_ct
11241af11ae2SHaren Myneni 	 * is used on power8 (icswx).
11251af11ae2SHaren Myneni 	 * VAS API for NX GZIP is registered during init for user space
11261af11ae2SHaren Myneni 	 * use. So delete this API use for GZIP engine.
11271af11ae2SHaren Myneni 	 */
11281af11ae2SHaren Myneni 	if (!nx842_ct)
112906c6fad9SHaren Myneni 		vas_unregister_api_powernv();
11301af11ae2SHaren Myneni 
113132e091a6SHaren Myneni 	crypto_unregister_alg(&nx842_powernv_alg);
113232e091a6SHaren Myneni 
11334aebf3ceSHaren Myneni 	nx_delete_coprocs();
113432e091a6SHaren Myneni }
11354aebf3ceSHaren Myneni module_exit(nx_compress_powernv_exit);
1136