raw/ifpga/base: enhance driver reliability in multi-process
[dpdk.git] / drivers / raw / ifpga / base / opae_spi_transaction.c
1 /* SPDX-License-Identifier: BSD-3-Clause
2  * Copyright(c) 2010-2019 Intel Corporation
3  */
4
5 #include "opae_spi.h"
6 #include "ifpga_compat.h"
7
8 /*transaction opcodes*/
9 #define SPI_TRAN_SEQ_WRITE 0x04 /* SPI transaction sequential write */
10 #define SPI_TRAN_SEQ_READ  0x14 /* SPI transaction sequential read */
11 #define SPI_TRAN_NON_SEQ_WRITE 0x00 /* SPI transaction non-sequential write */
12 #define SPI_TRAN_NON_SEQ_READ  0x10 /* SPI transaction non-sequential read*/
13
14 /*specail packet characters*/
15 #define SPI_PACKET_SOP     0x7a
16 #define SPI_PACKET_EOP     0x7b
17 #define SPI_PACKET_CHANNEL 0x7c
18 #define SPI_PACKET_ESC     0x7d
19
20 /*special byte characters*/
21 #define SPI_BYTE_IDLE 0x4a
22 #define SPI_BYTE_ESC  0x4d
23
24 #define SPI_REG_BYTES 4
25
26 #define INIT_SPI_TRAN_HEADER(trans_type, size, address) \
27 ({ \
28         header.trans_type = trans_type; \
29         header.reserve = 0; \
30         header.size = cpu_to_be16(size); \
31         header.addr = cpu_to_be32(addr); \
32 })
33
34 #ifdef OPAE_SPI_DEBUG
35 static void print_buffer(const char *string, void *buffer, int len)
36 {
37         int i;
38         unsigned char *p = buffer;
39
40         printf("%s print buffer, len=%d\n", string, len);
41
42         for (i = 0; i < len; i++)
43                 printf("%x ", *(p+i));
44         printf("\n");
45 }
46 #else
47 static void print_buffer(const char *string, void *buffer, int len)
48 {
49         UNUSED(string);
50         UNUSED(buffer);
51         UNUSED(len);
52 }
53 #endif
54
55 static unsigned char xor_20(unsigned char val)
56 {
57         return val^0x20;
58 }
59
60 static void reorder_phy_data(u8 bits_per_word,
61                 void *buf, unsigned int len)
62 {
63         unsigned int count = len / (bits_per_word/8);
64         u32 *p;
65
66         if (bits_per_word == 32) {
67                 p = (u32 *)buf;
68                 while (count--) {
69                         *p = cpu_to_be32(*p);
70                         p++;
71                 }
72         }
73 }
74
75 enum {
76         SPI_FOUND_SOP,
77         SPI_FOUND_EOP,
78         SPI_NOT_FOUND,
79 };
80
81 static int resp_find_sop_eop(unsigned char *resp, unsigned int len,
82                 int flags)
83 {
84         int ret = SPI_NOT_FOUND;
85
86         unsigned char *b = resp;
87
88         /* find SOP */
89         if (flags != SPI_FOUND_SOP) {
90                 while (b < resp + len && *b != SPI_PACKET_SOP)
91                         b++;
92
93                 if (*b != SPI_PACKET_SOP)
94                         goto done;
95
96                 ret = SPI_FOUND_SOP;
97         }
98
99         /* find EOP */
100         while (b < resp + len && *b != SPI_PACKET_EOP)
101                 b++;
102
103         if (*b != SPI_PACKET_EOP)
104                 goto done;
105
106         ret = SPI_FOUND_EOP;
107
108 done:
109         return ret;
110 }
111
112 static void phy_tx_pad(unsigned char *phy_buf, unsigned int phy_buf_len,
113                 unsigned int *aligned_len)
114 {
115         unsigned char *p = &phy_buf[phy_buf_len - 1], *dst_p;
116
117         *aligned_len = IFPGA_ALIGN(phy_buf_len, 4);
118
119         if (*aligned_len == phy_buf_len)
120                 return;
121
122         dst_p = &phy_buf[*aligned_len - 1];
123
124         /* move EOP and bytes after EOP to the end of aligned size */
125         while (p > phy_buf) {
126                 *dst_p = *p;
127
128                 if (*p == SPI_PACKET_EOP)
129                         break;
130
131                 p--;
132                 dst_p--;
133         }
134
135         /* fill the hole with PHY_IDLE */
136         while (p < dst_p)
137                 *p++ = SPI_BYTE_IDLE;
138 }
139
140 static int byte_to_core_convert(struct spi_transaction_dev *dev,
141                 unsigned int send_len, unsigned char *send_data,
142                 unsigned int resp_len, unsigned char *resp_data,
143                 unsigned int *valid_resp_len)
144 {
145         unsigned int i;
146         int ret = 0;
147         unsigned char *send_packet = dev->buffer->bytes_send;
148         unsigned char *resp_packet = dev->buffer->bytes_resp;
149         unsigned char *p;
150         unsigned char current_byte;
151         unsigned char *tx_buffer;
152         unsigned int tx_len = 0;
153         unsigned char *rx_buffer;
154         unsigned int rx_len = 0;
155         int retry = 0;
156         int spi_flags;
157         unsigned long timeout = msecs_to_timer_cycles(1000);
158         unsigned long ticks;
159         unsigned int resp_max_len = 2 * resp_len;
160
161         print_buffer("before bytes:", send_data, send_len);
162
163         p = send_packet;
164
165         for (i = 0; i < send_len; i++) {
166                 current_byte = send_data[i];
167                 switch (current_byte) {
168                 case SPI_BYTE_IDLE:
169                         *p++ = SPI_BYTE_ESC;
170                         *p++ = xor_20(current_byte);
171                         break;
172                 case SPI_BYTE_ESC:
173                         *p++ = SPI_BYTE_ESC;
174                         *p++ = xor_20(current_byte);
175                         break;
176                 default:
177                         *p++ = current_byte;
178                         break;
179                 }
180         }
181
182         tx_len = p - send_packet;
183
184         print_buffer("before spi:", send_packet, tx_len);
185
186         phy_tx_pad(send_packet, tx_len, &tx_len);
187         print_buffer("after pad:", send_packet, tx_len);
188
189         reorder_phy_data(32, send_packet, tx_len);
190
191         print_buffer("after order to spi:", send_packet, tx_len);
192
193         /* call spi */
194         tx_buffer = send_packet;
195         rx_buffer = resp_packet;
196         rx_len = resp_max_len;
197         spi_flags = SPI_NOT_FOUND;
198
199 read_again:
200         ret = spi_command(dev->dev, dev->chipselect, tx_len, tx_buffer,
201                         rx_len, rx_buffer);
202         if (ret)
203                 return -EBUSY;
204
205         print_buffer("read from spi:", rx_buffer, rx_len);
206
207         /* look for SOP firstly*/
208         ret = resp_find_sop_eop(rx_buffer, rx_len - 1, spi_flags);
209         if (ret != SPI_FOUND_EOP) {
210                 tx_buffer = NULL;
211                 tx_len = 0;
212                 ticks = rte_get_timer_cycles();
213                 if (time_after(ticks, timeout) &&
214                                 retry++ > SPI_MAX_RETRY) {
215                         dev_err(NULL, "Have retry %d, found invalid packet data\n",
216                                 retry);
217                         return -EBUSY;
218                 }
219
220                 if (ret == SPI_FOUND_SOP) {
221                         rx_buffer += rx_len;
222                         resp_max_len += rx_len;
223                 }
224
225                 spi_flags = ret;
226                 goto read_again;
227         }
228
229         print_buffer("found valid data:", resp_packet, resp_max_len);
230
231         /* analyze response packet */
232         i = 0;
233         p = resp_data;
234         while (i < resp_max_len) {
235                 current_byte = resp_packet[i];
236                 switch (current_byte) {
237                 case SPI_BYTE_IDLE:
238                         i++;
239                         break;
240                 case SPI_BYTE_ESC:
241                         i++;
242                         current_byte = resp_packet[i];
243                         *p++ = xor_20(current_byte);
244                         i++;
245                         break;
246                 default:
247                         *p++ = current_byte;
248                         i++;
249                         break;
250                 }
251         }
252
253         /* receive "4a" means the SPI is idle, not valid data */
254         *valid_resp_len = p - resp_data;
255         if (*valid_resp_len == 0) {
256                 dev_err(NULL, "error: repond package without valid data\n");
257                 return -EINVAL;
258         }
259
260         return 0;
261 }
262
263 static int packet_to_byte_conver(struct spi_transaction_dev *dev,
264                 unsigned int send_len, unsigned char *send_buf,
265                 unsigned int resp_len, unsigned char *resp_buf,
266                 unsigned int *valid)
267 {
268         int ret = 0;
269         unsigned int i;
270         unsigned char current_byte;
271         unsigned int resp_max_len;
272         unsigned char *send_packet = dev->buffer->packet_send;
273         unsigned char *resp_packet = dev->buffer->packet_resp;
274         unsigned char *p;
275         unsigned int valid_resp_len = 0;
276
277         print_buffer("before packet:", send_buf, send_len);
278
279         resp_max_len = 2 * resp_len + 4;
280
281         p = send_packet;
282
283         /* SOP header */
284         *p++ = SPI_PACKET_SOP;
285
286         *p++ = SPI_PACKET_CHANNEL;
287         *p++ = 0;
288
289         /* append the data into a packet */
290         for (i = 0; i < send_len; i++) {
291                 current_byte = send_buf[i];
292
293                 /* EOP for last byte */
294                 if (i == send_len - 1)
295                         *p++ = SPI_PACKET_EOP;
296
297                 switch (current_byte) {
298                 case SPI_PACKET_SOP:
299                 case SPI_PACKET_EOP:
300                 case SPI_PACKET_CHANNEL:
301                 case SPI_PACKET_ESC:
302                         *p++ = SPI_PACKET_ESC;
303                         *p++ = xor_20(current_byte);
304                         break;
305                 default:
306                         *p++ = current_byte;
307                 }
308         }
309
310         ret = byte_to_core_convert(dev, p - send_packet,
311                         send_packet, resp_max_len, resp_packet,
312                         &valid_resp_len);
313         if (ret)
314                 return -EBUSY;
315
316         print_buffer("after byte conver:", resp_packet, valid_resp_len);
317
318         /* analyze the response packet */
319         p = resp_buf;
320
321         /* look for SOP */
322         for (i = 0; i < valid_resp_len; i++) {
323                 if (resp_packet[i] == SPI_PACKET_SOP)
324                         break;
325         }
326
327         if (i == valid_resp_len) {
328                 dev_err(NULL, "error on analyze response packet 0x%x\n",
329                                 resp_packet[i]);
330                 return -EINVAL;
331         }
332
333         i++;
334
335         /* continue parsing data after SOP */
336         while (i < valid_resp_len) {
337                 current_byte = resp_packet[i];
338
339                 switch (current_byte) {
340                 case SPI_PACKET_ESC:
341                 case SPI_PACKET_CHANNEL:
342                 case SPI_PACKET_SOP:
343                         i++;
344                         current_byte = resp_packet[i];
345                         *p++ = xor_20(current_byte);
346                         i++;
347                         break;
348                 case SPI_PACKET_EOP:
349                         i++;
350                         current_byte = resp_packet[i];
351                         if (current_byte == SPI_PACKET_ESC ||
352                                         current_byte == SPI_PACKET_CHANNEL ||
353                                         current_byte == SPI_PACKET_SOP) {
354                                 i++;
355                                 current_byte = resp_packet[i];
356                                 *p++ = xor_20(current_byte);
357                         } else
358                                 *p++ = current_byte;
359                         i = valid_resp_len;
360                         break;
361                 default:
362                         *p++ = current_byte;
363                         i++;
364                 }
365
366         }
367
368         *valid = p - resp_buf;
369
370         print_buffer("after packet:", resp_buf, *valid);
371
372         return ret;
373 }
374
375 static int do_transaction(struct spi_transaction_dev *dev, unsigned int addr,
376                 unsigned int size, unsigned char *data,
377                 unsigned int trans_type)
378 {
379
380         struct spi_tran_header header;
381         unsigned char *transaction = dev->buffer->tran_send;
382         unsigned char *response = dev->buffer->tran_resp;
383         unsigned char *p;
384         int ret = 0;
385         unsigned int i;
386         unsigned int valid_len = 0;
387
388         /* make transacation header */
389         INIT_SPI_TRAN_HEADER(trans_type, size, addr);
390
391         /* fill the header */
392         p = transaction;
393         opae_memcpy(p, &header, sizeof(struct spi_tran_header));
394         p = p + sizeof(struct spi_tran_header);
395
396         switch (trans_type) {
397         case SPI_TRAN_SEQ_WRITE:
398         case SPI_TRAN_NON_SEQ_WRITE:
399                 for (i = 0; i < size; i++)
400                         *p++ = *data++;
401
402                 ret = packet_to_byte_conver(dev, size + HEADER_LEN,
403                                 transaction, RESPONSE_LEN, response,
404                                 &valid_len);
405                 if (ret)
406                         return -EBUSY;
407
408                 /* check the result */
409                 if (size != ((unsigned int)(response[2] & 0xff) << 8 |
410                         (unsigned int)(response[3] & 0xff)))
411                         ret = -EBUSY;
412
413                 break;
414         case SPI_TRAN_SEQ_READ:
415         case SPI_TRAN_NON_SEQ_READ:
416                 ret = packet_to_byte_conver(dev, HEADER_LEN,
417                                 transaction, size, response,
418                                 &valid_len);
419                 if (ret || valid_len != size)
420                         return -EBUSY;
421
422                 for (i = 0; i < size; i++)
423                         *data++ = *response++;
424
425                 ret = 0;
426                 break;
427         }
428
429         return ret;
430 }
431
432 int spi_transaction_read(struct spi_transaction_dev *dev, unsigned int addr,
433                 unsigned int size, unsigned char *data)
434 {
435         int ret;
436
437         pthread_mutex_lock(dev->mutex);
438         ret = do_transaction(dev, addr, size, data,
439                         (size > SPI_REG_BYTES) ?
440                         SPI_TRAN_SEQ_READ : SPI_TRAN_NON_SEQ_READ);
441         pthread_mutex_unlock(dev->mutex);
442
443         return ret;
444 }
445
446 int spi_transaction_write(struct spi_transaction_dev *dev, unsigned int addr,
447                 unsigned int size, unsigned char *data)
448 {
449         int ret;
450
451         pthread_mutex_lock(dev->mutex);
452         ret = do_transaction(dev, addr, size, data,
453                         (size > SPI_REG_BYTES) ?
454                         SPI_TRAN_SEQ_WRITE : SPI_TRAN_NON_SEQ_WRITE);
455         pthread_mutex_unlock(dev->mutex);
456
457         return ret;
458 }
459
460 struct spi_transaction_dev *spi_transaction_init(struct altera_spi_device *dev,
461                 int chipselect)
462 {
463         struct spi_transaction_dev *spi_tran_dev;
464         int ret;
465
466         spi_tran_dev = opae_malloc(sizeof(struct spi_transaction_dev));
467         if (!spi_tran_dev)
468                 return NULL;
469
470         spi_tran_dev->dev = dev;
471         spi_tran_dev->chipselect = chipselect;
472
473         spi_tran_dev->buffer = opae_malloc(sizeof(struct spi_tran_buffer));
474         if (!spi_tran_dev->buffer)
475                 goto err;
476
477         ret = pthread_mutex_init(&spi_tran_dev->lock, NULL);
478         if (ret) {
479                 dev_err(spi_tran_dev, "fail to init mutex lock\n");
480                 goto err;
481         }
482         if (dev->mutex) {
483                 dev_info(NULL, "use multi-process mutex in spi\n");
484                 spi_tran_dev->mutex = dev->mutex;
485         } else {
486                 dev_info(NULL, "use multi-thread mutex in spi\n");
487                 spi_tran_dev->mutex = &spi_tran_dev->lock;
488         }
489
490         return spi_tran_dev;
491
492 err:
493         opae_free(spi_tran_dev);
494         return NULL;
495 }
496
497 void spi_transaction_remove(struct spi_transaction_dev *dev)
498 {
499         if (dev && dev->buffer)
500                 opae_free(dev->buffer);
501         if (dev) {
502                 pthread_mutex_destroy(&dev->lock);
503                 opae_free(dev);
504         }
505 }