Switchtec Userspace PROJECT_NUMBER = 3.1
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
402 tag = get_tag(idev);
403 i2c_gas_data_write(dev, dest, src, n, tag);
404 status = i2c_gas_write_status_get(dev, tag);
405 if (status == 0 || status == GAS_TWI_MRPC_ERR)
406 return;
407
408 raise(SIGBUS);
409}
410
411static void i2c_memcpy_to_gas(struct switchtec_dev *dev, void __gas *dest,
412 const void *src, size_t n)
413{
414 size_t cnt;
415
416 while (n) {
417 cnt = n > I2C_MAX_WRITE ? I2C_MAX_WRITE : n;
418 i2c_gas_write(dev, dest, src, cnt);
419
420 dest += cnt;
421 src += cnt;
422 n -= cnt;
423 }
424}
425
426static uint8_t i2c_gas_data_read(struct switchtec_dev *dev, void *dest,
427 const void __gas *src, size_t n)
428{
429 int ret;
430 int pec_index, status_index;
431 uint8_t msg_0_pec, pec;
432 uint8_t retry_count = 0;
433
434 struct switchtec_i2c *idev = to_switchtec_i2c(dev);
435 uint32_t gas_addr = (uint32_t)(src - (void __gas *)dev->gas_map);
436 uint8_t status;
437
438 struct i2c_msg msgs[2];
439 struct i2c_rdwr_ioctl_data rwdata = {
440 .msgs = msgs,
441 .nmsgs = 2,
442 };
443
444 struct {
445 uint8_t command_code;
446 uint8_t byte_count;
447 uint32_t offset;
448 uint8_t data_length;
449 } __attribute__((packed)) *read_command;
450
451 struct {
452 uint8_t byte_count;
453 /* tail is one byte status and one byte pec */
454 uint8_t data_and_tail[];
455 }*read_response;
456
457 read_command = malloc(sizeof(*read_command));
458 read_response = malloc(sizeof(*read_response) + n \
459 + DATA_TAIL_BYTE_COUNT);
460
461 msgs[0].addr = msgs[1].addr = idev->i2c_addr;
462 msgs[0].flags = 0;
463 msgs[0].len = sizeof(*read_command);
464
465 read_command->command_code = CMD_GAS_READ;
466 read_command->byte_count = sizeof(read_command->offset) \
467 + sizeof(read_command->data_length);
468 gas_addr = htobe32(gas_addr);
469 read_command->offset = gas_addr;
470 read_command->data_length = n;
471 msgs[0].buf = (uint8_t *)read_command;
472
473 msgs[1].flags = I2C_M_RD;
474 msgs[1].len = sizeof(read_response->byte_count) + n + \
475 DATA_TAIL_BYTE_COUNT;
476 msgs[1].buf = (uint8_t *)read_response;
477
478 do {
479 ret = ioctl(idev->fd, I2C_RDWR, &rwdata);
480 if (ret < 0)
481 goto i2c_read_fail;
482
483 msg_0_pec = i2c_msg_pec(&msgs[0], msgs[0].len, 0, true);
484 pec = i2c_msg_pec(&msgs[1], msgs[1].len - PEC_BYTE_COUNT, \
485 msg_0_pec, false);
486 pec_index = msgs[1].len - sizeof(read_response->byte_count) \
487 - PEC_BYTE_COUNT;
488 if (read_response->data_and_tail[ pec_index ] == pec)
489 break;
490
491 retry_count++;
492 } while(retry_count < MAX_RETRY_COUNT);
493
494 if (retry_count == MAX_RETRY_COUNT)
495 goto i2c_read_fail;
496
497 memcpy(dest, read_response->data_and_tail, n);
498 status_index = msgs[1].len - sizeof(read_response->byte_count) \
499 - DATA_TAIL_BYTE_COUNT;
500 status = read_response->data_and_tail[ status_index ];
501
502 free(read_command);
503 free(read_response);
504 return status;
505
506i2c_read_fail:
507 free(read_command);
508 free(read_response);
509 return -1;
510}
511
512static void i2c_gas_read(struct switchtec_dev *dev, void *dest,
513 const void __gas *src, size_t n)
514{
515 uint8_t status;
516 uint8_t retry_count = 0;
517
518 do {
519 status = i2c_gas_data_read(dev, dest, src, n);
520 if (status == 0 || status == GAS_TWI_MRPC_ERR)
521 break;
522 retry_count++;
523 }while(retry_count < MAX_RETRY_COUNT);
524
525 if (retry_count == MAX_RETRY_COUNT)
526 raise(SIGBUS);
527}
528
529static void i2c_memcpy_from_gas(struct switchtec_dev *dev, void *dest,
530 const void __gas *src, size_t n)
531{
532 size_t cnt;
533
534 while (n) {
535 cnt = n > I2C_MAX_READ ? I2C_MAX_READ : n;
536 i2c_gas_read(dev, dest, src, cnt);
537
538 dest += cnt;
539 src += cnt;
540 n -= cnt;
541 }
542}
543
544static ssize_t i2c_write_from_gas(struct switchtec_dev *dev, int fd,
545 const void __gas *src, size_t n)
546{
547 ssize_t ret;
548 void *buf;
549
550 buf = malloc(n);
551
552 i2c_memcpy_from_gas(dev, buf, src, n);
553
554 ret = write(fd, buf, n);
555
556 free(buf);
557
558 return ret;
559}
560
561// noop conversion functions to make macros below work
562static inline uint8_t le8toh(uint8_t x) { return x; }
563
564#define create_gas_read(type, suffix) \
565 static type i2c_gas_read ## suffix(struct switchtec_dev *dev, \
566 type __gas *addr) \
567 { \
568 type ret; \
569 i2c_memcpy_from_gas(dev, &ret, addr, sizeof(ret)); \
570 return le##suffix##toh(ret); \
571 }
572
573create_gas_read(uint8_t, 8);
574create_gas_read(uint16_t, 16);
575create_gas_read(uint32_t, 32);
576create_gas_read(uint64_t, 64);
577
578static void i2c_gas_write8(struct switchtec_dev *dev, uint8_t val,
579 uint8_t __gas *addr)
580{
581 i2c_gas_write(dev, addr, &val, sizeof(uint8_t));
582}
583
584static void i2c_gas_write16(struct switchtec_dev *dev, uint16_t val,
585 uint16_t __gas *addr)
586{
587 val = htole16(val);
588 i2c_gas_write(dev, addr, &val, sizeof(uint16_t));
589}
590
591static void i2c_gas_write32(struct switchtec_dev *dev, uint32_t val,
592 uint32_t __gas *addr)
593{
594 val = htole32(val);
595 i2c_gas_write(dev, addr, &val, sizeof(uint32_t));
596}
597
598static void i2c_gas_write32_no_retry(struct switchtec_dev *dev, uint32_t val,
599 uint32_t __gas *addr)
600{
601 val = htole32(val);
602 i2c_gas_write_no_retry(dev, addr, &val, sizeof(uint32_t));
603}
604
605static void i2c_gas_write64(struct switchtec_dev *dev, uint64_t val,
606 uint64_t __gas *addr)
607{
608 val = htole64(val);
609 i2c_gas_write(dev, addr, &val, sizeof(uint64_t));
610}
611
612static const struct switchtec_ops i2c_ops = {
613 .close = i2c_close,
614 .gas_map = i2c_gas_map,
615
616 .cmd = gasop_cmd,
617 .get_device_id = gasop_get_device_id,
618 .get_fw_version = gasop_get_fw_version,
619 .pff_to_port = gasop_pff_to_port,
620 .port_to_pff = gasop_port_to_pff,
621 .flash_part = gasop_flash_part,
622 .event_summary = gasop_event_summary,
623 .event_ctl = gasop_event_ctl,
624 .event_wait_for = gasop_event_wait_for,
625
626 .gas_read8 = i2c_gas_read8,
627 .gas_read16 = i2c_gas_read16,
628 .gas_read32 = i2c_gas_read32,
629 .gas_read64 = i2c_gas_read64,
630 .gas_write8 = i2c_gas_write8,
631 .gas_write16 = i2c_gas_write16,
632 .gas_write32 = i2c_gas_write32,
633 .gas_write32_no_retry = i2c_gas_write32_no_retry,
634 .gas_write64 = i2c_gas_write64,
635 .memcpy_to_gas = i2c_memcpy_to_gas,
636 .memcpy_from_gas = i2c_memcpy_from_gas,
637 .write_from_gas = i2c_write_from_gas,
638};
639
640struct switchtec_dev *switchtec_open_i2c(const char *path, int i2c_addr)
641{
642 struct switchtec_i2c *idev;
643
644 idev = malloc(sizeof(*idev));
645 if (!idev)
646 return NULL;
647
648 idev->fd = open(path, O_RDWR | O_CLOEXEC);
649 if (idev->fd < 0)
650 goto err_free;
651
652 if (check_i2c_device(idev))
653 goto err_close_free;
654
655 if (i2c_set_addr(idev, i2c_addr))
656 goto err_close_free;
657
658 if (i2c_set_timeout(idev, 10))
659 goto err_close_free;
660
661 if (i2c_gas_cap_get(&idev->dev) != TWI_ENHANCED_MODE)
662 goto err_close_free;
663
664 if (map_gas(&idev->dev))
665 goto err_close_free;
666
667 idev->dev.ops = &i2c_ops;
668
669 gasop_set_partition_info(&idev->dev);
670
671 return &idev->dev;
672
673err_close_free:
674 close(idev->fd);
675err_free:
676 free(idev);
677 return NULL;
678}
679
680struct switchtec_dev *switchtec_open_i2c_by_adapter(int adapter, int i2c_addr)
681{
682 char path[PATH_MAX];
683
684 sprintf(path, "/dev/i2c-%d", adapter);
685
686 return switchtec_open_i2c(path, i2c_addr);
687}
688
689#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