Skip to content

Commit 859af9e

Browse files
conghuic23acrnsi
authored andcommitted
DM: virtio-i2c: add backend interface
Add backend interface for virtio-i2c, it will parse the parameters, maintain the info for native i2c device, remap the slave address and dispatch the requirement from FE. When there is only one native adapter, will not remap the slave address. Usage for virtio-i2c: virtio-i2c,<bus>[:<slave_addr>][:<slave_addr>] [,<bus>[:<slave_addr>][:<slave_addr>]] e.g. 1. virtio-i2c,4:1C SOS: mount /dev/i2c-4, slave addr is 0x1C. Guest OS: /dev/i2c-x |- 0x1C 2. virtio-i2c,4:1C:2F,6:70 SOS: /dev/i2c-4, slave addr 0x1C and 0x2F /dev/i2c-6, slave addr 0x70 Guest OS: /dev/i2c-x |- 0x1C |- 0x2F |- 0x70 Tracked-On: #3357 Signed-off-by: Conghui Chen <conghui.chen@intel.com> Reviewed-by: Yuan Liu <yuan1.liu@intel.com> Reviewed-by: Shuo A Liu <shuo.a.liu@intel.com> Acked-by: Wang Yu <yu1.wang@intel.com>
1 parent a450add commit 859af9e

File tree

1 file changed

+200
-1
lines changed

1 file changed

+200
-1
lines changed

devicemodel/hw/pci/virtio/virtio_i2c.c

Lines changed: 200 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,11 @@
1616
#include <linux/i2c.h>
1717
#include <linux/i2c-dev.h>
1818
#include <sys/ioctl.h>
19+
#include <sys/queue.h>
20+
#include <stdbool.h>
21+
#include <pthread.h>
22+
#include <fcntl.h>
23+
#include <unistd.h>
1924

