Switchtec Userspace PROJECT_NUMBER = 4.2
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
292 i2c_data->command_code = CMD_GAS_WRITE;
293 i2c_data->byte_count = (sizeof(i2c_data->tag)
294 + sizeof(i2c_data->offset)
295 + n);
296 i2c_data->tag = tag;
297
298 gas_addr = htobe32(gas_addr);
299 i2c_data->offset = gas_addr;
300 memcpy(&i2c_data->data, src, n);
301 msg.addr = idev->i2c_addr;
302 msg.flags = 0;
303 msg.len = sizeof(*i2c_data) + n + PEC_BYTE_COUNT;
304 msg.buf = (uint8_t *)i2c_data;
305
306 i2c_data->data[n] = i2c_msg_pec(&msg, msg.len - PEC_BYTE_COUNT, 0,
307 true);
308
309 ret = ioctl(idev->fd, I2C_RDWR, &wdata);
310 if (ret < 0)
311 goto i2c_write_fail;
312
313 free(i2c_data);
314 return 0;
315
316i2c_write_fail:
317 free(i2c_data);
318 return -1;
319}
320
321static uint8_t i2c_gas_write_status_get(struct switchtec_dev *dev,
322 uint8_t tag)
323{
324 int ret;
325 struct switchtec_i2c *idev = to_switchtec_i2c(dev);
326 struct i2c_msg msgs[2];
327 struct i2c_rdwr_ioctl_data rwdata = {
328 .msgs = msgs,
329 .nmsgs = 2,
330 };
331
332 uint8_t command_code = CMD_GET_WRITE_STATUS;
333 uint8_t rx_buf[3];
334
335 uint8_t msg_0_pec, pec;
336 uint8_t retry_count = 0;
337
338 msgs[0].addr = msgs[1].addr = idev->i2c_addr;
339 msgs[0].flags = 0;
340 msgs[0].len = 1;
341 msgs[0].buf = &command_code;
342
343 msgs[1].flags = I2C_M_RD;
344 msgs[1].len = 3;
345 msgs[1].buf = rx_buf;
346
347 do {
348 ret = ioctl(idev->fd, I2C_RDWR, &rwdata);
349 if (ret < 0) {
350 retry_count++;
351 /* Delay is typically only needed for BL1/2 phase */
352 usleep(2000);
353 continue;
354 }
355
356 msg_0_pec = i2c_msg_pec(&msgs[0], msgs[0].len, 0, true);
357 pec = i2c_msg_pec(&msgs[1], msgs[1].len - PEC_BYTE_COUNT,
358 msg_0_pec, false);
359 if (rx_buf[0] == tag && rx_buf[2] == pec &&
360 (rx_buf[1] == 0 || rx_buf[1] == GAS_TWI_MRPC_ERR))
361 return rx_buf[1];
362
363 /* Extra delay is typically only needed for BL1/2 phase */
364 usleep(2000);
365 retry_count++;
366 } while(retry_count < MAX_STATUS_GET_RETRY);
367
368 return -1;
369}
370
371static void i2c_gas_write(struct switchtec_dev *dev, void __gas *dest,
372 const void *src, size_t n)
373{
374 struct switchtec_i2c *idev = to_switchtec_i2c(dev);
375 uint8_t tag;
376 uint8_t status;
377 uint8_t retry_count = 0;
378
379 do {
380 tag = get_tag(idev);
381 i2c_gas_data_write(dev, dest, src, n, tag);
382 status = i2c_gas_write_status_get(dev, tag);
383 if (status == 0 || status == GAS_TWI_MRPC_ERR)
384 break;
385
386 /* Extra delay is typically only needed for BL1/2 phase */
387 usleep(1000);
388 retry_count++;
389 } while (retry_count < MAX_RETRY_COUNT);
390
391 if (retry_count == MAX_RETRY_COUNT)
392 raise(SIGBUS);
393}
394
395static void i2c_gas_write_no_retry(struct switchtec_dev *dev, void __gas *dest,
396 const void *src, size_t n)
397{
398 struct switchtec_i2c *idev = to_switchtec_i2c(dev);
399 uint8_t tag;
400 uint8_t status;
401 uint8_t retry_count = 0;
402
403 tag = get_tag(idev);
404 i2c_gas_data_write(dev, dest, src, n, tag);
405 do {
406 status = i2c_gas_write_status_get(dev, tag);
407 if (status == 0 || status == GAS_TWI_MRPC_ERR)
408 return;
409
410 /* Extra delay is typically only needed for BL1/2 phase */
411 usleep(1000);
412 retry_count++;
413 } while (retry_count < MAX_RETRY_COUNT);
414
415 raise(SIGBUS);
416}
417
418static void i2c_memcpy_to_gas(struct switchtec_dev *dev, void __gas *dest,
419 const void *src, size_t n)
420{
421 size_t cnt;
422
423 while (n) {
424 cnt = n > I2C_MAX_WRITE ? I2C_MAX_WRITE : n;
425 i2c_gas_write(dev, dest, src, cnt);
426
427 dest += cnt;
428 src += cnt;
429 n -= cnt;
430 }
431}
432
433static uint8_t i2c_gas_data_read(struct switchtec_dev *dev, void *dest,
434 const void __gas *src, size_t n)
435{
436 int ret;
437 int pec_index, status_index;
438 uint8_t msg_0_pec, pec;
439 uint8_t retry_count = 0;
440
441 struct switchtec_i2c *idev = to_switchtec_i2c(dev);
442 uint32_t gas_addr = (uint32_t)(src - (void __gas *)dev->gas_map);
443 uint8_t status;
444
445 struct i2c_msg msgs[2];
446 struct i2c_rdwr_ioctl_data rwdata = {
447 .msgs = msgs,
448 .nmsgs = 2,
449 };
450
451 struct {
452 uint8_t command_code;
453 uint8_t byte_count;
454 uint32_t offset;
455 uint8_t data_length;
456 } __attribute__((packed)) *read_command;
457
458 struct {
459 uint8_t byte_count;
460 /* tail is one byte status and one byte pec */
461 uint8_t data_and_tail[];
462 }*read_response;
463
464 read_command = malloc(sizeof(*read_command));
465 read_response = malloc(sizeof(*read_response) + n \
466 + DATA_TAIL_BYTE_COUNT);
467
468 msgs[0].addr = msgs[1].addr = idev->i2c_addr;
469 msgs[0].flags = 0;
470 msgs[0].len = sizeof(*read_command);
471
472 read_command->command_code = CMD_GAS_READ;
473 read_command->byte_count = sizeof(read_command->offset) \
474 + sizeof(read_command->data_length);
475 gas_addr = htobe32(gas_addr);
476 read_command->offset = gas_addr;
477 read_command->data_length = n;
478 msgs[0].buf = (uint8_t *)read_command;
479
480 msgs[1].flags = I2C_M_RD;
481 msgs[1].len = sizeof(read_response->byte_count) + n + \
482 DATA_TAIL_BYTE_COUNT;
483 msgs[1].buf = (uint8_t *)read_response;
484
485 do {
486 ret = ioctl(idev->fd, I2C_RDWR, &rwdata);
487 if (ret < 0)
488 goto i2c_read_fail;
489
490 msg_0_pec = i2c_msg_pec(&msgs[0], msgs[0].len, 0, true);
491 pec = i2c_msg_pec(&msgs[1], msgs[1].len - PEC_BYTE_COUNT, \
492 msg_0_pec, false);
493 pec_index = msgs[1].len - sizeof(read_response->byte_count) \
494 - PEC_BYTE_COUNT;
495 if (read_response->data_and_tail[ pec_index ] == pec)
496 break;
497
498 retry_count++;
499 } while(retry_count < MAX_RETRY_COUNT);
500
501 if (retry_count == MAX_RETRY_COUNT)
502 goto i2c_read_fail;
503
504 memcpy(dest, read_response->data_and_tail, n);
505 status_index = msgs[1].len - sizeof(read_response->byte_count) \
506 - DATA_TAIL_BYTE_COUNT;
507 status = read_response->data_and_tail[ status_index ];
508
509 free(read_command);
510 free(read_response);
511 return status;
512
513i2c_read_fail:
514 free(read_command);
515 free(read_response);
516 return -1;
517}
518
519static void i2c_gas_read(struct switchtec_dev *dev, void *dest,
520 const void __gas *src, size_t n)
521{
522 uint8_t status;
523 uint8_t retry_count = 0;
524
525 do {
526 status = i2c_gas_data_read(dev, dest, src, n);
527 if (status == 0 || status == GAS_TWI_MRPC_ERR)
528 break;
529 retry_count++;
530 }while(retry_count < MAX_RETRY_COUNT);
531
532 if (retry_count == MAX_RETRY_COUNT)
533 raise(SIGBUS);
534}
535
536static void i2c_memcpy_from_gas(struct switchtec_dev *dev, void *dest,
537 const void __gas *src, size_t n)
538{
539 size_t cnt;
540
541 while (n) {
542 cnt = n > I2C_MAX_READ ? I2C_MAX_READ : n;
543 i2c_gas_read(dev, dest, src, cnt);
544
545 dest += cnt;
546 src += cnt;
547 n -= cnt;
548 }
549}
550
551static ssize_t i2c_write_from_gas(struct switchtec_dev *dev, int fd,
552 const void __gas *src, size_t n)
553{
554 ssize_t ret;
555 void *buf;
556
557 buf = malloc(n);
558
559 i2c_memcpy_from_gas(dev, buf, src, n);
560
561 ret = write(fd, buf, n);
562
563 free(buf);
564
565 return ret;
566}
567
568// noop conversion functions to make macros below work
569static inline uint8_t le8toh(uint8_t x) { return x; }
570
571#define create_gas_read(type, suffix) \
572 static type i2c_gas_read ## suffix(struct switchtec_dev *dev, \
573 type __gas *addr) \
574 { \
575 type ret; \
576 i2c_memcpy_from_gas(dev, &ret, addr, sizeof(ret)); \
577 return le##suffix##toh(ret); \
578 }
579
580create_gas_read(uint8_t, 8);
581create_gas_read(uint16_t, 16);
582create_gas_read(uint32_t, 32);
583create_gas_read(uint64_t, 64);
584
585static void i2c_gas_write8(struct switchtec_dev *dev, uint8_t val,
586 uint8_t __gas *addr)
587{
588 i2c_gas_write(dev, addr, &val, sizeof(uint8_t));
589}
590
591static void i2c_gas_write16(struct switchtec_dev *dev, uint16_t val,
592 uint16_t __gas *addr)
593{
594 val = htole16(val);
595 i2c_gas_write(dev, addr, &val, sizeof(uint16_t));
596}
597
598static void i2c_gas_write32(struct switchtec_dev *dev, uint32_t val,
599 uint32_t __gas *addr)
600{
601 val = htole32(val);
602 i2c_gas_write(dev, addr, &val, sizeof(uint32_t));
603}
604
605static void i2c_gas_write32_no_retry(struct switchtec_dev *dev, uint32_t val,
606 uint32_t __gas *addr)
607{
608 val = htole32(val);
609 i2c_gas_write_no_retry(dev, addr, &val, sizeof(uint32_t));
610}
611
612static void i2c_gas_write64(struct switchtec_dev *dev, uint64_t val,
613 uint64_t __gas *addr)
614{
615 val = htole64(val);
616 i2c_gas_write(dev, addr, &val, sizeof(uint64_t));
617}
618
619static const struct switchtec_ops i2c_ops = {
620 .close = i2c_close,
621 .gas_map = i2c_gas_map,
622
623 .cmd = gasop_cmd,
624 .get_device_id = gasop_get_device_id,
625 .get_fw_version = gasop_get_fw_version,
626 .pff_to_port = gasop_pff_to_port,
627 .port_to_pff = gasop_port_to_pff,
628 .flash_part = gasop_flash_part,
629 .event_summary = gasop_event_summary,
630 .event_ctl = gasop_event_ctl,
631 .event_wait_for = gasop_event_wait_for,
632
633 .gas_read8 = i2c_gas_read8,
634 .gas_read16 = i2c_gas_read16,
635 .gas_read32 = i2c_gas_read32,
636 .gas_read64 = i2c_gas_read64,
637 .gas_write8 = i2c_gas_write8,
638 .gas_write16 = i2c_gas_write16,
639 .gas_write32 = i2c_gas_write32,
640 .gas_write32_no_retry = i2c_gas_write32_no_retry,
641 .gas_write64 = i2c_gas_write64,
642 .memcpy_to_gas = i2c_memcpy_to_gas,
643 .memcpy_from_gas = i2c_memcpy_from_gas,
644 .write_from_gas = i2c_write_from_gas,
645};
646
647struct switchtec_dev *switchtec_open_i2c(const char *path, int i2c_addr)
648{
649 struct switchtec_i2c *idev;
650
651 idev = malloc(sizeof(*idev));
652 if (!idev)
653 return NULL;
654
655 idev->fd = open(path, O_RDWR | O_CLOEXEC);
656 if (idev->fd < 0)
657 goto err_free;
658
659 if (check_i2c_device(idev))
660 goto err_close_free;
661
662 if (i2c_set_addr(idev, i2c_addr))
663 goto err_close_free;
664
665 if (i2c_set_timeout(idev, 10))
666 goto err_close_free;
667
668 if (i2c_gas_cap_get(&idev->dev) != TWI_ENHANCED_MODE)
669 goto err_close_free;
670
671 if (map_gas(&idev->dev))
672 goto err_close_free;
673
674 idev->dev.ops = &i2c_ops;
675
676 gasop_set_partition_info(&idev->dev);
677
678 return &idev->dev;
679
680err_close_free:
681 close(idev->fd);
682err_free:
683 free(idev);
684 return NULL;
685}
686
687struct switchtec_dev *switchtec_open_i2c_by_adapter(int adapter, int i2c_addr)
688{
689 char path[PATH_MAX];
690
691 sprintf(path, "/dev/i2c-%d", adapter);
692
693 return switchtec_open_i2c(path, i2c_addr);
694}
695
696#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:80