diff options
author | Dan Streetman <ddstreet@ieee.org> | 2015-05-07 13:49:19 -0400 |
---|---|---|
committer | Herbert Xu <herbert@gondor.apana.org.au> | 2015-05-11 03:06:47 -0400 |
commit | 99182a42b7ef3d5e4180992ce01befd9e87526d2 (patch) | |
tree | 56b0d4e29202a01f0c400b8a2db12ad29eaa11e4 | |
parent | 959e6659b6f74ec1fa4d391a3b88d63dc0189f36 (diff) |
crypto: nx - add PowerNV platform NX-842 driver
Add driver for NX-842 hardware on the PowerNV platform.
This allows the use of the 842 compression hardware coprocessor on
the PowerNV platform.
Signed-off-by: Dan Streetman <ddstreet@ieee.org>
Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au>
-rw-r--r-- | drivers/crypto/nx/Kconfig | 10 | ||||
-rw-r--r-- | drivers/crypto/nx/Makefile | 2 | ||||
-rw-r--r-- | drivers/crypto/nx/nx-842-powernv.c | 625 | ||||
-rw-r--r-- | drivers/crypto/nx/nx-842-pseries.c | 9 | ||||
-rw-r--r-- | drivers/crypto/nx/nx-842.c | 4 | ||||
-rw-r--r-- | drivers/crypto/nx/nx-842.h | 97 | ||||
-rw-r--r-- | include/linux/nx842.h | 6 |
7 files changed, 741 insertions, 12 deletions
diff --git a/drivers/crypto/nx/Kconfig b/drivers/crypto/nx/Kconfig index 34013f7d46c8..ee9e25956241 100644 --- a/drivers/crypto/nx/Kconfig +++ b/drivers/crypto/nx/Kconfig | |||
@@ -40,4 +40,14 @@ config CRYPTO_DEV_NX_COMPRESS_PSERIES | |||
40 | algorithm. This supports NX hardware on the pSeries platform. | 40 | algorithm. This supports NX hardware on the pSeries platform. |
41 | If you choose 'M' here, this module will be called nx_compress_pseries. | 41 | If you choose 'M' here, this module will be called nx_compress_pseries. |
42 | 42 | ||
43 | config CRYPTO_DEV_NX_COMPRESS_POWERNV | ||
44 | tristate "Compression acceleration support on PowerNV platform" | ||
45 | depends on PPC_POWERNV | ||
46 | default y | ||
47 | help | ||
48 | Support for PowerPC Nest (NX) compression acceleration. This | ||
49 | module supports acceleration for compressing memory with the 842 | ||
50 | algorithm. This supports NX hardware on the PowerNV platform. | ||
51 | If you choose 'M' here, this module will be called nx_compress_powernv. | ||
52 | |||
43 | endif | 53 | endif |
diff --git a/drivers/crypto/nx/Makefile b/drivers/crypto/nx/Makefile index 5d9f4bc15209..6619787423b3 100644 --- a/drivers/crypto/nx/Makefile +++ b/drivers/crypto/nx/Makefile | |||
@@ -12,5 +12,7 @@ nx-crypto-objs := nx.o \ | |||
12 | 12 | ||
13 | obj-$(CONFIG_CRYPTO_DEV_NX_COMPRESS) += nx-compress.o | 13 | obj-$(CONFIG_CRYPTO_DEV_NX_COMPRESS) += nx-compress.o |
14 | obj-$(CONFIG_CRYPTO_DEV_NX_COMPRESS_PSERIES) += nx-compress-pseries.o | 14 | obj-$(CONFIG_CRYPTO_DEV_NX_COMPRESS_PSERIES) += nx-compress-pseries.o |
15 | obj-$(CONFIG_CRYPTO_DEV_NX_COMPRESS_POWERNV) += nx-compress-powernv.o | ||
15 | nx-compress-objs := nx-842.o | 16 | nx-compress-objs := nx-842.o |
16 | nx-compress-pseries-objs := nx-842-pseries.o | 17 | nx-compress-pseries-objs := nx-842-pseries.o |
18 | nx-compress-powernv-objs := nx-842-powernv.o | ||
diff --git a/drivers/crypto/nx/nx-842-powernv.c b/drivers/crypto/nx/nx-842-powernv.c new file mode 100644 index 000000000000..6a9fb8b2d05b --- /dev/null +++ b/drivers/crypto/nx/nx-842-powernv.c | |||
@@ -0,0 +1,625 @@ | |||
1 | /* | ||
2 | * Driver for IBM PowerNV 842 compression accelerator | ||
3 | * | ||
4 | * Copyright (C) 2015 Dan Streetman, IBM Corp | ||
5 | * | ||
6 | * This program is free software; you can redistribute it and/or modify | ||
7 | * it under the terms of the GNU General Public License as published by | ||
8 | * the Free Software Foundation; either version 2 of the License, or | ||
9 | * (at your option) any later version. | ||
10 | * | ||
11 | * This program is distributed in the hope that it will be useful, | ||
12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
14 | * GNU General Public License for more details. | ||
15 | */ | ||
16 | |||
17 | #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt | ||
18 | |||
19 | #include "nx-842.h" | ||
20 | |||
21 | #include <linux/timer.h> | ||
22 | |||
23 | #include <asm/prom.h> | ||
24 | #include <asm/icswx.h> | ||
25 | |||
26 | #define MODULE_NAME NX842_POWERNV_MODULE_NAME | ||
27 | MODULE_LICENSE("GPL"); | ||
28 | MODULE_AUTHOR("Dan Streetman <ddstreet@ieee.org>"); | ||
29 | MODULE_DESCRIPTION("842 H/W Compression driver for IBM PowerNV processors"); | ||
30 | |||
31 | #define WORKMEM_ALIGN (CRB_ALIGN) | ||
32 | #define CSB_WAIT_MAX (5000) /* ms */ | ||
33 | |||
34 | struct nx842_workmem { | ||
35 | /* Below fields must be properly aligned */ | ||
36 | struct coprocessor_request_block crb; /* CRB_ALIGN align */ | ||
37 | struct data_descriptor_entry ddl_in[DDL_LEN_MAX]; /* DDE_ALIGN align */ | ||
38 | struct data_descriptor_entry ddl_out[DDL_LEN_MAX]; /* DDE_ALIGN align */ | ||
39 | /* Above fields must be properly aligned */ | ||
40 | |||
41 | ktime_t start; | ||
42 | |||
43 | char padding[WORKMEM_ALIGN]; /* unused, to allow alignment */ | ||
44 | } __packed __aligned(WORKMEM_ALIGN); | ||
45 | |||
46 | struct nx842_coproc { | ||
47 | unsigned int chip_id; | ||
48 | unsigned int ct; | ||
49 | unsigned int ci; | ||
50 | struct list_head list; | ||
51 | }; | ||
52 | |||
53 | /* no cpu hotplug on powernv, so this list never changes after init */ | ||
54 | static LIST_HEAD(nx842_coprocs); | ||
55 | static unsigned int nx842_ct; | ||
56 | |||
57 | /** | ||
58 | * setup_indirect_dde - Setup an indirect DDE | ||
59 | * | ||
60 | * The DDE is setup with the the DDE count, byte count, and address of | ||
61 | * first direct DDE in the list. | ||
62 | */ | ||
63 | static void setup_indirect_dde(struct data_descriptor_entry *dde, | ||
64 | struct data_descriptor_entry *ddl, | ||
65 | unsigned int dde_count, unsigned int byte_count) | ||
66 | { | ||
67 | dde->flags = 0; | ||
68 | dde->count = dde_count; | ||
69 | dde->index = 0; | ||
70 | dde->length = cpu_to_be32(byte_count); | ||
71 | dde->address = cpu_to_be64(nx842_get_pa(ddl)); | ||
72 | } | ||
73 | |||
74 | /** | ||
75 | * setup_direct_dde - Setup single DDE from buffer | ||
76 | * | ||
77 | * The DDE is setup with the buffer and length. The buffer must be properly | ||
78 | * aligned. The used length is returned. | ||
79 | * Returns: | ||
80 | * N Successfully set up DDE with N bytes | ||
81 | */ | ||
82 | static unsigned int setup_direct_dde(struct data_descriptor_entry *dde, | ||
83 | unsigned long pa, unsigned int len) | ||
84 | { | ||
85 | unsigned int l = min_t(unsigned int, len, LEN_ON_PAGE(pa)); | ||
86 | |||
87 | dde->flags = 0; | ||
88 | dde->count = 0; | ||
89 | dde->index = 0; | ||
90 | dde->length = cpu_to_be32(l); | ||
91 | dde->address = cpu_to_be64(pa); | ||
92 | |||
93 | return l; | ||
94 | } | ||
95 | |||
96 | /** | ||
97 | * setup_ddl - Setup DDL from buffer | ||
98 | * | ||
99 | * Returns: | ||
100 | * 0 Successfully set up DDL | ||
101 | */ | ||
102 | static int setup_ddl(struct data_descriptor_entry *dde, | ||
103 | struct data_descriptor_entry *ddl, | ||
104 | unsigned char *buf, unsigned int len, | ||
105 | bool in) | ||
106 | { | ||
107 | unsigned long pa = nx842_get_pa(buf); | ||
108 | int i, ret, total_len = len; | ||
109 | |||
110 | if (!IS_ALIGNED(pa, DDE_BUFFER_ALIGN)) { | ||
111 | pr_debug("%s buffer pa 0x%lx not 0x%x-byte aligned\n", | ||
112 | in ? "input" : "output", pa, DDE_BUFFER_ALIGN); | ||
113 | return -EINVAL; | ||
114 | } | ||
115 | |||
116 | /* only need to check last mult; since buffer must be | ||
117 | * DDE_BUFFER_ALIGN aligned, and that is a multiple of | ||
118 | * DDE_BUFFER_SIZE_MULT, and pre-last page DDE buffers | ||
119 | * are guaranteed a multiple of DDE_BUFFER_SIZE_MULT. | ||
120 | */ | ||
121 | if (len % DDE_BUFFER_LAST_MULT) { | ||
122 | pr_debug("%s buffer len 0x%x not a multiple of 0x%x\n", | ||
123 | in ? "input" : "output", len, DDE_BUFFER_LAST_MULT); | ||
124 | if (in) | ||
125 | return -EINVAL; | ||
126 | len = round_down(len, DDE_BUFFER_LAST_MULT); | ||
127 | } | ||
128 | |||
129 | /* use a single direct DDE */ | ||
130 | if (len <= LEN_ON_PAGE(pa)) { | ||
131 | ret = setup_direct_dde(dde, pa, len); | ||
132 | WARN_ON(ret < len); | ||
133 | return 0; | ||
134 | } | ||
135 | |||
136 | /* use the DDL */ | ||
137 | for (i = 0; i < DDL_LEN_MAX && len > 0; i++) { | ||
138 | ret = setup_direct_dde(&ddl[i], pa, len); | ||
139 | buf += ret; | ||
140 | len -= ret; | ||
141 | pa = nx842_get_pa(buf); | ||
142 | } | ||
143 | |||
144 | if (len > 0) { | ||
145 | pr_debug("0x%x total %s bytes 0x%x too many for DDL.\n", | ||
146 | total_len, in ? "input" : "output", len); | ||
147 | if (in) | ||
148 | return -EMSGSIZE; | ||
149 | total_len -= len; | ||
150 | } | ||
151 | setup_indirect_dde(dde, ddl, i, total_len); | ||
152 | |||
153 | return 0; | ||
154 | } | ||
155 | |||
156 | #define CSB_ERR(csb, msg, ...) \ | ||
157 | pr_err("ERROR: " msg " : %02x %02x %02x %02x %08x\n", \ | ||
158 | ##__VA_ARGS__, (csb)->flags, \ | ||
159 | (csb)->cs, (csb)->cc, (csb)->ce, \ | ||
160 | be32_to_cpu((csb)->count)) | ||
161 | |||
162 | #define CSB_ERR_ADDR(csb, msg, ...) \ | ||
163 | CSB_ERR(csb, msg " at %lx", ##__VA_ARGS__, \ | ||
164 | (unsigned long)be64_to_cpu((csb)->address)) | ||
165 | |||
166 | /** | ||
167 | * wait_for_csb | ||
168 | */ | ||
169 | static int wait_for_csb(struct nx842_workmem *wmem, | ||
170 | struct coprocessor_status_block *csb) | ||
171 | { | ||
172 | ktime_t start = wmem->start, now = ktime_get(); | ||
173 | ktime_t timeout = ktime_add_ms(start, CSB_WAIT_MAX); | ||
174 | |||
175 | while (!(ACCESS_ONCE(csb->flags) & CSB_V)) { | ||
176 | cpu_relax(); | ||
177 | now = ktime_get(); | ||
178 | if (ktime_after(now, timeout)) | ||
179 | break; | ||
180 | } | ||
181 | |||
182 | /* hw has updated csb and output buffer */ | ||
183 | barrier(); | ||
184 | |||
185 | /* check CSB flags */ | ||
186 | if (!(csb->flags & CSB_V)) { | ||
187 | CSB_ERR(csb, "CSB still not valid after %ld us, giving up", | ||
188 | (long)ktime_us_delta(now, start)); | ||
189 | return -ETIMEDOUT; | ||
190 | } | ||
191 | if (csb->flags & CSB_F) { | ||
192 | CSB_ERR(csb, "Invalid CSB format"); | ||
193 | return -EPROTO; | ||
194 | } | ||
195 | if (csb->flags & CSB_CH) { | ||
196 | CSB_ERR(csb, "Invalid CSB chaining state"); | ||
197 | return -EPROTO; | ||
198 | } | ||
199 | |||
200 | /* verify CSB completion sequence is 0 */ | ||
201 | if (csb->cs) { | ||
202 | CSB_ERR(csb, "Invalid CSB completion sequence"); | ||
203 | return -EPROTO; | ||
204 | } | ||
205 | |||
206 | /* check CSB Completion Code */ | ||
207 | switch (csb->cc) { | ||
208 | /* no error */ | ||
209 | case CSB_CC_SUCCESS: | ||
210 | break; | ||
211 | case CSB_CC_TPBC_GT_SPBC: | ||
212 | /* not an error, but the compressed data is | ||
213 | * larger than the uncompressed data :( | ||
214 | */ | ||
215 | break; | ||
216 | |||
217 | /* input data errors */ | ||
218 | case CSB_CC_OPERAND_OVERLAP: | ||
219 | /* input and output buffers overlap */ | ||
220 | CSB_ERR(csb, "Operand Overlap error"); | ||
221 | return -EINVAL; | ||
222 | case CSB_CC_INVALID_OPERAND: | ||
223 | CSB_ERR(csb, "Invalid operand"); | ||
224 | return -EINVAL; | ||
225 | case CSB_CC_NOSPC: | ||
226 | /* output buffer too small */ | ||
227 | return -ENOSPC; | ||
228 | case CSB_CC_ABORT: | ||
229 | CSB_ERR(csb, "Function aborted"); | ||
230 | return -EINTR; | ||
231 | case CSB_CC_CRC_MISMATCH: | ||
232 | CSB_ERR(csb, "CRC mismatch"); | ||
233 | return -EINVAL; | ||
234 | case CSB_CC_TEMPL_INVALID: | ||
235 | CSB_ERR(csb, "Compressed data template invalid"); | ||
236 | return -EINVAL; | ||
237 | case CSB_CC_TEMPL_OVERFLOW: | ||
238 | CSB_ERR(csb, "Compressed data template shows data past end"); | ||
239 | return -EINVAL; | ||
240 | |||
241 | /* these should not happen */ | ||
242 | case CSB_CC_INVALID_ALIGN: | ||
243 | /* setup_ddl should have detected this */ | ||
244 | CSB_ERR_ADDR(csb, "Invalid alignment"); | ||
245 | return -EINVAL; | ||
246 | case CSB_CC_DATA_LENGTH: | ||
247 | /* setup_ddl should have detected this */ | ||
248 | CSB_ERR(csb, "Invalid data length"); | ||
249 | return -EINVAL; | ||
250 | case CSB_CC_WR_TRANSLATION: | ||
251 | case CSB_CC_TRANSLATION: | ||
252 | case CSB_CC_TRANSLATION_DUP1: | ||
253 | case CSB_CC_TRANSLATION_DUP2: | ||
254 | case CSB_CC_TRANSLATION_DUP3: | ||
255 | case CSB_CC_TRANSLATION_DUP4: | ||
256 | case CSB_CC_TRANSLATION_DUP5: | ||
257 | case CSB_CC_TRANSLATION_DUP6: | ||
258 | /* should not happen, we use physical addrs */ | ||
259 | CSB_ERR_ADDR(csb, "Translation error"); | ||
260 | return -EPROTO; | ||
261 | case CSB_CC_WR_PROTECTION: | ||
262 | case CSB_CC_PROTECTION: | ||
263 | case CSB_CC_PROTECTION_DUP1: | ||
264 | case CSB_CC_PROTECTION_DUP2: | ||
265 | case CSB_CC_PROTECTION_DUP3: | ||
266 | case CSB_CC_PROTECTION_DUP4: | ||
267 | case CSB_CC_PROTECTION_DUP5: | ||
268 | case CSB_CC_PROTECTION_DUP6: | ||
269 | /* should not happen, we use physical addrs */ | ||
270 | CSB_ERR_ADDR(csb, "Protection error"); | ||
271 | return -EPROTO; | ||
272 | case CSB_CC_PRIVILEGE: | ||
273 | /* shouldn't happen, we're in HYP mode */ | ||
274 | CSB_ERR(csb, "Insufficient Privilege error"); | ||
275 | return -EPROTO; | ||
276 | case CSB_CC_EXCESSIVE_DDE: | ||
277 | /* shouldn't happen, setup_ddl doesn't use many dde's */ | ||
278 | CSB_ERR(csb, "Too many DDEs in DDL"); | ||
279 | return -EINVAL; | ||
280 | case CSB_CC_TRANSPORT: | ||
281 | /* shouldn't happen, we setup CRB correctly */ | ||
282 | CSB_ERR(csb, "Invalid CRB"); | ||
283 | return -EINVAL; | ||
284 | case CSB_CC_SEGMENTED_DDL: | ||
285 | /* shouldn't happen, setup_ddl creates DDL right */ | ||
286 | CSB_ERR(csb, "Segmented DDL error"); | ||
287 | return -EINVAL; | ||
288 | case CSB_CC_DDE_OVERFLOW: | ||
289 | /* shouldn't happen, setup_ddl creates DDL right */ | ||
290 | CSB_ERR(csb, "DDE overflow error"); | ||
291 | return -EINVAL; | ||
292 | case CSB_CC_SESSION: | ||
293 | /* should not happen with ICSWX */ | ||
294 | CSB_ERR(csb, "Session violation error"); | ||
295 | return -EPROTO; | ||
296 | case CSB_CC_CHAIN: | ||
297 | /* should not happen, we don't use chained CRBs */ | ||
298 | CSB_ERR(csb, "Chained CRB error"); | ||
299 | return -EPROTO; | ||
300 | case CSB_CC_SEQUENCE: | ||
301 | /* should not happen, we don't use chained CRBs */ | ||
302 | CSB_ERR(csb, "CRB seqeunce number error"); | ||
303 | return -EPROTO; | ||
304 | case CSB_CC_UNKNOWN_CODE: | ||
305 | CSB_ERR(csb, "Unknown subfunction code"); | ||
306 | return -EPROTO; | ||
307 | |||
308 | /* hardware errors */ | ||
309 | case CSB_CC_RD_EXTERNAL: | ||
310 | case CSB_CC_RD_EXTERNAL_DUP1: | ||
311 | case CSB_CC_RD_EXTERNAL_DUP2: | ||
312 | case CSB_CC_RD_EXTERNAL_DUP3: | ||
313 | CSB_ERR_ADDR(csb, "Read error outside coprocessor"); | ||
314 | return -EPROTO; | ||
315 | case CSB_CC_WR_EXTERNAL: | ||
316 | CSB_ERR_ADDR(csb, "Write error outside coprocessor"); | ||
317 | return -EPROTO; | ||
318 | case CSB_CC_INTERNAL: | ||
319 | CSB_ERR(csb, "Internal error in coprocessor"); | ||
320 | return -EPROTO; | ||
321 | case CSB_CC_PROVISION: | ||
322 | CSB_ERR(csb, "Storage provision error"); | ||
323 | return -EPROTO; | ||
324 | case CSB_CC_HW: | ||
325 | CSB_ERR(csb, "Correctable hardware error"); | ||
326 | return -EPROTO; | ||
327 | |||
328 | default: | ||
329 | CSB_ERR(csb, "Invalid CC %d", csb->cc); | ||
330 | return -EPROTO; | ||
331 | } | ||
332 | |||
333 | /* check Completion Extension state */ | ||
334 | if (csb->ce & CSB_CE_TERMINATION) { | ||
335 | CSB_ERR(csb, "CSB request was terminated"); | ||
336 | return -EPROTO; | ||
337 | } | ||
338 | if (csb->ce & CSB_CE_INCOMPLETE) { | ||
339 | CSB_ERR(csb, "CSB request not complete"); | ||
340 | return -EPROTO; | ||
341 | } | ||
342 | if (!(csb->ce & CSB_CE_TPBC)) { | ||
343 | CSB_ERR(csb, "TPBC not provided, unknown target length"); | ||
344 | return -EPROTO; | ||
345 | } | ||
346 | |||
347 | /* successful completion */ | ||
348 | pr_debug_ratelimited("Processed %u bytes in %lu us\n", csb->count, | ||
349 | (unsigned long)ktime_us_delta(now, start)); | ||
350 | |||
351 | return 0; | ||
352 | } | ||
353 | |||
354 | /** | ||
355 | * nx842_powernv_function - compress/decompress data using the 842 algorithm | ||
356 | * | ||
357 | * (De)compression provided by the NX842 coprocessor on IBM PowerNV systems. | ||
358 | * This compresses or decompresses the provided input buffer into the provided | ||
359 | * output buffer. | ||
360 | * | ||
361 | * Upon return from this function @outlen contains the length of the | ||
362 | * output data. If there is an error then @outlen will be 0 and an | ||
363 | * error will be specified by the return code from this function. | ||
364 | * | ||
365 | * The @workmem buffer should only be used by one function call at a time. | ||
366 | * | ||
367 | * @in: input buffer pointer | ||
368 | * @inlen: input buffer size | ||
369 | * @out: output buffer pointer | ||
370 | * @outlenp: output buffer size pointer | ||
371 | * @workmem: working memory buffer pointer, must be at least NX842_MEM_COMPRESS | ||
372 | * @fc: function code, see CCW Function Codes in nx-842.h | ||
373 | * | ||
374 | * Returns: | ||
375 | * 0 Success, output of length @outlenp stored in the buffer at @out | ||
376 | * -ENODEV Hardware unavailable | ||
377 | * -ENOSPC Output buffer is to small | ||
378 | * -EMSGSIZE Input buffer too large | ||
379 | * -EINVAL buffer constraints do not fix nx842_constraints | ||
380 | * -EPROTO hardware error during operation | ||
381 | * -ETIMEDOUT hardware did not complete operation in reasonable time | ||
382 | * -EINTR operation was aborted | ||
383 | */ | ||
384 | static int nx842_powernv_function(const unsigned char *in, unsigned int inlen, | ||
385 | unsigned char *out, unsigned int *outlenp, | ||
386 | void *workmem, int fc) | ||
387 | { | ||
388 | struct coprocessor_request_block *crb; | ||
389 | struct coprocessor_status_block *csb; | ||
390 | struct nx842_workmem *wmem; | ||
391 | int ret; | ||
392 | u64 csb_addr; | ||
393 | u32 ccw; | ||
394 | unsigned int outlen = *outlenp; | ||
395 | |||
396 | wmem = PTR_ALIGN(workmem, WORKMEM_ALIGN); | ||
397 | |||
398 | *outlenp = 0; | ||
399 | |||
400 | /* shoudn't happen, we don't load without a coproc */ | ||
401 | if (!nx842_ct) { | ||
402 | pr_err_ratelimited("coprocessor CT is 0"); | ||
403 | return -ENODEV; | ||
404 | } | ||
405 | |||
406 | crb = &wmem->crb; | ||
407 | csb = &crb->csb; | ||
408 | |||
409 | /* Clear any previous values */ | ||
410 | memset(crb, 0, sizeof(*crb)); | ||
411 | |||
412 | /* set up DDLs */ | ||
413 | ret = setup_ddl(&crb->source, wmem->ddl_in, | ||
414 | (unsigned char *)in, inlen, true); | ||
415 | if (ret) | ||
416 | return ret; | ||
417 | ret = setup_ddl(&crb->target, wmem->ddl_out, | ||
418 | out, outlen, false); | ||
419 | if (ret) | ||
420 | return ret; | ||
421 | |||
422 | /* set up CCW */ | ||
423 | ccw = 0; | ||
424 | ccw = SET_FIELD(ccw, CCW_CT, nx842_ct); | ||
425 | ccw = SET_FIELD(ccw, CCW_CI_842, 0); /* use 0 for hw auto-selection */ | ||
426 | ccw = SET_FIELD(ccw, CCW_FC_842, fc); | ||
427 | |||
428 | /* set up CRB's CSB addr */ | ||
429 | csb_addr = nx842_get_pa(csb) & CRB_CSB_ADDRESS; | ||
430 | csb_addr |= CRB_CSB_AT; /* Addrs are phys */ | ||
431 | crb->csb_addr = cpu_to_be64(csb_addr); | ||
432 | |||
433 | wmem->start = ktime_get(); | ||
434 | |||
435 | /* do ICSWX */ | ||
436 | ret = icswx(cpu_to_be32(ccw), crb); | ||
437 | |||
438 | pr_debug_ratelimited("icswx CR %x ccw %x crb->ccw %x\n", ret, | ||
439 | (unsigned int)ccw, | ||
440 | (unsigned int)be32_to_cpu(crb->ccw)); | ||
441 | |||
442 | switch (ret) { | ||
443 | case ICSWX_INITIATED: | ||
444 | ret = wait_for_csb(wmem, csb); | ||
445 | break; | ||
446 | case ICSWX_BUSY: | ||
447 | pr_debug_ratelimited("842 Coprocessor busy\n"); | ||
448 | ret = -EBUSY; | ||
449 | break; | ||
450 | case ICSWX_REJECTED: | ||
451 | pr_err_ratelimited("ICSWX rejected\n"); | ||
452 | ret = -EPROTO; | ||
453 | break; | ||
454 | default: | ||
455 | pr_err_ratelimited("Invalid ICSWX return code %x\n", ret); | ||
456 | ret = -EPROTO; | ||
457 | break; | ||
458 | } | ||
459 | |||
460 | if (!ret) | ||
461 | *outlenp = be32_to_cpu(csb->count); | ||
462 | |||
463 | return ret; | ||
464 | } | ||
465 | |||
466 | /** | ||
467 | * nx842_powernv_compress - Compress data using the 842 algorithm | ||
468 | * | ||
469 | * Compression provided by the NX842 coprocessor on IBM PowerNV systems. | ||
470 | * The input buffer is compressed and the result is stored in the | ||
471 | * provided output buffer. | ||
472 | * | ||
473 | * Upon return from this function @outlen contains the length of the | ||
474 | * compressed data. If there is an error then @outlen will be 0 and an | ||
475 | * error will be specified by the return code from this function. | ||
476 | * | ||
477 | * @in: input buffer pointer | ||
478 | * @inlen: input buffer size | ||
479 | * @out: output buffer pointer | ||
480 | * @outlenp: output buffer size pointer | ||
481 | * @workmem: working memory buffer pointer, must be at least NX842_MEM_COMPRESS | ||
482 | * | ||
483 | * Returns: see @nx842_powernv_function() | ||
484 | */ | ||
485 | static int nx842_powernv_compress(const unsigned char *in, unsigned int inlen, | ||
486 | unsigned char *out, unsigned int *outlenp, | ||
487 | void *wmem) | ||
488 | { | ||
489 | return nx842_powernv_function(in, inlen, out, outlenp, | ||
490 | wmem, CCW_FC_842_COMP_NOCRC); | ||
491 | } | ||
492 | |||
493 | /** | ||
494 | * nx842_powernv_decompress - Decompress data using the 842 algorithm | ||
495 | * | ||
496 | * Decompression provided by the NX842 coprocessor on IBM PowerNV systems. | ||
497 | * The input buffer is decompressed and the result is stored in the | ||
498 | * provided output buffer. | ||
499 | * | ||
500 | * Upon return from this function @outlen contains the length of the | ||
501 | * decompressed data. If there is an error then @outlen will be 0 and an | ||
502 | * error will be specified by the return code from this function. | ||
503 | * | ||
504 | * @in: input buffer pointer | ||
505 | * @inlen: input buffer size | ||
506 | * @out: output buffer pointer | ||
507 | * @outlenp: output buffer size pointer | ||
508 | * @workmem: working memory buffer pointer, must be at least NX842_MEM_COMPRESS | ||
509 | * | ||
510 | * Returns: see @nx842_powernv_function() | ||
511 | */ | ||
512 | static int nx842_powernv_decompress(const unsigned char *in, unsigned int inlen, | ||
513 | unsigned char *out, unsigned int *outlenp, | ||
514 | void *wmem) | ||
515 | { | ||
516 | return nx842_powernv_function(in, inlen, out, outlenp, | ||
517 | wmem, CCW_FC_842_DECOMP_NOCRC); | ||
518 | } | ||
519 | |||
520 | static int __init nx842_powernv_probe(struct device_node *dn) | ||
521 | { | ||
522 | struct nx842_coproc *coproc; | ||
523 | struct property *ct_prop, *ci_prop; | ||
524 | unsigned int ct, ci; | ||
525 | int chip_id; | ||
526 | |||
527 | chip_id = of_get_ibm_chip_id(dn); | ||
528 | if (chip_id < 0) { | ||
529 | pr_err("ibm,chip-id missing\n"); | ||
530 | return -EINVAL; | ||
531 | } | ||
532 | ct_prop = of_find_property(dn, "ibm,842-coprocessor-type", NULL); | ||
533 | if (!ct_prop) { | ||
534 | pr_err("ibm,842-coprocessor-type missing\n"); | ||
535 | return -EINVAL; | ||
536 | } | ||
537 | ct = be32_to_cpu(*(unsigned int *)ct_prop->value); | ||
538 | ci_prop = of_find_property(dn, "ibm,842-coprocessor-instance", NULL); | ||
539 | if (!ci_prop) { | ||
540 | pr_err("ibm,842-coprocessor-instance missing\n"); | ||
541 | return -EINVAL; | ||
542 | } | ||
543 | ci = be32_to_cpu(*(unsigned int *)ci_prop->value); | ||
544 | |||
545 | coproc = kmalloc(sizeof(*coproc), GFP_KERNEL); | ||
546 | if (!coproc) | ||
547 | return -ENOMEM; | ||
548 | |||
549 | coproc->chip_id = chip_id; | ||
550 | coproc->ct = ct; | ||
551 | coproc->ci = ci; | ||
552 | INIT_LIST_HEAD(&coproc->list); | ||
553 | list_add(&coproc->list, &nx842_coprocs); | ||
554 | |||
555 | pr_info("coprocessor found on chip %d, CT %d CI %d\n", chip_id, ct, ci); | ||
556 | |||
557 | if (!nx842_ct) | ||
558 | nx842_ct = ct; | ||
559 | else if (nx842_ct != ct) | ||
560 | pr_err("NX842 chip %d, CT %d != first found CT %d\n", | ||
561 | chip_id, ct, nx842_ct); | ||
562 | |||
563 | return 0; | ||
564 | } | ||
565 | |||
566 | static struct nx842_constraints nx842_powernv_constraints = { | ||
567 | .alignment = DDE_BUFFER_ALIGN, | ||
568 | .multiple = DDE_BUFFER_LAST_MULT, | ||
569 | .minimum = DDE_BUFFER_LAST_MULT, | ||
570 | .maximum = (DDL_LEN_MAX - 1) * PAGE_SIZE, | ||
571 | }; | ||
572 | |||
573 | static struct nx842_driver nx842_powernv_driver = { | ||
574 | .owner = THIS_MODULE, | ||
575 | .constraints = &nx842_powernv_constraints, | ||
576 | .compress = nx842_powernv_compress, | ||
577 | .decompress = nx842_powernv_decompress, | ||
578 | }; | ||
579 | |||
580 | static __init int nx842_powernv_init(void) | ||
581 | { | ||
582 | struct device_node *dn; | ||
583 | |||
584 | /* verify workmem size/align restrictions */ | ||
585 | BUILD_BUG_ON(sizeof(struct nx842_workmem) > NX842_MEM_COMPRESS); | ||
586 | BUILD_BUG_ON(WORKMEM_ALIGN % CRB_ALIGN); | ||
587 | BUILD_BUG_ON(CRB_ALIGN % DDE_ALIGN); | ||
588 | BUILD_BUG_ON(CRB_SIZE % DDE_ALIGN); | ||
589 | /* verify buffer size/align restrictions */ | ||
590 | BUILD_BUG_ON(PAGE_SIZE % DDE_BUFFER_ALIGN); | ||
591 | BUILD_BUG_ON(DDE_BUFFER_ALIGN % DDE_BUFFER_SIZE_MULT); | ||
592 | BUILD_BUG_ON(DDE_BUFFER_SIZE_MULT % DDE_BUFFER_LAST_MULT); | ||
593 | |||
594 | pr_info("loading\n"); | ||
595 | |||
596 | for_each_compatible_node(dn, NULL, NX842_POWERNV_COMPAT_NAME) | ||
597 | nx842_powernv_probe(dn); | ||
598 | |||
599 | if (!nx842_ct) { | ||
600 | pr_err("no coprocessors found\n"); | ||
601 | return -ENODEV; | ||
602 | } | ||
603 | |||
604 | nx842_register_driver(&nx842_powernv_driver); | ||
605 | |||
606 | pr_info("loaded\n"); | ||
607 | |||
608 | return 0; | ||
609 | } | ||
610 | module_init(nx842_powernv_init); | ||
611 | |||
612 | static void __exit nx842_powernv_exit(void) | ||
613 | { | ||
614 | struct nx842_coproc *coproc, *n; | ||
615 | |||
616 | nx842_unregister_driver(&nx842_powernv_driver); | ||
617 | |||
618 | list_for_each_entry_safe(coproc, n, &nx842_coprocs, list) { | ||
619 | list_del(&coproc->list); | ||
620 | kfree(coproc); | ||
621 | } | ||
622 | |||
623 | pr_info("unloaded\n"); | ||
624 | } | ||
625 | module_exit(nx842_powernv_exit); | ||
diff --git a/drivers/crypto/nx/nx-842-pseries.c b/drivers/crypto/nx/nx-842-pseries.c index cb481d81df06..6db99924652c 100644 --- a/drivers/crypto/nx/nx-842-pseries.c +++ b/drivers/crypto/nx/nx-842-pseries.c | |||
@@ -160,15 +160,6 @@ static inline unsigned long nx842_get_scatterlist_size( | |||
160 | return sl->entry_nr * sizeof(struct nx842_slentry); | 160 | return sl->entry_nr * sizeof(struct nx842_slentry); |
161 | } | 161 | } |
162 | 162 | ||
163 | static inline unsigned long nx842_get_pa(void *addr) | ||
164 | { | ||
165 | if (is_vmalloc_addr(addr)) | ||
166 | return page_to_phys(vmalloc_to_page(addr)) | ||
167 | + offset_in_page(addr); | ||
168 | else | ||
169 | return __pa(addr); | ||
170 | } | ||
171 | |||
172 | static int nx842_build_scatterlist(unsigned long buf, int len, | 163 | static int nx842_build_scatterlist(unsigned long buf, int len, |
173 | struct nx842_scatterlist *sl) | 164 | struct nx842_scatterlist *sl) |
174 | { | 165 | { |
diff --git a/drivers/crypto/nx/nx-842.c b/drivers/crypto/nx/nx-842.c index 160fe2d97336..bf2823ceaf4e 100644 --- a/drivers/crypto/nx/nx-842.c +++ b/drivers/crypto/nx/nx-842.c | |||
@@ -164,7 +164,9 @@ static __init int nx842_init(void) | |||
164 | { | 164 | { |
165 | pr_info("loading\n"); | 165 | pr_info("loading\n"); |
166 | 166 | ||
167 | if (of_find_compatible_node(NULL, NULL, NX842_PSERIES_COMPAT_NAME)) | 167 | if (of_find_compatible_node(NULL, NULL, NX842_POWERNV_COMPAT_NAME)) |
168 | request_module_nowait(NX842_POWERNV_MODULE_NAME); | ||
169 | else if (of_find_compatible_node(NULL, NULL, NX842_PSERIES_COMPAT_NAME)) | ||
168 | request_module_nowait(NX842_PSERIES_MODULE_NAME); | 170 | request_module_nowait(NX842_PSERIES_MODULE_NAME); |
169 | else | 171 | else |
170 | pr_err("no nx842 driver found.\n"); | 172 | pr_err("no nx842 driver found.\n"); |
diff --git a/drivers/crypto/nx/nx-842.h b/drivers/crypto/nx/nx-842.h index c6ceb0f1d04c..84b15b7448bb 100644 --- a/drivers/crypto/nx/nx-842.h +++ b/drivers/crypto/nx/nx-842.h | |||
@@ -5,9 +5,104 @@ | |||
5 | #include <linux/kernel.h> | 5 | #include <linux/kernel.h> |
6 | #include <linux/module.h> | 6 | #include <linux/module.h> |
7 | #include <linux/nx842.h> | 7 | #include <linux/nx842.h> |
8 | #include <linux/sw842.h> | ||
8 | #include <linux/of.h> | 9 | #include <linux/of.h> |
9 | #include <linux/slab.h> | 10 | #include <linux/slab.h> |
10 | #include <linux/io.h> | 11 | #include <linux/io.h> |
12 | #include <linux/mm.h> | ||
13 | #include <linux/ratelimit.h> | ||
14 | |||
15 | /* Restrictions on Data Descriptor List (DDL) and Entry (DDE) buffers | ||
16 | * | ||
17 | * From NX P8 workbook, sec 4.9.1 "842 details" | ||
18 | * Each DDE buffer is 128 byte aligned | ||
19 | * Each DDE buffer size is a multiple of 32 bytes (except the last) | ||
20 | * The last DDE buffer size is a multiple of 8 bytes | ||
21 | */ | ||
22 | #define DDE_BUFFER_ALIGN (128) | ||
23 | #define DDE_BUFFER_SIZE_MULT (32) | ||
24 | #define DDE_BUFFER_LAST_MULT (8) | ||
25 | |||
26 | /* Arbitrary DDL length limit | ||
27 | * Allows max buffer size of MAX-1 to MAX pages | ||
28 | * (depending on alignment) | ||
29 | */ | ||
30 | #define DDL_LEN_MAX (17) | ||
31 | |||
32 | /* CCW 842 CI/FC masks | ||
33 | * NX P8 workbook, section 4.3.1, figure 4-6 | ||
34 | * "CI/FC Boundary by NX CT type" | ||
35 | */ | ||
36 | #define CCW_CI_842 (0x00003ff8) | ||
37 | #define CCW_FC_842 (0x00000007) | ||
38 | |||
39 | /* CCW Function Codes (FC) for 842 | ||
40 | * NX P8 workbook, section 4.9, table 4-28 | ||
41 | * "Function Code Definitions for 842 Memory Compression" | ||
42 | */ | ||
43 | #define CCW_FC_842_COMP_NOCRC (0) | ||
44 | #define CCW_FC_842_COMP_CRC (1) | ||
45 | #define CCW_FC_842_DECOMP_NOCRC (2) | ||
46 | #define CCW_FC_842_DECOMP_CRC (3) | ||
47 | #define CCW_FC_842_MOVE (4) | ||
48 | |||
49 | /* CSB CC Error Types for 842 | ||
50 | * NX P8 workbook, section 4.10.3, table 4-30 | ||
51 | * "Reported Error Types Summary Table" | ||
52 | */ | ||
53 | /* These are all duplicates of existing codes defined in icswx.h. */ | ||
54 | #define CSB_CC_TRANSLATION_DUP1 (80) | ||
55 | #define CSB_CC_TRANSLATION_DUP2 (82) | ||
56 | #define CSB_CC_TRANSLATION_DUP3 (84) | ||
57 | #define CSB_CC_TRANSLATION_DUP4 (86) | ||
58 | #define CSB_CC_TRANSLATION_DUP5 (92) | ||
59 | #define CSB_CC_TRANSLATION_DUP6 (94) | ||
60 | #define CSB_CC_PROTECTION_DUP1 (81) | ||
61 | #define CSB_CC_PROTECTION_DUP2 (83) | ||
62 | #define CSB_CC_PROTECTION_DUP3 (85) | ||
63 | #define CSB_CC_PROTECTION_DUP4 (87) | ||
64 | #define CSB_CC_PROTECTION_DUP5 (93) | ||
65 | #define CSB_CC_PROTECTION_DUP6 (95) | ||
66 | #define CSB_CC_RD_EXTERNAL_DUP1 (89) | ||
67 | #define CSB_CC_RD_EXTERNAL_DUP2 (90) | ||
68 | #define CSB_CC_RD_EXTERNAL_DUP3 (91) | ||
69 | /* These are specific to NX */ | ||
70 | /* 842 codes */ | ||
71 | #define CSB_CC_TPBC_GT_SPBC (64) /* no error, but >1 comp ratio */ | ||
72 | #define CSB_CC_CRC_MISMATCH (65) /* decomp crc mismatch */ | ||
73 | #define CSB_CC_TEMPL_INVALID (66) /* decomp invalid template value */ | ||
74 | #define CSB_CC_TEMPL_OVERFLOW (67) /* decomp template shows data after end */ | ||
75 | /* sym crypt codes */ | ||
76 | #define CSB_CC_DECRYPT_OVERFLOW (64) | ||
77 | /* asym crypt codes */ | ||
78 | #define CSB_CC_MINV_OVERFLOW (128) | ||
79 | /* These are reserved for hypervisor use */ | ||
80 | #define CSB_CC_HYP_RESERVE_START (240) | ||
81 | #define CSB_CC_HYP_RESERVE_END (253) | ||
82 | #define CSB_CC_HYP_NO_HW (254) | ||
83 | #define CSB_CC_HYP_HANG_ABORTED (255) | ||
84 | |||
85 | /* CCB Completion Modes (CM) for 842 | ||
86 | * NX P8 workbook, section 4.3, figure 4-5 | ||
87 | * "CRB Details - Normal Cop_Req (CL=00, C=1)" | ||
88 | */ | ||
89 | #define CCB_CM_EXTRA_WRITE (CCB_CM0_ALL_COMPLETIONS & CCB_CM12_STORE) | ||
90 | #define CCB_CM_INTERRUPT (CCB_CM0_ALL_COMPLETIONS & CCB_CM12_INTERRUPT) | ||
91 | |||
92 | #define LEN_ON_PAGE(pa) (PAGE_SIZE - ((pa) & ~PAGE_MASK)) | ||
93 | |||
94 | static inline unsigned long nx842_get_pa(void *addr) | ||
95 | { | ||
96 | if (!is_vmalloc_addr(addr)) | ||
97 | return __pa(addr); | ||
98 | |||
99 | return page_to_phys(vmalloc_to_page(addr)) + offset_in_page(addr); | ||
100 | } | ||
101 | |||
102 | /* Get/Set bit fields */ | ||
103 | #define MASK_LSH(m) (__builtin_ffsl(m) - 1) | ||
104 | #define GET_FIELD(v, m) (((v) & (m)) >> MASK_LSH(m)) | ||
105 | #define SET_FIELD(v, m, val) (((v) & ~(m)) | (((val) << MASK_LSH(m)) & (m))) | ||
11 | 106 | ||
12 | struct nx842_driver { | 107 | struct nx842_driver { |
13 | struct module *owner; | 108 | struct module *owner; |
@@ -27,6 +122,8 @@ void nx842_unregister_driver(struct nx842_driver *driver); | |||
27 | 122 | ||
28 | 123 | ||
29 | /* To allow the main nx-compress module to load platform module */ | 124 | /* To allow the main nx-compress module to load platform module */ |
125 | #define NX842_POWERNV_MODULE_NAME "nx-compress-powernv" | ||
126 | #define NX842_POWERNV_COMPAT_NAME "ibm,power-nx" | ||
30 | #define NX842_PSERIES_MODULE_NAME "nx-compress-pseries" | 127 | #define NX842_PSERIES_MODULE_NAME "nx-compress-pseries" |
31 | #define NX842_PSERIES_COMPAT_NAME "ibm,compression" | 128 | #define NX842_PSERIES_COMPAT_NAME "ibm,compression" |
32 | 129 | ||
diff --git a/include/linux/nx842.h b/include/linux/nx842.h index aa1a97e90dea..4ddf68d9c0d4 100644 --- a/include/linux/nx842.h +++ b/include/linux/nx842.h | |||
@@ -1,9 +1,11 @@ | |||
1 | #ifndef __NX842_H__ | 1 | #ifndef __NX842_H__ |
2 | #define __NX842_H__ | 2 | #define __NX842_H__ |
3 | 3 | ||
4 | #define __NX842_PSERIES_MEM_COMPRESS ((PAGE_SIZE * 2) + 10240) | 4 | #define __NX842_PSERIES_MEM_COMPRESS (10240) |
5 | #define __NX842_POWERNV_MEM_COMPRESS (1024) | ||
5 | 6 | ||
6 | #define NX842_MEM_COMPRESS __NX842_PSERIES_MEM_COMPRESS | 7 | #define NX842_MEM_COMPRESS (max_t(unsigned int, \ |
8 | __NX842_PSERIES_MEM_COMPRESS, __NX842_POWERNV_MEM_COMPRESS)) | ||
7 | 9 | ||
8 | struct nx842_constraints { | 10 | struct nx842_constraints { |
9 | int alignment; | 11 | int alignment; |