Switchtec Userspace  PROJECT_NUMBER = PROJECT_NUMBER=PROJECT_NUMBER = 2.2
linux-uart.c
1 /*
2  * Microsemi Switchtec(tm) PCIe Management Library
3  * Copyright (c) 2018, Microsemi Corporation
4  *
5  * Permission is hereby granted, free of charge, to any person obtaining a
6  * copy of this software and associated documentation files (the "Software"),
7  * to deal in the Software without restriction, including without limitation
8  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
9  * and/or sell copies of the Software, and to permit persons to whom the
10  * Software is furnished to do so, subject to the following conditions:
11  *
12  * The above copyright notice and this permission notice shall be included
13  * in all copies or substantial portions of the Software.
14  *
15  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
16  * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
18  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
19  * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
20  * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
21  * OTHER DEALINGS IN THE SOFTWARE.
22  *
23  */
24 
25 #ifdef __linux__
26 
27 #include "../switchtec_priv.h"
28 #include "../crc.h"
29 #include "switchtec/switchtec.h"
30 #include "gasops.h"
31 
32 #include <sys/types.h>
33 #include <sys/stat.h>
34 #include <sys/ioctl.h>
35 #include <sys/mman.h>
36 #include <fcntl.h>
37 #include <unistd.h>
38 #include <errno.h>
39 #include <signal.h>
40 #include <stddef.h>
41 #include <assert.h>
42 #include <string.h>
43 #include <stdarg.h>
44 
45 #include <sys/file.h>
46 #include <termios.h>
47 
48 /*
49  * Example of uart operations
50  *
51  * GAS Write:
52  *
53  * command: gaswr -c -s <offset> 0x<byte str> <crc>
54  *
55  * case 1: success
56  * input: gaswr -c -s 0x5 0xaabbccddeeff 0x84
57  * output: gas_reg_write() success
58  * CRC: [0x84/0x84]
59  * 0x00000000:1212>
60  *
61  * case 2: success
62  * input: gaswr -c -s 0x135c10 0x00000008 0xbc
63  * output: [PFF] cs addr: 0x0304, not hit
64  * gas_reg_write() success
65  * CRC: [0xbc/0xbc]
66  * 0x00000000:2172>
67  *
68 
69  * case 3: crc error
70  * input: gaswr -c -s 0x5 0xaabbccddeeff 0xb
71  * output: gas_reg_write() CRC Error
72  * CRC: [0x84/0x0b]
73  * 0x00000000:0000>
74  *
75  * case 4: out of range
76  * input: gaswr -c -s 0x5135c00 0x00000000 0xe9
77  * output: Error with gas_reg_write(): 0x63006, Offset:0x5135c00
78  * CRC:[0xe9/0xe9]
79  * 0x00000000:084d>
80  *
81  * GAS Read:
82  *
83  * command: gasrd -c -s <offset> <byte count>
84  *
85  * case 1: success
86  * input: gasrd -c -s 0x3 5
87  * output: gas_reg_read <0x3> [5 Byte]
88  * 00 58 00 00 00
89  * CRC: 0x37
90  * 0x00000000:1204>
91  *
92  * case 2: success
93  * input: gasrd -c -s 0x135c00 4
94  * output: gas_reg_read <0x135c00> [4 Byte]
95  * [PFF] cs addr: 0x0300,not hit
96  * 00 00 00 00
97  * CRC: 0xb6
98  * 0x00000000:0d93>
99  *
100  * case 3: out of range
101  * input: gasrd -c -s 0x5135c00 4
102  * output: gas_reg_read <0x5135c00> [4 Byte]
103  * No access beyond the Total GAS Section
104  * ...
105  * ...
106  * 0x00000000:0d93>
107  */
108 
109 struct switchtec_uart{
110  struct switchtec_dev dev;
111  int fd;
112 };
113 
114 #define to_switchtec_uart(d) \
115  ((struct switchtec_uart *) \
116  ((char *)(d) - offsetof(struct switchtec_uart, dev)))
117 
118 #define UART_MAX_WRITE_BYTES 100
119 #define UART_MAX_READ_BYTES 1024
120 #define RETRY_NUM 3
121 #define SWITCHTEC_UART_BAUDRATE (B230400)
122 
123 static int send_cmd(int fd, const char *fmt, int write_bytes, ...)
124 {
125  int ret;
126  int i;
127  int cnt;
128  char cmd[1024];
129  uint8_t *write_data;
130  uint32_t write_crc;
131  va_list argp;
132 
133  va_start(argp, write_bytes);
134 
135  if (write_bytes) {
136  write_data = va_arg(argp, uint8_t *);
137  write_crc = va_arg(argp, uint32_t);
138  }
139 
140  cnt = vsnprintf(cmd, sizeof(cmd), fmt, argp);
141 
142  if (write_bytes) {
143  for (i = 0; i< write_bytes; i++) {
144  cnt += snprintf(cmd + cnt, sizeof(cmd) - cnt,
145  "%02x", write_data[write_bytes - 1 - i]);
146  }
147 
148  cnt += snprintf(cmd + cnt, sizeof(cmd) - cnt,
149  " 0x%x\r", write_crc);
150  }
151 
152  va_end(argp);
153 
154  ret = write(fd, cmd, cnt);
155  if (ret < 0)
156  return ret;
157 
158  if (ret != cnt) {
159  errno = EIO;
160  return -errno;
161  }
162 
163  return 0;
164 }
165 
166 static int read_resp_line(int fd, char *str)
167 {
168  int ret;
169  int cnt = 0;
170 
171  while(1) {
172  ret = read(fd, str + cnt, sizeof(str));
173  if (ret <= 0)
174  return ret;
175 
176  cnt += ret;
177  str[cnt] = '\0';
178 
179  /* Prompt "0x12345678:1234>" */
180  if (strrchr(str, ':') + 5 == strrchr(str, '>'))
181  return 0;
182  }
183 
184  return -1;
185 }
186 
187 static int cli_control(struct switchtec_dev *dev, const char *str)
188 {
189  int ret;
190  char rtn[1024];
191  struct switchtec_uart *udev = to_switchtec_uart(dev);
192 
193  ret = send_cmd(udev->fd, str, 0);
194  if (ret)
195  return ret;
196 
197  ret = read_resp_line(udev->fd, rtn);
198  if (ret)
199  return ret;
200 
201  return 0;
202 }
203 
204 #ifdef __CHECKER__
205 #define __force __attribute__((force))
206 #else
207 #define __force
208 #endif
209 
210 static void uart_close(struct switchtec_dev *dev)
211 {
212  struct switchtec_uart *udev = to_switchtec_uart(dev);
213  cli_control(dev, "echo 1\r");
214 
215  if (dev->gas_map)
216  munmap((void __force *)dev->gas_map,
217  dev->gas_map_size);
218 
219  flock(udev->fd, LOCK_UN);
220  close(udev->fd);
221  free(udev);
222 }
223 
224 static int map_gas(struct switchtec_dev *dev)
225 {
226  void *addr;
227  dev->gas_map_size = 4 << 20;
228 
229  addr = mmap(NULL, dev->gas_map_size,
230  PROT_NONE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
231  if (addr == MAP_FAILED)
232  return -1;
233 
234  dev->gas_map = (gasptr_t __force)addr;
235 
236  return 0;
237 }
238 
239 #undef __force
240 
241 static gasptr_t uart_gas_map(struct switchtec_dev *dev, int writeable,
242  size_t *map_size)
243 {
244  if (map_size)
245  *map_size = dev->gas_map_size;
246 
247  return dev->gas_map;
248 }
249 
250 static void uart_gas_read(struct switchtec_dev *dev, void *dest,
251  const void __gas *src, size_t n)
252 {
253  int ret;
254  int raddr, rnum, rcrc;
255  int i, j;
256  char *pos;
257  struct switchtec_uart *udev = to_switchtec_uart(dev);
258  uint32_t addr = (uint32_t)(src - (void __gas *)dev->gas_map);
259  uint8_t *ptr = dest;
260  uint8_t cal;
261  char gas_rd_rtn[4096];
262 
263  for (i = 0; i < RETRY_NUM; i++) {
264  ret = send_cmd(udev->fd, "gasrd -c -s 0x%x %zu\r", 0, addr, n);
265  if (ret)
266  continue;
267 
268  ret = read_resp_line(udev->fd, gas_rd_rtn);
269  if (ret)
270  continue;
271 
272  /* case 3 */
273  if (strstr(gas_rd_rtn, "No access beyond the Total GAS Section")){
274  memset(dest, 0xff, n);
275  break;
276  }
277  /* case 2 */
278  if (strchr(gas_rd_rtn, ',')) {
279  if (sscanf(gas_rd_rtn,
280  "%*[^<]<0x%x> [%d Byte]%*[^,],%*[^:]: 0x"
281  "%x%*[^:]:",
282  &raddr, &rnum, &rcrc) != 3)
283  continue;
284  } else {
285  /* case 1 */
286  if (sscanf(gas_rd_rtn,
287  "%*[^<]<0x%x> [%d Byte]%*[^:]: 0x%x%*[^:]:",
288  &raddr, &rnum, &rcrc) != 3)
289  continue;
290  }
291 
292  if ((raddr != addr) || (rnum != n))
293  continue;
294 
295  pos = strchr(gas_rd_rtn, ']');
296  if (strchr(gas_rd_rtn, ','))
297  pos = strchr(gas_rd_rtn, ',') + strlen("not hit");
298  else
299  pos += 2;
300 
301  for (j = 0; j < n; j++)
302  *ptr++ = strtol(pos, &pos, 16);
303 
304  addr = htobe32(addr);
305  cal = crc8((uint8_t *)&addr, sizeof(addr), 0, true);
306  cal = crc8(dest, n, cal, false);
307  if (cal == rcrc)
308  break;
309  }
310 
311  if (i == RETRY_NUM)
312  raise(SIGBUS);
313 }
314 
315 static void uart_memcpy_from_gas(struct switchtec_dev *dev, void *dest,
316  const void __gas *src, size_t n)
317 {
318  ssize_t cnt;
319 
320  while(n) {
321  cnt = n > UART_MAX_READ_BYTES? UART_MAX_READ_BYTES : n;
322  uart_gas_read(dev, dest, src, cnt);
323  dest += cnt;
324  src += cnt;
325  n -= cnt;
326  }
327 }
328 
329 #define create_gas_read(type, suffix) \
330  static type uart_gas_read ## suffix(struct switchtec_dev *dev, \
331  type __gas *addr) \
332  { \
333  type ret; \
334  uart_gas_read(dev, &ret, addr, sizeof(ret)); \
335  return ret; \
336  }
337 create_gas_read(uint8_t, 8);
338 create_gas_read(uint16_t, 16);
339 create_gas_read(uint32_t, 32);
340 create_gas_read(uint64_t, 64);
341 
342 static void uart_gas_write(struct switchtec_dev *dev, void __gas *dest,
343  const void *src, size_t n)
344 {
345  int ret;
346  int i;
347  char gas_wr_rtn[4096];
348  uint32_t crc;
349  uint32_t cal, exp;
350  struct switchtec_uart *udev = to_switchtec_uart(dev);
351  uint32_t addr = (uint32_t)(dest - (void __gas *)dev->gas_map);
352 
353  addr = htobe32(addr);
354  crc = crc8((uint8_t *)&addr, sizeof(addr), 0, true);
355  for (i = n; i > 0; i--)
356  crc = crc8((uint8_t *)src + i - 1, sizeof(uint8_t), crc, false);
357 
358  addr = htobe32(addr);
359  for (i = 0; i < RETRY_NUM; i++) {
360  ret = send_cmd(udev->fd, "gaswr -c -s 0x%x 0x",
361  n, src, crc, addr);
362  if (ret)
363  continue;
364 
365  ret = read_resp_line(udev->fd, gas_wr_rtn);
366  if (ret)
367  continue;
368 
369  /* case 4 */
370  if (strstr(gas_wr_rtn, "Error with gas_reg_write()"))
371  break;
372  /* case 2 */
373  if (strchr(gas_wr_rtn, ',')) {
374  if (sscanf(gas_wr_rtn, "%*[^,],%*[^:]: [0x%x/0x%x]%*[^:]:",
375  &cal, &exp) != 2)
376  continue;
377  } else {
378  /* case 1 and case 3 */
379  if (sscanf(gas_wr_rtn, "%*[^:]: [0x%x/0x%x]%*[^:]:",
380  &cal, &exp) != 2)
381  continue;
382  }
383  if ((exp == cal) && (cal == crc))
384  break;
385  }
386 
387  if (i == RETRY_NUM)
388  raise(SIGBUS);
389 }
390 
391 static void uart_memcpy_to_gas(struct switchtec_dev *dev, void __gas *dest,
392  const void *src, size_t n)
393 {
394  size_t cnt;
395 
396  while(n){
397  cnt = n > UART_MAX_WRITE_BYTES ? UART_MAX_WRITE_BYTES : n;
398  uart_gas_write(dev, dest, src, cnt);
399  dest += cnt;
400  src += cnt;
401  n -= cnt;
402  }
403 }
404 
405 #define create_gas_write(type, suffix) \
406  static void uart_gas_write ## suffix(struct switchtec_dev *dev, \
407  type val, type __gas *addr) \
408  { \
409  uart_gas_write(dev, addr, &val, sizeof(type)); \
410  }
411 
412 create_gas_write(uint8_t, 8);
413 create_gas_write(uint16_t, 16);
414 create_gas_write(uint32_t, 32);
415 create_gas_write(uint64_t, 64);
416 
417 static ssize_t uart_write_from_gas(struct switchtec_dev *dev, int fd,
418  const void __gas *src, size_t n)
419 {
420  ssize_t ret;
421  void *buf;
422 
423  buf = malloc(n);
424 
425  uart_memcpy_from_gas(dev, buf, src, n);
426  ret = write(fd, buf, n);
427 
428  free(buf);
429 
430  return ret;
431 }
432 
433 static const struct switchtec_ops uart_ops = {
434  .flags = SWITCHTEC_OPS_FLAG_NO_MFG,
435 
436  .close = uart_close,
437  .gas_map = uart_gas_map,
438 
439  .cmd = gasop_cmd,
440  .get_device_id = gasop_get_device_id,
441  .get_fw_version = gasop_get_fw_version,
442  .pff_to_port = gasop_pff_to_port,
443  .port_to_pff = gasop_port_to_pff,
444  .flash_part = gasop_flash_part,
445  .event_summary = gasop_event_summary,
446  .event_ctl = gasop_event_ctl,
447  .event_wait_for = gasop_event_wait_for,
448 
449  .gas_read8 = uart_gas_read8,
450  .gas_read16 = uart_gas_read16,
451  .gas_read32 = uart_gas_read32,
452  .gas_read64 = uart_gas_read64,
453  .gas_write8 = uart_gas_write8,
454  .gas_write16 = uart_gas_write16,
455  .gas_write32 = uart_gas_write32,
456  .gas_write32_no_retry = uart_gas_write32,
457  .gas_write64 = uart_gas_write64,
458 
459  .memcpy_to_gas = uart_memcpy_to_gas,
460  .memcpy_from_gas = uart_memcpy_from_gas,
461  .write_from_gas = uart_write_from_gas,
462 };
463 
464 static int set_uart_attribs(int fd, int speed, int parity)
465 {
466  int ret;
467  struct termios uart_attribs;
468  memset(&uart_attribs, 0, sizeof(uart_attribs));
469 
470  ret = tcgetattr(fd, &uart_attribs);
471  if (ret)
472  return -1;
473 
474  cfsetospeed(&uart_attribs, speed);
475  cfsetispeed(&uart_attribs, speed);
476 
477  uart_attribs.c_iflag &= ~IGNBRK;
478  uart_attribs.c_iflag &= ~(IXON | IXOFF | IXANY);
479  uart_attribs.c_lflag = 0;
480  uart_attribs.c_oflag = 0;
481  uart_attribs.c_cflag = (uart_attribs.c_cflag & ~CSIZE) | CS8;
482  uart_attribs.c_cflag |= (CLOCAL | CREAD);
483  uart_attribs.c_cflag &= ~(PARENB | PARODD);
484  uart_attribs.c_cflag |= parity;
485  uart_attribs.c_cflag &= ~CSTOPB;
486  uart_attribs.c_cflag &= ~CRTSCTS;
487  uart_attribs.c_cc[VMIN] = 0;
488  uart_attribs.c_cc[VTIME] = 50;
489 
490  ret = tcsetattr(fd, TCSANOW, &uart_attribs);
491  if (ret)
492  return -1;
493 
494  return 0;
495 }
496 
497 struct switchtec_dev *switchtec_open_uart(int fd)
498 {
499  int ret;
500  struct switchtec_uart *udev;
501 
502  udev = malloc(sizeof(*udev));
503  if (!udev)
504  return NULL;
505 
506  udev->fd = fd;
507  if (udev->fd < 0)
508  goto err_free;
509 
510  ret = flock(udev->fd, LOCK_EX | LOCK_NB);
511  if (ret)
512  goto err_close_free;
513 
514  ret = set_uart_attribs(udev->fd, SWITCHTEC_UART_BAUDRATE, 0);
515  if (ret)
516  goto err_close_free;
517 
518  ret = cli_control(&udev->dev, "pscdbg 0 all\r");
519  if (ret)
520  goto err_close_free;
521 
522  ret = cli_control(&udev->dev, "echo 0\r");
523  if (ret)
524  goto err_close_free;
525 
526  if (map_gas(&udev->dev))
527  goto err_close_free;
528 
529  udev->dev.ops = &uart_ops;
530  gasop_set_partition_info(&udev->dev);
531  return &udev->dev;
532 
533 err_close_free:
534  close(udev->fd);
535 
536 err_free:
537  free(udev);
538  return NULL;
539 }
540 
541 #endif
542 
__gas struct switchtec_gas * gasptr_t
Shortform for a pointer to the GAS register space.
Definition: switchtec.h:77
Main Switchtec header.
struct switchtec_dev * switchtec_open_uart(int fd)
Open a switchtec device behind a uart device.