Switchtec Userspace  PROJECT_NUMBER = PROJECT_NUMBER=PROJECT_NUMBER = 2.2
linux-i2c.c
1 /*
2  * Microsemi Switchtec(tm) PCIe Management Library
3  * Copyright (c) 2017, 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 <sys/sysmacros.h>
37 #include <fcntl.h>
38 #include <unistd.h>
39 #include <errno.h>
40 #include <signal.h>
41 #include <stddef.h>
42 #include <assert.h>
43 #include <string.h>
44 
45 #include <linux/i2c.h>
46 #include <linux/i2c-dev.h>
47 
48 struct switchtec_i2c {
49  struct switchtec_dev dev;
50  int fd;
51  int i2c_addr;
52  uint8_t tag;
53 };
54 
55 #define CMD_GET_CAP 0xE0
56 #define CMD_GAS_WRITE 0xEA
57 #define CMD_GET_WRITE_STATUS 0xE2
58 #define CMD_GAS_WRITE_WITH_STATUS 0xE8
59 #define CMD_GAS_READ 0xE9
60 
61 #define MAX_RETRY_COUNT 100
62 #define MAX_STATUS_GET_RETRY 50
63 #define PEC_BYTE_COUNT 1
64 #define TWI_ENHANCED_MODE 0x80
65 #define GAS_TWI_MRPC_ERR 0x20
66 #define DATA_TAIL_BYTE_COUNT 2
67 
68 #define to_switchtec_i2c(d) \
69  ((struct switchtec_i2c *) \
70  ((char *)d - offsetof(struct switchtec_i2c, dev)))
71 
72 static uint8_t get_tag(struct switchtec_i2c *idev)
73 {
74  /* Valid tag is 0x01 ~ 0xff */
75  idev->tag++;
76  if (!idev->tag)
77  idev->tag = 1;
78  return idev->tag;
79 }
80 
81 static uint8_t i2c_msg_pec(struct i2c_msg *msg, uint8_t byte_count,
82  uint8_t oldchksum, bool init)
83 {
84  /* This function just supports 7-bits I2C address */
85  uint8_t addr = (msg->addr << 1) | msg->flags;
86  uint8_t pec = crc8(&addr, 1, oldchksum, init);
87  return crc8(msg->buf, byte_count, pec, false);
88 }
89 
90 static int dev_to_sysfs_path(struct switchtec_i2c *idev, const char *suffix,
91  char *buf, size_t buflen)
92 {
93  int ret;
94  struct stat stat;
95 
96  ret = fstat(idev->fd, &stat);
97  if (ret < 0)
98  return ret;
99 
100  snprintf(buf, buflen,
101  "/sys/dev/char/%d:%d/%s",
102  major(stat.st_rdev), minor(stat.st_rdev), suffix);
103 
104  return 0;
105 }
106 
107 static int check_i2c_device_supported(struct switchtec_i2c *idev)
108 {
109  unsigned long funcs;
110  int ret;
111 
112  ret = ioctl(idev->fd, I2C_FUNCS, &funcs);
113  if (ret < 0)
114  return ret;
115 
116  if (!(funcs & I2C_FUNC_I2C)) {
117  errno = ENOPROTOOPT;
118  return -errno;
119  }
120 
121  return 0;
122 }
123 
124 static int check_i2c_device(struct switchtec_i2c *idev)
125 {
126  int ret;
127  char syspath[PATH_MAX];
128 
129  ret = dev_to_sysfs_path(idev, "device/i2c-dev", syspath,
130  sizeof(syspath));
131  if (ret)
132  return ret;
133 
134  ret = access(syspath, F_OK);
135  if (ret)
136  errno = ENOTTY;
137 
138  return check_i2c_device_supported(idev);
139 }
140 
141 static int i2c_set_addr(struct switchtec_i2c *idev, int i2c_addr)
142 {
143  idev->i2c_addr = i2c_addr;
144 
145  return ioctl(idev->fd, I2C_SLAVE, i2c_addr);
146 }
147 
148 static int i2c_set_timeout(struct switchtec_i2c *idev, int time)
149 {
150  return ioctl(idev->fd, I2C_TIMEOUT, time);
151 }
152 
153 #ifdef __CHECKER__
154 #define __force __attribute__((force))
155 #else
156 #define __force
157 #endif
158 
159 static void i2c_close(struct switchtec_dev *dev)
160 {
161  struct switchtec_i2c *idev = to_switchtec_i2c(dev);
162 
163  if (dev->gas_map)
164  munmap((void __force *)dev->gas_map, dev->gas_map_size);
165 
166  close(idev->fd);
167  free(idev);
168 }
169 
170 static int map_gas(struct switchtec_dev *dev)
171 {
172  void *addr;
173  dev->gas_map_size = 4 << 20;
174 
175  /*
176  * Ensure that if someone tries to do something stupid,
177  * like dereference the GAS directly we fail without
178  * trashing random memory somewhere. We do this by
179  * allocating an innaccessible range in the virtual
180  * address space and use that as the GAS address which
181  * will be subtracted by subsequent operations
182  */
183 
184  addr = mmap(NULL, dev->gas_map_size, PROT_NONE,
185  MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
186  if (addr == MAP_FAILED)
187  return -1;
188 
189  dev->gas_map = (gasptr_t __force)addr;
190 
191  return 0;
192 }
193 
194 #undef __force
195 
196 static gasptr_t i2c_gas_map(struct switchtec_dev *dev, int writeable,
197  size_t *map_size)
198 {
199  if (map_size)
200  *map_size = dev->gas_map_size;
201 
202  return dev->gas_map;
203 }
204 
205 static uint8_t i2c_gas_cap_get(struct switchtec_dev *dev)
206 {
207  int ret;
208  struct switchtec_i2c *idev = to_switchtec_i2c(dev);
209 
210  struct i2c_msg msgs[2];
211  struct i2c_rdwr_ioctl_data rwdata = {
212  .msgs = msgs,
213  .nmsgs = 2,
214  };
215 
216  uint8_t command_code = CMD_GET_CAP;
217  uint8_t rx_buf[2];
218  uint8_t msg_0_pec, pec;
219  uint8_t retry_count = 0;
220 
221  msgs[0].addr = msgs[1].addr = idev->i2c_addr;
222  msgs[0].flags = 0;
223  msgs[0].len = 1;
224  msgs[0].buf = &command_code;
225 
226  msgs[1].flags = I2C_M_RD;
227  msgs[1].len = 2;
228  msgs[1].buf = rx_buf;
229 
230  do {
231  ret = ioctl(idev->fd, I2C_RDWR, &rwdata);
232  if (ret < 0)
233  goto i2c_ioctl_fail;
234 
235  msg_0_pec = i2c_msg_pec(&msgs[0], msgs[0].len, 0, true);
236  pec = i2c_msg_pec(&msgs[1], msgs[1].len - PEC_BYTE_COUNT,
237  msg_0_pec, false);
238  if (rx_buf[1] == pec)
239  break;
240 
241  retry_count++;
242  } while(retry_count < MAX_RETRY_COUNT);
243 
244  /* return capability */
245  if (retry_count == MAX_RETRY_COUNT)
246  return -1;
247  else
248  return (rx_buf[0] & TWI_ENHANCED_MODE);
249 
250 i2c_ioctl_fail:
251  return -1;
252 }
253 
254 /*
255  * One I2C transaction can write a maximum of 26 bytes, but it is better to
256  * write the GAS with dword.
257  */
258 #define I2C_MAX_WRITE 24
259 /*
260  * One I2C transaction can read a maximum of 27 bytes, but it is better to
261  * read GAS with dword.
262  */
263 #define I2C_MAX_READ 24
264 
265 static uint8_t i2c_gas_data_write(struct switchtec_dev *dev, void __gas *dest,
266  const void *src, size_t n, uint8_t tag)
267 {
268  int ret;
269  struct switchtec_i2c *idev = to_switchtec_i2c(dev);
270 
271  struct i2c_msg msg;
272  struct i2c_rdwr_ioctl_data wdata = {
273  .msgs = &msg,
274  .nmsgs = 1,
275  };
276 
277  struct {
278  uint8_t command_code;
279  uint8_t byte_count;
280  uint8_t tag;
281  uint32_t offset;
282  uint8_t data[];
283  } __attribute__((packed)) *i2c_data;
284 
285  uint32_t gas_addr = (uint32_t)(dest - (void __gas *)dev->gas_map);
286  assert(n <= I2C_MAX_WRITE);
287 
288  /* PEC is the last byte */
289  i2c_data = malloc(sizeof(*i2c_data) + n + PEC_BYTE_COUNT);
290 
291  i2c_data->command_code = CMD_GAS_WRITE;
292  i2c_data->byte_count = (sizeof(i2c_data->tag)
293  + sizeof(i2c_data->offset)
294  + n);
295  i2c_data->tag = tag;
296 
297  gas_addr = htobe32(gas_addr);
298  i2c_data->offset = gas_addr;
299  memcpy(&i2c_data->data, src, n);
300  msg.addr = idev->i2c_addr;
301  msg.flags = 0;
302  msg.len = sizeof(*i2c_data) + n + PEC_BYTE_COUNT;
303  msg.buf = (uint8_t *)i2c_data;
304 
305  i2c_data->data[n] = i2c_msg_pec(&msg, msg.len - PEC_BYTE_COUNT, 0,
306  true);
307 
308  ret = ioctl(idev->fd, I2C_RDWR, &wdata);
309  if (ret < 0)
310  goto i2c_write_fail;
311 
312  free(i2c_data);
313  return 0;
314 
315 i2c_write_fail:
316  free(i2c_data);
317  return -1;
318 }
319 
320 static uint8_t i2c_gas_write_status_get(struct switchtec_dev *dev,
321  uint8_t tag)
322 {
323  int ret;
324  struct switchtec_i2c *idev = to_switchtec_i2c(dev);
325  struct i2c_msg msgs[2];
326  struct i2c_rdwr_ioctl_data rwdata = {
327  .msgs = msgs,
328  .nmsgs = 2,
329  };
330 
331  uint8_t command_code = CMD_GET_WRITE_STATUS;
332  uint8_t rx_buf[3];
333 
334  uint8_t msg_0_pec, pec;
335  uint8_t retry_count = 0;
336 
337  msgs[0].addr = msgs[1].addr = idev->i2c_addr;
338  msgs[0].flags = 0;
339  msgs[0].len = 1;
340  msgs[0].buf = &command_code;
341 
342  msgs[1].flags = I2C_M_RD;
343  msgs[1].len = 3;
344  msgs[1].buf = rx_buf;
345 
346  do {
347  ret = ioctl(idev->fd, I2C_RDWR, &rwdata);
348  if (ret < 0) {
349  retry_count++;
350  /* Delay is typically only needed for BL1/2 phase */
351  usleep(2000);
352  continue;
353  }
354 
355  msg_0_pec = i2c_msg_pec(&msgs[0], msgs[0].len, 0, true);
356  pec = i2c_msg_pec(&msgs[1], msgs[1].len - PEC_BYTE_COUNT,
357  msg_0_pec, false);
358  if (rx_buf[0] == tag && rx_buf[2] == pec &&
359  (rx_buf[1] == 0 || rx_buf[1] == GAS_TWI_MRPC_ERR))
360  return rx_buf[1];
361 
362  /* Extra delay is typically only needed for BL1/2 phase */
363  usleep(2000);
364  retry_count++;
365  } while(retry_count < MAX_STATUS_GET_RETRY);
366 
367  return -1;
368 }
369 
370 static void i2c_gas_write(struct switchtec_dev *dev, void __gas *dest,
371  const void *src, size_t n)
372 {
373  struct switchtec_i2c *idev = to_switchtec_i2c(dev);
374  uint8_t tag;
375  uint8_t status;
376  uint8_t retry_count = 0;
377 
378  do {
379  tag = get_tag(idev);
380  i2c_gas_data_write(dev, dest, src, n, tag);
381  status = i2c_gas_write_status_get(dev, tag);
382  if (status == 0 || status == GAS_TWI_MRPC_ERR)
383  break;
384 
385  /* Extra delay is typically only needed for BL1/2 phase */
386  usleep(1000);
387  retry_count++;
388  } while (retry_count < MAX_RETRY_COUNT);
389 
390  if (retry_count == MAX_RETRY_COUNT)
391  raise(SIGBUS);
392 }
393 
394 static void i2c_gas_write_no_retry(struct switchtec_dev *dev, void __gas *dest,
395  const void *src, size_t n)
396 {
397  struct switchtec_i2c *idev = to_switchtec_i2c(dev);
398  uint8_t tag;
399  uint8_t status;
400 
401  tag = get_tag(idev);
402  i2c_gas_data_write(dev, dest, src, n, tag);
403  status = i2c_gas_write_status_get(dev, tag);
404  if (status == 0 || status == GAS_TWI_MRPC_ERR)
405  return;
406 
407  raise(SIGBUS);
408 }
409 
410 static void i2c_memcpy_to_gas(struct switchtec_dev *dev, void __gas *dest,
411  const void *src, size_t n)
412 {
413  size_t cnt;
414 
415  while (n) {
416  cnt = n > I2C_MAX_WRITE ? I2C_MAX_WRITE : n;
417  i2c_gas_write(dev, dest, src, cnt);
418 
419  dest += cnt;
420  src += cnt;
421  n -= cnt;
422  }
423 }
424 
425 static uint8_t i2c_gas_data_read(struct switchtec_dev *dev, void *dest,
426  const void __gas *src, size_t n)
427 {
428  int ret;
429  int pec_index, status_index;
430  uint8_t msg_0_pec, pec;
431  uint8_t retry_count = 0;
432 
433  struct switchtec_i2c *idev = to_switchtec_i2c(dev);
434  uint32_t gas_addr = (uint32_t)(src - (void __gas *)dev->gas_map);
435  uint8_t status;
436 
437  struct i2c_msg msgs[2];
438  struct i2c_rdwr_ioctl_data rwdata = {
439  .msgs = msgs,
440  .nmsgs = 2,
441  };
442 
443  struct {
444  uint8_t command_code;
445  uint8_t byte_count;
446  uint32_t offset;
447  uint8_t data_length;
448  } __attribute__((packed)) *read_command;
449 
450  struct {
451  uint8_t byte_count;
452  /* tail is one byte status and one byte pec */
453  uint8_t data_and_tail[];
454  }*read_response;
455 
456  read_command = malloc(sizeof(*read_command));
457  read_response = malloc(sizeof(*read_response) + n \
458  + DATA_TAIL_BYTE_COUNT);
459 
460  msgs[0].addr = msgs[1].addr = idev->i2c_addr;
461  msgs[0].flags = 0;
462  msgs[0].len = sizeof(*read_command);
463 
464  read_command->command_code = CMD_GAS_READ;
465  read_command->byte_count = sizeof(read_command->offset) \
466  + sizeof(read_command->data_length);
467  gas_addr = htobe32(gas_addr);
468  read_command->offset = gas_addr;
469  read_command->data_length = n;
470  msgs[0].buf = (uint8_t *)read_command;
471 
472  msgs[1].flags = I2C_M_RD;
473  msgs[1].len = sizeof(read_response->byte_count) + n + \
474  DATA_TAIL_BYTE_COUNT;
475  msgs[1].buf = (uint8_t *)read_response;
476 
477  do {
478  ret = ioctl(idev->fd, I2C_RDWR, &rwdata);
479  if (ret < 0)
480  goto i2c_read_fail;
481 
482  msg_0_pec = i2c_msg_pec(&msgs[0], msgs[0].len, 0, true);
483  pec = i2c_msg_pec(&msgs[1], msgs[1].len - PEC_BYTE_COUNT, \
484  msg_0_pec, false);
485  pec_index = msgs[1].len - sizeof(read_response->byte_count) \
486  - PEC_BYTE_COUNT;
487  if (read_response->data_and_tail[ pec_index ] == pec)
488  break;
489 
490  retry_count++;
491  } while(retry_count < MAX_RETRY_COUNT);
492 
493  if (retry_count == MAX_RETRY_COUNT)
494  goto i2c_read_fail;
495 
496  memcpy(dest, read_response->data_and_tail, n);
497  status_index = msgs[1].len - sizeof(read_response->byte_count) \
498  - DATA_TAIL_BYTE_COUNT;
499  status = read_response->data_and_tail[ status_index ];
500 
501  free(read_command);
502  free(read_response);
503  return status;
504 
505 i2c_read_fail:
506  free(read_command);
507  free(read_response);
508  return -1;
509 }
510 
511 static void i2c_gas_read(struct switchtec_dev *dev, void *dest,
512  const void __gas *src, size_t n)
513 {
514  uint8_t status;
515  uint8_t retry_count = 0;
516 
517  do {
518  status = i2c_gas_data_read(dev, dest, src, n);
519  if (status == 0 || status == GAS_TWI_MRPC_ERR)
520  break;
521  retry_count++;
522  }while(retry_count < MAX_RETRY_COUNT);
523 
524  if (retry_count == MAX_RETRY_COUNT)
525  raise(SIGBUS);
526 }
527 
528 static void i2c_memcpy_from_gas(struct switchtec_dev *dev, void *dest,
529  const void __gas *src, size_t n)
530 {
531  size_t cnt;
532 
533  while (n) {
534  cnt = n > I2C_MAX_READ ? I2C_MAX_READ : n;
535  i2c_gas_read(dev, dest, src, cnt);
536 
537  dest += cnt;
538  src += cnt;
539  n -= cnt;
540  }
541 }
542 
543 static ssize_t i2c_write_from_gas(struct switchtec_dev *dev, int fd,
544  const void __gas *src, size_t n)
545 {
546  ssize_t ret;
547  void *buf;
548 
549  buf = malloc(n);
550 
551  i2c_memcpy_from_gas(dev, buf, src, n);
552 
553  ret = write(fd, buf, n);
554 
555  free(buf);
556 
557  return ret;
558 }
559 
560 #define create_gas_read(type, suffix) \
561  static type i2c_gas_read ## suffix(struct switchtec_dev *dev, \
562  type __gas *addr) \
563  { \
564  type ret; \
565  i2c_memcpy_from_gas(dev, &ret, addr, sizeof(ret)); \
566  return ret; \
567  }
568 
569 create_gas_read(uint8_t, 8);
570 create_gas_read(uint16_t, 16);
571 create_gas_read(uint32_t, 32);
572 create_gas_read(uint64_t, 64);
573 
574 static void i2c_gas_write8(struct switchtec_dev *dev, uint8_t val,
575  uint8_t __gas *addr)
576 {
577  i2c_gas_write(dev, addr, &val, sizeof(uint8_t));
578 }
579 
580 static void i2c_gas_write16(struct switchtec_dev *dev, uint16_t val,
581  uint16_t __gas *addr)
582 {
583  i2c_gas_write(dev, addr, &val, sizeof(uint16_t));
584 }
585 
586 static void i2c_gas_write32(struct switchtec_dev *dev, uint32_t val,
587  uint32_t __gas *addr)
588 {
589  i2c_gas_write(dev, addr, &val, sizeof(uint32_t));
590 }
591 
592 static void i2c_gas_write32_no_retry(struct switchtec_dev *dev, uint32_t val,
593  uint32_t __gas *addr)
594 {
595  i2c_gas_write_no_retry(dev, addr, &val, sizeof(uint32_t));
596 }
597 
598 static void i2c_gas_write64(struct switchtec_dev *dev, uint64_t val,
599  uint64_t __gas *addr)
600 {
601  i2c_gas_write(dev, addr, &val, sizeof(uint64_t));
602 }
603 
604 static const struct switchtec_ops i2c_ops = {
605  .close = i2c_close,
606  .gas_map = i2c_gas_map,
607 
608  .cmd = gasop_cmd,
609  .get_device_id = gasop_get_device_id,
610  .get_fw_version = gasop_get_fw_version,
611  .pff_to_port = gasop_pff_to_port,
612  .port_to_pff = gasop_port_to_pff,
613  .flash_part = gasop_flash_part,
614  .event_summary = gasop_event_summary,
615  .event_ctl = gasop_event_ctl,
616  .event_wait_for = gasop_event_wait_for,
617 
618  .gas_read8 = i2c_gas_read8,
619  .gas_read16 = i2c_gas_read16,
620  .gas_read32 = i2c_gas_read32,
621  .gas_read64 = i2c_gas_read64,
622  .gas_write8 = i2c_gas_write8,
623  .gas_write16 = i2c_gas_write16,
624  .gas_write32 = i2c_gas_write32,
625  .gas_write32_no_retry = i2c_gas_write32_no_retry,
626  .gas_write64 = i2c_gas_write64,
627  .memcpy_to_gas = i2c_memcpy_to_gas,
628  .memcpy_from_gas = i2c_memcpy_from_gas,
629  .write_from_gas = i2c_write_from_gas,
630 };
631 
632 struct switchtec_dev *switchtec_open_i2c(const char *path, int i2c_addr)
633 {
634  struct switchtec_i2c *idev;
635 
636  idev = malloc(sizeof(*idev));
637  if (!idev)
638  return NULL;
639 
640  idev->fd = open(path, O_RDWR | O_CLOEXEC);
641  if (idev->fd < 0)
642  goto err_free;
643 
644  if (check_i2c_device(idev))
645  goto err_close_free;
646 
647  if (i2c_set_addr(idev, i2c_addr))
648  goto err_close_free;
649 
650  if (i2c_set_timeout(idev, 10))
651  goto err_close_free;
652 
653  if (i2c_gas_cap_get(&idev->dev) != TWI_ENHANCED_MODE)
654  goto err_close_free;
655 
656  if (map_gas(&idev->dev))
657  goto err_close_free;
658 
659  idev->dev.ops = &i2c_ops;
660 
661  gasop_set_partition_info(&idev->dev);
662 
663  return &idev->dev;
664 
665 err_close_free:
666  close(idev->fd);
667 err_free:
668  free(idev);
669  return NULL;
670 }
671 
672 struct switchtec_dev *switchtec_open_i2c_by_adapter(int adapter, int i2c_addr)
673 {
674  char path[PATH_MAX];
675 
676  sprintf(path, "/dev/i2c-%d", adapter);
677 
678  return switchtec_open_i2c(path, i2c_addr);
679 }
680 
681 #endif
__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_i2c(const char *path, int i2c_addr)
Open a switchtec device behind an I2C device.