1*4882a593Smuzhiyun // SPDX-License-Identifier: GPL-2.0-only
2*4882a593Smuzhiyun /*
3*4882a593Smuzhiyun * Copyright 2016 Broadcom
4*4882a593Smuzhiyun */
5*4882a593Smuzhiyun
6*4882a593Smuzhiyun #include <linux/debugfs.h>
7*4882a593Smuzhiyun
8*4882a593Smuzhiyun #include "cipher.h"
9*4882a593Smuzhiyun #include "util.h"
10*4882a593Smuzhiyun
11*4882a593Smuzhiyun /* offset of SPU_OFIFO_CTRL register */
12*4882a593Smuzhiyun #define SPU_OFIFO_CTRL 0x40
13*4882a593Smuzhiyun #define SPU_FIFO_WATERMARK 0x1FF
14*4882a593Smuzhiyun
15*4882a593Smuzhiyun /**
16*4882a593Smuzhiyun * spu_sg_at_offset() - Find the scatterlist entry at a given distance from the
17*4882a593Smuzhiyun * start of a scatterlist.
18*4882a593Smuzhiyun * @sg: [in] Start of a scatterlist
19*4882a593Smuzhiyun * @skip: [in] Distance from the start of the scatterlist, in bytes
20*4882a593Smuzhiyun * @sge: [out] Scatterlist entry at skip bytes from start
21*4882a593Smuzhiyun * @sge_offset: [out] Number of bytes from start of sge buffer to get to
22*4882a593Smuzhiyun * requested distance.
23*4882a593Smuzhiyun *
24*4882a593Smuzhiyun * Return: 0 if entry found at requested distance
25*4882a593Smuzhiyun * < 0 otherwise
26*4882a593Smuzhiyun */
spu_sg_at_offset(struct scatterlist * sg,unsigned int skip,struct scatterlist ** sge,unsigned int * sge_offset)27*4882a593Smuzhiyun int spu_sg_at_offset(struct scatterlist *sg, unsigned int skip,
28*4882a593Smuzhiyun struct scatterlist **sge, unsigned int *sge_offset)
29*4882a593Smuzhiyun {
30*4882a593Smuzhiyun /* byte index from start of sg to the end of the previous entry */
31*4882a593Smuzhiyun unsigned int index = 0;
32*4882a593Smuzhiyun /* byte index from start of sg to the end of the current entry */
33*4882a593Smuzhiyun unsigned int next_index;
34*4882a593Smuzhiyun
35*4882a593Smuzhiyun next_index = sg->length;
36*4882a593Smuzhiyun while (next_index <= skip) {
37*4882a593Smuzhiyun sg = sg_next(sg);
38*4882a593Smuzhiyun index = next_index;
39*4882a593Smuzhiyun if (!sg)
40*4882a593Smuzhiyun return -EINVAL;
41*4882a593Smuzhiyun next_index += sg->length;
42*4882a593Smuzhiyun }
43*4882a593Smuzhiyun
44*4882a593Smuzhiyun *sge_offset = skip - index;
45*4882a593Smuzhiyun *sge = sg;
46*4882a593Smuzhiyun return 0;
47*4882a593Smuzhiyun }
48*4882a593Smuzhiyun
49*4882a593Smuzhiyun /* Copy len bytes of sg data, starting at offset skip, to a dest buffer */
sg_copy_part_to_buf(struct scatterlist * src,u8 * dest,unsigned int len,unsigned int skip)50*4882a593Smuzhiyun void sg_copy_part_to_buf(struct scatterlist *src, u8 *dest,
51*4882a593Smuzhiyun unsigned int len, unsigned int skip)
52*4882a593Smuzhiyun {
53*4882a593Smuzhiyun size_t copied;
54*4882a593Smuzhiyun unsigned int nents = sg_nents(src);
55*4882a593Smuzhiyun
56*4882a593Smuzhiyun copied = sg_pcopy_to_buffer(src, nents, dest, len, skip);
57*4882a593Smuzhiyun if (copied != len) {
58*4882a593Smuzhiyun flow_log("%s copied %u bytes of %u requested. ",
59*4882a593Smuzhiyun __func__, (u32)copied, len);
60*4882a593Smuzhiyun flow_log("sg with %u entries and skip %u\n", nents, skip);
61*4882a593Smuzhiyun }
62*4882a593Smuzhiyun }
63*4882a593Smuzhiyun
64*4882a593Smuzhiyun /*
65*4882a593Smuzhiyun * Copy data into a scatterlist starting at a specified offset in the
66*4882a593Smuzhiyun * scatterlist. Specifically, copy len bytes of data in the buffer src
67*4882a593Smuzhiyun * into the scatterlist dest, starting skip bytes into the scatterlist.
68*4882a593Smuzhiyun */
sg_copy_part_from_buf(struct scatterlist * dest,u8 * src,unsigned int len,unsigned int skip)69*4882a593Smuzhiyun void sg_copy_part_from_buf(struct scatterlist *dest, u8 *src,
70*4882a593Smuzhiyun unsigned int len, unsigned int skip)
71*4882a593Smuzhiyun {
72*4882a593Smuzhiyun size_t copied;
73*4882a593Smuzhiyun unsigned int nents = sg_nents(dest);
74*4882a593Smuzhiyun
75*4882a593Smuzhiyun copied = sg_pcopy_from_buffer(dest, nents, src, len, skip);
76*4882a593Smuzhiyun if (copied != len) {
77*4882a593Smuzhiyun flow_log("%s copied %u bytes of %u requested. ",
78*4882a593Smuzhiyun __func__, (u32)copied, len);
79*4882a593Smuzhiyun flow_log("sg with %u entries and skip %u\n", nents, skip);
80*4882a593Smuzhiyun }
81*4882a593Smuzhiyun }
82*4882a593Smuzhiyun
83*4882a593Smuzhiyun /**
84*4882a593Smuzhiyun * spu_sg_count() - Determine number of elements in scatterlist to provide a
85*4882a593Smuzhiyun * specified number of bytes.
86*4882a593Smuzhiyun * @sg_list: scatterlist to examine
87*4882a593Smuzhiyun * @skip: index of starting point
88*4882a593Smuzhiyun * @nbytes: consider elements of scatterlist until reaching this number of
89*4882a593Smuzhiyun * bytes
90*4882a593Smuzhiyun *
91*4882a593Smuzhiyun * Return: the number of sg entries contributing to nbytes of data
92*4882a593Smuzhiyun */
spu_sg_count(struct scatterlist * sg_list,unsigned int skip,int nbytes)93*4882a593Smuzhiyun int spu_sg_count(struct scatterlist *sg_list, unsigned int skip, int nbytes)
94*4882a593Smuzhiyun {
95*4882a593Smuzhiyun struct scatterlist *sg;
96*4882a593Smuzhiyun int sg_nents = 0;
97*4882a593Smuzhiyun unsigned int offset;
98*4882a593Smuzhiyun
99*4882a593Smuzhiyun if (!sg_list)
100*4882a593Smuzhiyun return 0;
101*4882a593Smuzhiyun
102*4882a593Smuzhiyun if (spu_sg_at_offset(sg_list, skip, &sg, &offset) < 0)
103*4882a593Smuzhiyun return 0;
104*4882a593Smuzhiyun
105*4882a593Smuzhiyun while (sg && (nbytes > 0)) {
106*4882a593Smuzhiyun sg_nents++;
107*4882a593Smuzhiyun nbytes -= (sg->length - offset);
108*4882a593Smuzhiyun offset = 0;
109*4882a593Smuzhiyun sg = sg_next(sg);
110*4882a593Smuzhiyun }
111*4882a593Smuzhiyun return sg_nents;
112*4882a593Smuzhiyun }
113*4882a593Smuzhiyun
114*4882a593Smuzhiyun /**
115*4882a593Smuzhiyun * spu_msg_sg_add() - Copy scatterlist entries from one sg to another, up to a
116*4882a593Smuzhiyun * given length.
117*4882a593Smuzhiyun * @to_sg: scatterlist to copy to
118*4882a593Smuzhiyun * @from_sg: scatterlist to copy from
119*4882a593Smuzhiyun * @from_skip: number of bytes to skip in from_sg. Non-zero when previous
120*4882a593Smuzhiyun * request included part of the buffer in entry in from_sg.
121*4882a593Smuzhiyun * Assumes from_skip < from_sg->length.
122*4882a593Smuzhiyun * @from_nents number of entries in from_sg
123*4882a593Smuzhiyun * @length number of bytes to copy. may reach this limit before exhausting
124*4882a593Smuzhiyun * from_sg.
125*4882a593Smuzhiyun *
126*4882a593Smuzhiyun * Copies the entries themselves, not the data in the entries. Assumes to_sg has
127*4882a593Smuzhiyun * enough entries. Does not limit the size of an individual buffer in to_sg.
128*4882a593Smuzhiyun *
129*4882a593Smuzhiyun * to_sg, from_sg, skip are all updated to end of copy
130*4882a593Smuzhiyun *
131*4882a593Smuzhiyun * Return: Number of bytes copied
132*4882a593Smuzhiyun */
spu_msg_sg_add(struct scatterlist ** to_sg,struct scatterlist ** from_sg,u32 * from_skip,u8 from_nents,u32 length)133*4882a593Smuzhiyun u32 spu_msg_sg_add(struct scatterlist **to_sg,
134*4882a593Smuzhiyun struct scatterlist **from_sg, u32 *from_skip,
135*4882a593Smuzhiyun u8 from_nents, u32 length)
136*4882a593Smuzhiyun {
137*4882a593Smuzhiyun struct scatterlist *sg; /* an entry in from_sg */
138*4882a593Smuzhiyun struct scatterlist *to = *to_sg;
139*4882a593Smuzhiyun struct scatterlist *from = *from_sg;
140*4882a593Smuzhiyun u32 skip = *from_skip;
141*4882a593Smuzhiyun u32 offset;
142*4882a593Smuzhiyun int i;
143*4882a593Smuzhiyun u32 entry_len = 0;
144*4882a593Smuzhiyun u32 frag_len = 0; /* length of entry added to to_sg */
145*4882a593Smuzhiyun u32 copied = 0; /* number of bytes copied so far */
146*4882a593Smuzhiyun
147*4882a593Smuzhiyun if (length == 0)
148*4882a593Smuzhiyun return 0;
149*4882a593Smuzhiyun
150*4882a593Smuzhiyun for_each_sg(from, sg, from_nents, i) {
151*4882a593Smuzhiyun /* number of bytes in this from entry not yet used */
152*4882a593Smuzhiyun entry_len = sg->length - skip;
153*4882a593Smuzhiyun frag_len = min(entry_len, length - copied);
154*4882a593Smuzhiyun offset = sg->offset + skip;
155*4882a593Smuzhiyun if (frag_len)
156*4882a593Smuzhiyun sg_set_page(to++, sg_page(sg), frag_len, offset);
157*4882a593Smuzhiyun copied += frag_len;
158*4882a593Smuzhiyun if (copied == entry_len) {
159*4882a593Smuzhiyun /* used up all of from entry */
160*4882a593Smuzhiyun skip = 0; /* start at beginning of next entry */
161*4882a593Smuzhiyun }
162*4882a593Smuzhiyun if (copied == length)
163*4882a593Smuzhiyun break;
164*4882a593Smuzhiyun }
165*4882a593Smuzhiyun *to_sg = to;
166*4882a593Smuzhiyun *from_sg = sg;
167*4882a593Smuzhiyun if (frag_len < entry_len)
168*4882a593Smuzhiyun *from_skip = skip + frag_len;
169*4882a593Smuzhiyun else
170*4882a593Smuzhiyun *from_skip = 0;
171*4882a593Smuzhiyun
172*4882a593Smuzhiyun return copied;
173*4882a593Smuzhiyun }
174*4882a593Smuzhiyun
add_to_ctr(u8 * ctr_pos,unsigned int increment)175*4882a593Smuzhiyun void add_to_ctr(u8 *ctr_pos, unsigned int increment)
176*4882a593Smuzhiyun {
177*4882a593Smuzhiyun __be64 *high_be = (__be64 *)ctr_pos;
178*4882a593Smuzhiyun __be64 *low_be = high_be + 1;
179*4882a593Smuzhiyun u64 orig_low = __be64_to_cpu(*low_be);
180*4882a593Smuzhiyun u64 new_low = orig_low + (u64)increment;
181*4882a593Smuzhiyun
182*4882a593Smuzhiyun *low_be = __cpu_to_be64(new_low);
183*4882a593Smuzhiyun if (new_low < orig_low)
184*4882a593Smuzhiyun /* there was a carry from the low 8 bytes */
185*4882a593Smuzhiyun *high_be = __cpu_to_be64(__be64_to_cpu(*high_be) + 1);
186*4882a593Smuzhiyun }
187*4882a593Smuzhiyun
188*4882a593Smuzhiyun struct sdesc {
189*4882a593Smuzhiyun struct shash_desc shash;
190*4882a593Smuzhiyun char ctx[];
191*4882a593Smuzhiyun };
192*4882a593Smuzhiyun
193*4882a593Smuzhiyun /**
194*4882a593Smuzhiyun * do_shash() - Do a synchronous hash operation in software
195*4882a593Smuzhiyun * @name: The name of the hash algorithm
196*4882a593Smuzhiyun * @result: Buffer where digest is to be written
197*4882a593Smuzhiyun * @data1: First part of data to hash. May be NULL.
198*4882a593Smuzhiyun * @data1_len: Length of data1, in bytes
199*4882a593Smuzhiyun * @data2: Second part of data to hash. May be NULL.
200*4882a593Smuzhiyun * @data2_len: Length of data2, in bytes
201*4882a593Smuzhiyun * @key: Key (if keyed hash)
202*4882a593Smuzhiyun * @key_len: Length of key, in bytes (or 0 if non-keyed hash)
203*4882a593Smuzhiyun *
204*4882a593Smuzhiyun * Note that the crypto API will not select this driver's own transform because
205*4882a593Smuzhiyun * this driver only registers asynchronous algos.
206*4882a593Smuzhiyun *
207*4882a593Smuzhiyun * Return: 0 if hash successfully stored in result
208*4882a593Smuzhiyun * < 0 otherwise
209*4882a593Smuzhiyun */
do_shash(unsigned char * name,unsigned char * result,const u8 * data1,unsigned int data1_len,const u8 * data2,unsigned int data2_len,const u8 * key,unsigned int key_len)210*4882a593Smuzhiyun int do_shash(unsigned char *name, unsigned char *result,
211*4882a593Smuzhiyun const u8 *data1, unsigned int data1_len,
212*4882a593Smuzhiyun const u8 *data2, unsigned int data2_len,
213*4882a593Smuzhiyun const u8 *key, unsigned int key_len)
214*4882a593Smuzhiyun {
215*4882a593Smuzhiyun int rc;
216*4882a593Smuzhiyun unsigned int size;
217*4882a593Smuzhiyun struct crypto_shash *hash;
218*4882a593Smuzhiyun struct sdesc *sdesc;
219*4882a593Smuzhiyun
220*4882a593Smuzhiyun hash = crypto_alloc_shash(name, 0, 0);
221*4882a593Smuzhiyun if (IS_ERR(hash)) {
222*4882a593Smuzhiyun rc = PTR_ERR(hash);
223*4882a593Smuzhiyun pr_err("%s: Crypto %s allocation error %d\n", __func__, name, rc);
224*4882a593Smuzhiyun return rc;
225*4882a593Smuzhiyun }
226*4882a593Smuzhiyun
227*4882a593Smuzhiyun size = sizeof(struct shash_desc) + crypto_shash_descsize(hash);
228*4882a593Smuzhiyun sdesc = kmalloc(size, GFP_KERNEL);
229*4882a593Smuzhiyun if (!sdesc) {
230*4882a593Smuzhiyun rc = -ENOMEM;
231*4882a593Smuzhiyun goto do_shash_err;
232*4882a593Smuzhiyun }
233*4882a593Smuzhiyun sdesc->shash.tfm = hash;
234*4882a593Smuzhiyun
235*4882a593Smuzhiyun if (key_len > 0) {
236*4882a593Smuzhiyun rc = crypto_shash_setkey(hash, key, key_len);
237*4882a593Smuzhiyun if (rc) {
238*4882a593Smuzhiyun pr_err("%s: Could not setkey %s shash\n", __func__, name);
239*4882a593Smuzhiyun goto do_shash_err;
240*4882a593Smuzhiyun }
241*4882a593Smuzhiyun }
242*4882a593Smuzhiyun
243*4882a593Smuzhiyun rc = crypto_shash_init(&sdesc->shash);
244*4882a593Smuzhiyun if (rc) {
245*4882a593Smuzhiyun pr_err("%s: Could not init %s shash\n", __func__, name);
246*4882a593Smuzhiyun goto do_shash_err;
247*4882a593Smuzhiyun }
248*4882a593Smuzhiyun rc = crypto_shash_update(&sdesc->shash, data1, data1_len);
249*4882a593Smuzhiyun if (rc) {
250*4882a593Smuzhiyun pr_err("%s: Could not update1\n", __func__);
251*4882a593Smuzhiyun goto do_shash_err;
252*4882a593Smuzhiyun }
253*4882a593Smuzhiyun if (data2 && data2_len) {
254*4882a593Smuzhiyun rc = crypto_shash_update(&sdesc->shash, data2, data2_len);
255*4882a593Smuzhiyun if (rc) {
256*4882a593Smuzhiyun pr_err("%s: Could not update2\n", __func__);
257*4882a593Smuzhiyun goto do_shash_err;
258*4882a593Smuzhiyun }
259*4882a593Smuzhiyun }
260*4882a593Smuzhiyun rc = crypto_shash_final(&sdesc->shash, result);
261*4882a593Smuzhiyun if (rc)
262*4882a593Smuzhiyun pr_err("%s: Could not generate %s hash\n", __func__, name);
263*4882a593Smuzhiyun
264*4882a593Smuzhiyun do_shash_err:
265*4882a593Smuzhiyun crypto_free_shash(hash);
266*4882a593Smuzhiyun kfree(sdesc);
267*4882a593Smuzhiyun
268*4882a593Smuzhiyun return rc;
269*4882a593Smuzhiyun }
270*4882a593Smuzhiyun
271*4882a593Smuzhiyun /* Dump len bytes of a scatterlist starting at skip bytes into the sg */
__dump_sg(struct scatterlist * sg,unsigned int skip,unsigned int len)272*4882a593Smuzhiyun void __dump_sg(struct scatterlist *sg, unsigned int skip, unsigned int len)
273*4882a593Smuzhiyun {
274*4882a593Smuzhiyun u8 dbuf[16];
275*4882a593Smuzhiyun unsigned int idx = skip;
276*4882a593Smuzhiyun unsigned int num_out = 0; /* number of bytes dumped so far */
277*4882a593Smuzhiyun unsigned int count;
278*4882a593Smuzhiyun
279*4882a593Smuzhiyun if (packet_debug_logging) {
280*4882a593Smuzhiyun while (num_out < len) {
281*4882a593Smuzhiyun count = (len - num_out > 16) ? 16 : len - num_out;
282*4882a593Smuzhiyun sg_copy_part_to_buf(sg, dbuf, count, idx);
283*4882a593Smuzhiyun num_out += count;
284*4882a593Smuzhiyun print_hex_dump(KERN_ALERT, " sg: ", DUMP_PREFIX_NONE,
285*4882a593Smuzhiyun 4, 1, dbuf, count, false);
286*4882a593Smuzhiyun idx += 16;
287*4882a593Smuzhiyun }
288*4882a593Smuzhiyun }
289*4882a593Smuzhiyun if (debug_logging_sleep)
290*4882a593Smuzhiyun msleep(debug_logging_sleep);
291*4882a593Smuzhiyun }
292*4882a593Smuzhiyun
293*4882a593Smuzhiyun /* Returns the name for a given cipher alg/mode */
spu_alg_name(enum spu_cipher_alg alg,enum spu_cipher_mode mode)294*4882a593Smuzhiyun char *spu_alg_name(enum spu_cipher_alg alg, enum spu_cipher_mode mode)
295*4882a593Smuzhiyun {
296*4882a593Smuzhiyun switch (alg) {
297*4882a593Smuzhiyun case CIPHER_ALG_RC4:
298*4882a593Smuzhiyun return "rc4";
299*4882a593Smuzhiyun case CIPHER_ALG_AES:
300*4882a593Smuzhiyun switch (mode) {
301*4882a593Smuzhiyun case CIPHER_MODE_CBC:
302*4882a593Smuzhiyun return "cbc(aes)";
303*4882a593Smuzhiyun case CIPHER_MODE_ECB:
304*4882a593Smuzhiyun return "ecb(aes)";
305*4882a593Smuzhiyun case CIPHER_MODE_OFB:
306*4882a593Smuzhiyun return "ofb(aes)";
307*4882a593Smuzhiyun case CIPHER_MODE_CFB:
308*4882a593Smuzhiyun return "cfb(aes)";
309*4882a593Smuzhiyun case CIPHER_MODE_CTR:
310*4882a593Smuzhiyun return "ctr(aes)";
311*4882a593Smuzhiyun case CIPHER_MODE_XTS:
312*4882a593Smuzhiyun return "xts(aes)";
313*4882a593Smuzhiyun case CIPHER_MODE_GCM:
314*4882a593Smuzhiyun return "gcm(aes)";
315*4882a593Smuzhiyun default:
316*4882a593Smuzhiyun return "aes";
317*4882a593Smuzhiyun }
318*4882a593Smuzhiyun break;
319*4882a593Smuzhiyun case CIPHER_ALG_DES:
320*4882a593Smuzhiyun switch (mode) {
321*4882a593Smuzhiyun case CIPHER_MODE_CBC:
322*4882a593Smuzhiyun return "cbc(des)";
323*4882a593Smuzhiyun case CIPHER_MODE_ECB:
324*4882a593Smuzhiyun return "ecb(des)";
325*4882a593Smuzhiyun case CIPHER_MODE_CTR:
326*4882a593Smuzhiyun return "ctr(des)";
327*4882a593Smuzhiyun default:
328*4882a593Smuzhiyun return "des";
329*4882a593Smuzhiyun }
330*4882a593Smuzhiyun break;
331*4882a593Smuzhiyun case CIPHER_ALG_3DES:
332*4882a593Smuzhiyun switch (mode) {
333*4882a593Smuzhiyun case CIPHER_MODE_CBC:
334*4882a593Smuzhiyun return "cbc(des3_ede)";
335*4882a593Smuzhiyun case CIPHER_MODE_ECB:
336*4882a593Smuzhiyun return "ecb(des3_ede)";
337*4882a593Smuzhiyun case CIPHER_MODE_CTR:
338*4882a593Smuzhiyun return "ctr(des3_ede)";
339*4882a593Smuzhiyun default:
340*4882a593Smuzhiyun return "3des";
341*4882a593Smuzhiyun }
342*4882a593Smuzhiyun break;
343*4882a593Smuzhiyun default:
344*4882a593Smuzhiyun return "other";
345*4882a593Smuzhiyun }
346*4882a593Smuzhiyun }
347*4882a593Smuzhiyun
spu_debugfs_read(struct file * filp,char __user * ubuf,size_t count,loff_t * offp)348*4882a593Smuzhiyun static ssize_t spu_debugfs_read(struct file *filp, char __user *ubuf,
349*4882a593Smuzhiyun size_t count, loff_t *offp)
350*4882a593Smuzhiyun {
351*4882a593Smuzhiyun struct bcm_device_private *ipriv;
352*4882a593Smuzhiyun char *buf;
353*4882a593Smuzhiyun ssize_t ret, out_offset, out_count;
354*4882a593Smuzhiyun int i;
355*4882a593Smuzhiyun u32 fifo_len;
356*4882a593Smuzhiyun u32 spu_ofifo_ctrl;
357*4882a593Smuzhiyun u32 alg;
358*4882a593Smuzhiyun u32 mode;
359*4882a593Smuzhiyun u32 op_cnt;
360*4882a593Smuzhiyun
361*4882a593Smuzhiyun out_count = 2048;
362*4882a593Smuzhiyun
363*4882a593Smuzhiyun buf = kmalloc(out_count, GFP_KERNEL);
364*4882a593Smuzhiyun if (!buf)
365*4882a593Smuzhiyun return -ENOMEM;
366*4882a593Smuzhiyun
367*4882a593Smuzhiyun ipriv = filp->private_data;
368*4882a593Smuzhiyun out_offset = 0;
369*4882a593Smuzhiyun out_offset += scnprintf(buf + out_offset, out_count - out_offset,
370*4882a593Smuzhiyun "Number of SPUs.........%u\n",
371*4882a593Smuzhiyun ipriv->spu.num_spu);
372*4882a593Smuzhiyun out_offset += scnprintf(buf + out_offset, out_count - out_offset,
373*4882a593Smuzhiyun "Current sessions.......%u\n",
374*4882a593Smuzhiyun atomic_read(&ipriv->session_count));
375*4882a593Smuzhiyun out_offset += scnprintf(buf + out_offset, out_count - out_offset,
376*4882a593Smuzhiyun "Session count..........%u\n",
377*4882a593Smuzhiyun atomic_read(&ipriv->stream_count));
378*4882a593Smuzhiyun out_offset += scnprintf(buf + out_offset, out_count - out_offset,
379*4882a593Smuzhiyun "Cipher setkey..........%u\n",
380*4882a593Smuzhiyun atomic_read(&ipriv->setkey_cnt[SPU_OP_CIPHER]));
381*4882a593Smuzhiyun out_offset += scnprintf(buf + out_offset, out_count - out_offset,
382*4882a593Smuzhiyun "Cipher Ops.............%u\n",
383*4882a593Smuzhiyun atomic_read(&ipriv->op_counts[SPU_OP_CIPHER]));
384*4882a593Smuzhiyun for (alg = 0; alg < CIPHER_ALG_LAST; alg++) {
385*4882a593Smuzhiyun for (mode = 0; mode < CIPHER_MODE_LAST; mode++) {
386*4882a593Smuzhiyun op_cnt = atomic_read(&ipriv->cipher_cnt[alg][mode]);
387*4882a593Smuzhiyun if (op_cnt) {
388*4882a593Smuzhiyun out_offset += scnprintf(buf + out_offset,
389*4882a593Smuzhiyun out_count - out_offset,
390*4882a593Smuzhiyun " %-13s%11u\n",
391*4882a593Smuzhiyun spu_alg_name(alg, mode), op_cnt);
392*4882a593Smuzhiyun }
393*4882a593Smuzhiyun }
394*4882a593Smuzhiyun }
395*4882a593Smuzhiyun out_offset += scnprintf(buf + out_offset, out_count - out_offset,
396*4882a593Smuzhiyun "Hash Ops...............%u\n",
397*4882a593Smuzhiyun atomic_read(&ipriv->op_counts[SPU_OP_HASH]));
398*4882a593Smuzhiyun for (alg = 0; alg < HASH_ALG_LAST; alg++) {
399*4882a593Smuzhiyun op_cnt = atomic_read(&ipriv->hash_cnt[alg]);
400*4882a593Smuzhiyun if (op_cnt) {
401*4882a593Smuzhiyun out_offset += scnprintf(buf + out_offset,
402*4882a593Smuzhiyun out_count - out_offset,
403*4882a593Smuzhiyun " %-13s%11u\n",
404*4882a593Smuzhiyun hash_alg_name[alg], op_cnt);
405*4882a593Smuzhiyun }
406*4882a593Smuzhiyun }
407*4882a593Smuzhiyun out_offset += scnprintf(buf + out_offset, out_count - out_offset,
408*4882a593Smuzhiyun "HMAC setkey............%u\n",
409*4882a593Smuzhiyun atomic_read(&ipriv->setkey_cnt[SPU_OP_HMAC]));
410*4882a593Smuzhiyun out_offset += scnprintf(buf + out_offset, out_count - out_offset,
411*4882a593Smuzhiyun "HMAC Ops...............%u\n",
412*4882a593Smuzhiyun atomic_read(&ipriv->op_counts[SPU_OP_HMAC]));
413*4882a593Smuzhiyun for (alg = 0; alg < HASH_ALG_LAST; alg++) {
414*4882a593Smuzhiyun op_cnt = atomic_read(&ipriv->hmac_cnt[alg]);
415*4882a593Smuzhiyun if (op_cnt) {
416*4882a593Smuzhiyun out_offset += scnprintf(buf + out_offset,
417*4882a593Smuzhiyun out_count - out_offset,
418*4882a593Smuzhiyun " %-13s%11u\n",
419*4882a593Smuzhiyun hash_alg_name[alg], op_cnt);
420*4882a593Smuzhiyun }
421*4882a593Smuzhiyun }
422*4882a593Smuzhiyun out_offset += scnprintf(buf + out_offset, out_count - out_offset,
423*4882a593Smuzhiyun "AEAD setkey............%u\n",
424*4882a593Smuzhiyun atomic_read(&ipriv->setkey_cnt[SPU_OP_AEAD]));
425*4882a593Smuzhiyun
426*4882a593Smuzhiyun out_offset += scnprintf(buf + out_offset, out_count - out_offset,
427*4882a593Smuzhiyun "AEAD Ops...............%u\n",
428*4882a593Smuzhiyun atomic_read(&ipriv->op_counts[SPU_OP_AEAD]));
429*4882a593Smuzhiyun for (alg = 0; alg < AEAD_TYPE_LAST; alg++) {
430*4882a593Smuzhiyun op_cnt = atomic_read(&ipriv->aead_cnt[alg]);
431*4882a593Smuzhiyun if (op_cnt) {
432*4882a593Smuzhiyun out_offset += scnprintf(buf + out_offset,
433*4882a593Smuzhiyun out_count - out_offset,
434*4882a593Smuzhiyun " %-13s%11u\n",
435*4882a593Smuzhiyun aead_alg_name[alg], op_cnt);
436*4882a593Smuzhiyun }
437*4882a593Smuzhiyun }
438*4882a593Smuzhiyun out_offset += scnprintf(buf + out_offset, out_count - out_offset,
439*4882a593Smuzhiyun "Bytes of req data......%llu\n",
440*4882a593Smuzhiyun (u64)atomic64_read(&ipriv->bytes_out));
441*4882a593Smuzhiyun out_offset += scnprintf(buf + out_offset, out_count - out_offset,
442*4882a593Smuzhiyun "Bytes of resp data.....%llu\n",
443*4882a593Smuzhiyun (u64)atomic64_read(&ipriv->bytes_in));
444*4882a593Smuzhiyun out_offset += scnprintf(buf + out_offset, out_count - out_offset,
445*4882a593Smuzhiyun "Mailbox full...........%u\n",
446*4882a593Smuzhiyun atomic_read(&ipriv->mb_no_spc));
447*4882a593Smuzhiyun out_offset += scnprintf(buf + out_offset, out_count - out_offset,
448*4882a593Smuzhiyun "Mailbox send failures..%u\n",
449*4882a593Smuzhiyun atomic_read(&ipriv->mb_send_fail));
450*4882a593Smuzhiyun out_offset += scnprintf(buf + out_offset, out_count - out_offset,
451*4882a593Smuzhiyun "Check ICV errors.......%u\n",
452*4882a593Smuzhiyun atomic_read(&ipriv->bad_icv));
453*4882a593Smuzhiyun if (ipriv->spu.spu_type == SPU_TYPE_SPUM)
454*4882a593Smuzhiyun for (i = 0; i < ipriv->spu.num_spu; i++) {
455*4882a593Smuzhiyun spu_ofifo_ctrl = ioread32(ipriv->spu.reg_vbase[i] +
456*4882a593Smuzhiyun SPU_OFIFO_CTRL);
457*4882a593Smuzhiyun fifo_len = spu_ofifo_ctrl & SPU_FIFO_WATERMARK;
458*4882a593Smuzhiyun out_offset += scnprintf(buf + out_offset,
459*4882a593Smuzhiyun out_count - out_offset,
460*4882a593Smuzhiyun "SPU %d output FIFO high water.....%u\n",
461*4882a593Smuzhiyun i, fifo_len);
462*4882a593Smuzhiyun }
463*4882a593Smuzhiyun
464*4882a593Smuzhiyun if (out_offset > out_count)
465*4882a593Smuzhiyun out_offset = out_count;
466*4882a593Smuzhiyun
467*4882a593Smuzhiyun ret = simple_read_from_buffer(ubuf, count, offp, buf, out_offset);
468*4882a593Smuzhiyun kfree(buf);
469*4882a593Smuzhiyun return ret;
470*4882a593Smuzhiyun }
471*4882a593Smuzhiyun
472*4882a593Smuzhiyun static const struct file_operations spu_debugfs_stats = {
473*4882a593Smuzhiyun .owner = THIS_MODULE,
474*4882a593Smuzhiyun .open = simple_open,
475*4882a593Smuzhiyun .read = spu_debugfs_read,
476*4882a593Smuzhiyun };
477*4882a593Smuzhiyun
478*4882a593Smuzhiyun /*
479*4882a593Smuzhiyun * Create the debug FS directories. If the top-level directory has not yet
480*4882a593Smuzhiyun * been created, create it now. Create a stats file in this directory for
481*4882a593Smuzhiyun * a SPU.
482*4882a593Smuzhiyun */
spu_setup_debugfs(void)483*4882a593Smuzhiyun void spu_setup_debugfs(void)
484*4882a593Smuzhiyun {
485*4882a593Smuzhiyun if (!debugfs_initialized())
486*4882a593Smuzhiyun return;
487*4882a593Smuzhiyun
488*4882a593Smuzhiyun if (!iproc_priv.debugfs_dir)
489*4882a593Smuzhiyun iproc_priv.debugfs_dir = debugfs_create_dir(KBUILD_MODNAME,
490*4882a593Smuzhiyun NULL);
491*4882a593Smuzhiyun
492*4882a593Smuzhiyun if (!iproc_priv.debugfs_stats)
493*4882a593Smuzhiyun /* Create file with permissions S_IRUSR */
494*4882a593Smuzhiyun debugfs_create_file("stats", 0400, iproc_priv.debugfs_dir,
495*4882a593Smuzhiyun &iproc_priv, &spu_debugfs_stats);
496*4882a593Smuzhiyun }
497*4882a593Smuzhiyun
spu_free_debugfs(void)498*4882a593Smuzhiyun void spu_free_debugfs(void)
499*4882a593Smuzhiyun {
500*4882a593Smuzhiyun debugfs_remove_recursive(iproc_priv.debugfs_dir);
501*4882a593Smuzhiyun iproc_priv.debugfs_dir = NULL;
502*4882a593Smuzhiyun }
503*4882a593Smuzhiyun
504*4882a593Smuzhiyun /**
505*4882a593Smuzhiyun * format_value_ccm() - Format a value into a buffer, using a specified number
506*4882a593Smuzhiyun * of bytes (i.e. maybe writing value X into a 4 byte
507*4882a593Smuzhiyun * buffer, or maybe into a 12 byte buffer), as per the
508*4882a593Smuzhiyun * SPU CCM spec.
509*4882a593Smuzhiyun *
510*4882a593Smuzhiyun * @val: value to write (up to max of unsigned int)
511*4882a593Smuzhiyun * @buf: (pointer to) buffer to write the value
512*4882a593Smuzhiyun * @len: number of bytes to use (0 to 255)
513*4882a593Smuzhiyun *
514*4882a593Smuzhiyun */
format_value_ccm(unsigned int val,u8 * buf,u8 len)515*4882a593Smuzhiyun void format_value_ccm(unsigned int val, u8 *buf, u8 len)
516*4882a593Smuzhiyun {
517*4882a593Smuzhiyun int i;
518*4882a593Smuzhiyun
519*4882a593Smuzhiyun /* First clear full output buffer */
520*4882a593Smuzhiyun memset(buf, 0, len);
521*4882a593Smuzhiyun
522*4882a593Smuzhiyun /* Then, starting from right side, fill in with data */
523*4882a593Smuzhiyun for (i = 0; i < len; i++) {
524*4882a593Smuzhiyun buf[len - i - 1] = (val >> (8 * i)) & 0xff;
525*4882a593Smuzhiyun if (i >= 3)
526*4882a593Smuzhiyun break; /* Only handle up to 32 bits of 'val' */
527*4882a593Smuzhiyun }
528*4882a593Smuzhiyun }
529