2025
#include "dm.h"
2126
#include "pci_core.h"
@@ -57,12 +62,24 @@ static int virtio_i2c_debug=0;
5762
do { if (virtio_i2c_debug) printf(VIRTIO_I2C_PREF fmt, ##args); } while (0)
5863
#define WPRINTF(fmt, args...) printf(VIRTIO_I2C_PREF fmt, ##args)
5964

65+
#define MAX_I2C_VDEV 128
66+
#define MAX_NATIVE_I2C_ADAPTER 16
67+
68+
struct native_i2c_adapter {
69+
int fd;
70+
int bus;
71+
bool i2cdev_enable[MAX_I2C_VDEV];
72+
};
73+
6074
/*
6175
* Per-device struct
6276
*/
6377
struct virtio_i2c {
6478
struct virtio_base base;
6579
pthread_mutex_t mtx;
80+
struct native_i2c_adapter *native_adapter[MAX_NATIVE_I2C_ADAPTER];
81+
int native_adapter_num;
82+
uint16_t adapter_map[MAX_I2C_VDEV];
6683
struct virtio_vq_info vq;
6784
char ident[256];
6885
};
@@ -82,6 +99,177 @@ static struct virtio_ops virtio_i2c_ops = {
8299
NULL, /* called on guest set status */
83100
};
84101

102+
static bool
103+
native_slave_access_ok(struct native_i2c_adapter *adapter, uint16_t addr)
104+
{
105+
if (ioctl(adapter->fd, I2C_SLAVE, addr) < 0) {
106+
if (errno == EBUSY) {
107+
WPRINTF("i2c_core: slave device %x is busy!\n", addr);
108+
} else {
109+
WPRINTF("i2c_core: slave device %d is not exsit!\n", addr);
110+
}
111+
return false;
112+
}
113+
return true;
114+
}
115+
116+
static struct native_i2c_adapter *
117+
native_adapter_create(int bus, uint16_t slave_addr[], int n_slave)
118+
{
119+
int fd;
120+
struct native_i2c_adapter *native_adapter;
121+
char native_path[20];
122+
int i;
123+
124+
if (bus < 0)
125+
return NULL;
126+
127+
native_adapter = calloc(1, sizeof(struct native_i2c_adapter));
128+
if (native_adapter == NULL) {
129+
WPRINTF("i2c_core: failed to calloc struct virtio_i2c_vdev");
130+
return NULL;
131+
}
132+
133+
sprintf(native_path, "/dev/i2c-%d", bus);
134+
fd = open(native_path, O_RDWR);
135+
if (fd < 0) {
136+
WPRINTF("virtio_i2c: failed to open %s\n", native_path);
137+
return NULL;
138+
}
139+
native_adapter->fd = fd;
140+
native_adapter->bus = bus;
141+
for (i = 0; i < n_slave; i++) {
142+
if (slave_addr[i]) {
143+
if (native_slave_access_ok(native_adapter, slave_addr[i])) {
144+
if (native_adapter->i2cdev_enable[slave_addr[i]]) {
145+
WPRINTF("slave addr 0x%x repeat, not allowed.\n", slave_addr[i]);
146+
goto fail;
147+
}
148+
native_adapter->i2cdev_enable[slave_addr[i]] = true;
149+
DPRINTF("virtio_i2c: add slave 0x%x\n", slave_addr[i]);
150+
} else {
151+
goto fail;
152+
}
153+
}
154+
}
155+
return native_adapter;
156+
157+
fail:
158+
free(native_adapter);
159+
return NULL;
160+
}
161+
162+
static void
163+
native_adapter_remove(struct virtio_i2c *vi2c)
164+
{
165+
int i;
166+
struct native_i2c_adapter *native_adapter;
167+
168+
for (i = 0; i < MAX_NATIVE_I2C_ADAPTER; i++) {
169+
native_adapter = vi2c->native_adapter[i];
170+
if (native_adapter) {
171+
if (native_adapter->fd > 0)
172+
close(native_adapter->fd);
173+
free(native_adapter);
174+
vi2c->native_adapter[i] = NULL;
175+
}
176+
}
177+
}
178+
179+
static int
180+
virtio_i2c_map(struct virtio_i2c *vi2c)
181+
{
182+
int i, slave_addr;
183+
struct native_i2c_adapter *native_adapter;
184+
185+
/*
186+
* Flatten the map for slave address and native adapter to the array:
187+
*
188+
* adapter_map[MAX_I2C_VDEV]:
189+
*
190+
* Native Adapter | adapter2 | none | adapter1 | adapter3 | none | none| (val)
191+
* |----------|-------|----------|----------|------|-----|
192+
* Slave Address | addr 1 | none | addr 2 | addr 3 | none | none| (idx)
193+
* |<-----------------------MAX_I2C_VDEV---------------->|
194+
*/
195+
for (i = 0; i < vi2c->native_adapter_num; i++) {
196+
native_adapter = vi2c->native_adapter[i];
197+
for (slave_addr = 0; slave_addr < MAX_I2C_VDEV; slave_addr++) {
198+
if (native_adapter->i2cdev_enable[slave_addr]) {
199+
if (vi2c->adapter_map[slave_addr]) {
200+
WPRINTF("slave addr %x repeat, not support!\n", slave_addr);
201+
return -1;
202+
}
203+
/* As 0 is the initiate value, + 1 for index */
204+
vi2c->adapter_map[slave_addr] = i + 1;
205+
DPRINTF("slave:%d -> native adapter: %d \n",
206+
slave_addr,
207+
native_adapter->bus);
208+
}
209+
}
210+
}
211+
return 0;
212+
}
213+
214+
static int
215+
virtio_i2c_parse(struct virtio_i2c *vi2c, char *optstr)
216+
{
217+
char *cp, *t;
218+
uint16_t slave_addr[MAX_I2C_VDEV];
219+
int addr, bus, n_adapter, n_slave;
220+
221+
/*
222+
* virtio-i2c,<bus>:<slave_addr>[:<slave_addr>],
223+
* [<bus>:<slave_addr>[:<slave_addr>]]
224+
*
225+
* bus (dec): native adatper bus number.
226+
* e.g. 2 for /dev/i2c-2
227+
* slave_addr (hex): address for native slave device
228+
* e.g. 0x1C or 1C
229+
*
230+
* Note: slave address can not repeat.
231+
*/
232+
n_adapter = 0;
233+
while (optstr != NULL) {
234+
cp = strsep(&optstr, ",");
235+
/*
236+
* <bus>:<slave_addr>[:<slave_addr>]...
237+
*/
238+
n_slave = 0;
239+
bus = -1;
240+
while (cp != NULL && *cp !='\0') {
241+
if (*cp == ':')
242+
cp++;
243+
if (bus == -1) {
244+
if (dm_strtoi(cp, &t, 10, &bus) || bus < 0)
245+
return -1;
246+
} else {
247+
if (dm_strtoi(cp, &t, 16, &addr) || addr < 0)
248+
return -1;
249+
if (n_slave > MAX_I2C_VDEV) {
250+
WPRINTF("too many devices, only support %d \n", MAX_I2C_VDEV);
251+
return -1;
252+
}
253+
slave_addr[n_slave] = (uint16_t)(addr & (MAX_I2C_VDEV - 1));
254+
DPRINTF("native i2c adapter %d:0x%x\n", bus, slave_addr[n_slave]);
255+
n_slave++;
256+
}
257+
cp = t;
258+
}
259+
if (n_adapter > MAX_NATIVE_I2C_ADAPTER) {
260+
WPRINTF("too many adapter, only support %d \n", MAX_NATIVE_I2C_ADAPTER);
261+
return -1;
262+
}
263+
vi2c->native_adapter[n_adapter] = native_adapter_create(bus, slave_addr, n_slave);
264+
if (!vi2c->native_adapter[n_adapter])
265+
return -1;
266+
n_adapter++;
267+
}
268+
vi2c->native_adapter_num = n_adapter;
269+
270+
return 0;
271+
}
272+
85273
static void
86274
virtio_i2c_reset(void *vdev)
87275
{
@@ -104,14 +292,22 @@ virtio_i2c_init(struct vmctx *ctx, struct pci_vdev *dev, char *opts)
104292
u_char digest[16];
105293
struct virtio_i2c *vi2c;
106294
pthread_mutexattr_t attr;
107-
int rc;
295+
int rc = -1;
108296

109297
vi2c = calloc(1, sizeof(struct virtio_i2c));
110298
if (!vi2c) {
111299
WPRINTF("calloc returns NULL\n");
112300
return -ENOMEM;
113301
}
114302

303+
if (virtio_i2c_parse(vi2c, opts)) {
304+
WPRINTF("failed to parse parameters %s \n", opts);
305+
goto mtx_fail;
306+
}
307+
308+
if (virtio_i2c_map(vi2c))
309+
goto mtx_fail;
310+
115311
/* init mutex attribute properly to avoid deadlock */
116312
rc = pthread_mutexattr_init(&attr);
117313
if (rc) {
@@ -136,6 +332,7 @@ virtio_i2c_init(struct vmctx *ctx, struct pci_vdev *dev, char *opts)
136332
virtio_linkup(&vi2c->base, &virtio_i2c_ops, vi2c, dev, &vi2c->vq, BACKEND_VBSU);
137333
vi2c->base.mtx = &vi2c->mtx;
138334
vi2c->vq.qsize = 64;
335+
vi2c->native_adapter_num = 0;
139336

140337
MD5_Init(&mdctx);
141338
MD5_Update(&mdctx, "vi2c", strlen("vi2c"));
@@ -169,6 +366,7 @@ virtio_i2c_init(struct vmctx *ctx, struct pci_vdev *dev, char *opts)
169366
fail:
170367
pthread_mutex_destroy(&vi2c->mtx);
171368
mtx_fail:
369+
native_adapter_remove(vi2c);
172370
free(vi2c);
173371
return rc;
174372
}
@@ -181,6 +379,7 @@ virtio_i2c_deinit(struct vmctx *ctx, struct pci_vdev *dev, char *opts)
181379
if (dev->arg) {
182380
DPRINTF("deinit\n");
183381
vi2c = (struct virtio_i2c *) dev->arg;
382+
native_adapter_remove(vi2c);
184383
pthread_mutex_destroy(&vi2c->mtx);
185384
free(vi2c);
186385
dev->arg = NULL;

0 commit comments

Comments
 (0)