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