Skip to content

Commit

Permalink
DM: virtio-i2c: add support for virtio i2c adapter
Browse files Browse the repository at this point in the history
Add virtio i2c adapter BE driver.

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>
  • Loading branch information
conghuic23 authored and acrnsi committed Jul 5, 2019
1 parent 2751f13 commit a450add
Show file tree
Hide file tree
Showing 3 changed files with 200 additions and 0 deletions.
1 change: 1 addition & 0 deletions devicemodel/Makefile
Expand Up @@ -105,6 +105,7 @@ SRCS += hw/pci/core.c
SRCS += hw/pci/virtio/virtio_console.c
SRCS += hw/pci/virtio/virtio_block.c
SRCS += hw/pci/virtio/virtio_input.c
SRCS += hw/pci/virtio/virtio_i2c.c
SRCS += hw/pci/ahci.c
SRCS += hw/pci/hostbridge.c
SRCS += hw/pci/platform_gsi_info.c
Expand Down
197 changes: 197 additions & 0 deletions devicemodel/hw/pci/virtio/virtio_i2c.c
@@ -0,0 +1,197 @@
/*
* Copyright (C) 2019 Intel Corporation. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*
*/

#include <sys/param.h>
#include <sys/uio.h>
#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <pthread.h>
#include <openssl/md5.h>
#include <linux/i2c.h>
#include <linux/i2c-dev.h>
#include <sys/ioctl.h>

#include "dm.h"
#include "pci_core.h"
#include "virtio.h"

/* I2c adapter virtualization architecture
*
* +-----------------------------+
* | ACRN DM |
* | +----------------------+ | virtqueue
* | | |<--+-----------+
* | | virtio i2c mediator | | |
* | | | | |
* | +--+-----+-----+-------+ | |
* +-----+-----+-----+-----------+ |
* User space +-------+ | +-----------+ |
* v v v |
* +---------+----+ +-----+--------+ +-----+------+ | +-----------+
* ---+ /dev/i2c-0 +--+ /dev/i2c-1 +--+ /dev/i2c-n +----+--+UOS: |
* | | | | | | |/dev/i2c-n |
* +----------+---+ +-------+------+ +-----+------+ | +-----+-----+
* Kernel space v v v | v
* +-----+-------+ +----+--------+ +----+--------+ | +-----+------------+
* |i2c adapter 0| |i2c adapter 1| |i2c adapter n| +->|UOS: |
* | | | | | |virtio i2c adapter|
* +-----+-------+ +-------------+ +-------------+ +------------------+
* --------------+-----------------------------------------
* Hardware +----------+
* | |
* bus 0v v ....
* +-----+---+ +----+----+
* |i2c slave| |i2c slave| ....
* +---------+ +---------+
*/

static int virtio_i2c_debug=0;
#define VIRTIO_I2C_PREF "virtio_i2c: "
#define DPRINTF(fmt, args...) \
do { if (virtio_i2c_debug) printf(VIRTIO_I2C_PREF fmt, ##args); } while (0)
#define WPRINTF(fmt, args...) printf(VIRTIO_I2C_PREF fmt, ##args)

/*
* Per-device struct
*/
struct virtio_i2c {
struct virtio_base base;
pthread_mutex_t mtx;
struct virtio_vq_info vq;
char ident[256];
};

static void virtio_i2c_reset(void *);
static void virtio_i2c_notify(void *, struct virtio_vq_info *);

static struct virtio_ops virtio_i2c_ops = {
"virtio_i2c", /* our name */
1, /* we support 1 virtqueue */
0, /* config reg size */
virtio_i2c_reset, /* reset */
virtio_i2c_notify, /* device-wide qnotify */
NULL, /* read PCI config */
NULL, /* write PCI config */
NULL, /* apply negotiated features */
NULL, /* called on guest set status */
};

static void
virtio_i2c_reset(void *vdev)
{
struct virtio_i2c *vi2c = vdev;

DPRINTF("device reset requested !\n");
virtio_reset_dev(&vi2c->base);
}

static void
virtio_i2c_notify(void *vdev, struct virtio_vq_info *vq)
{
/* TODO: Add notify logic */
}

static int
virtio_i2c_init(struct vmctx *ctx, struct pci_vdev *dev, char *opts)
{
MD5_CTX mdctx;
u_char digest[16];
struct virtio_i2c *vi2c;
pthread_mutexattr_t attr;
int rc;

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

/* init mutex attribute properly to avoid deadlock */
rc = pthread_mutexattr_init(&attr);
if (rc) {
WPRINTF("mutexattr init failed with erro %d!\n", rc);
goto mtx_fail;
}
rc = pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE);
if (rc) {
WPRINTF("mutexattr_settype failed with "
"error %d!\n", rc);
goto mtx_fail;
}

rc = pthread_mutex_init(&vi2c->mtx, &attr);
if (rc) {
WPRINTF("pthread_mutex_init failed with "
"error %d!\n", rc);
goto mtx_fail;
}

/* init virtio struct and virtqueues */
virtio_linkup(&vi2c->base, &virtio_i2c_ops, vi2c, dev, &vi2c->vq, BACKEND_VBSU);
vi2c->base.mtx = &vi2c->mtx;
vi2c->vq.qsize = 64;

MD5_Init(&mdctx);
MD5_Update(&mdctx, "vi2c", strlen("vi2c"));
MD5_Final(digest, &mdctx);
rc = snprintf(vi2c->ident, sizeof(vi2c->ident),
"ACRN--%02X%02X-%02X%02X-%02X%02X", digest[0],
digest[1], digest[2], digest[3], digest[4],
digest[5]);
if (rc < 0) {
WPRINTF("create ident failed");
goto fail;
}
if (rc >= sizeof(vi2c->ident)) {
WPRINTF("ident too long\n");
}

pci_set_cfgdata16(dev, PCIR_DEVICE, VIRTIO_DEV_I2C);
pci_set_cfgdata16(dev, PCIR_VENDOR, INTEL_VENDOR_ID);
pci_set_cfgdata8(dev, PCIR_CLASS, PCIC_SERIALBUS);
pci_set_cfgdata16(dev, PCIR_SUBDEV_0, VIRTIO_TYPE_I2C);
pci_set_cfgdata16(dev, PCIR_SUBVEND_0, INTEL_VENDOR_ID);

if (virtio_interrupt_init(&vi2c->base, virtio_uses_msix())) {
WPRINTF("failed to init interrupt");
rc = -1;
goto fail;
}
virtio_set_io_bar(&vi2c->base, 0);
return 0;

fail:
pthread_mutex_destroy(&vi2c->mtx);
mtx_fail:
free(vi2c);
return rc;
}

static void
virtio_i2c_deinit(struct vmctx *ctx, struct pci_vdev *dev, char *opts)
{
struct virtio_i2c *vi2c;

if (dev->arg) {
DPRINTF("deinit\n");
vi2c = (struct virtio_i2c *) dev->arg;
pthread_mutex_destroy(&vi2c->mtx);
free(vi2c);
dev->arg = NULL;
}
}

struct pci_vdev_ops pci_ops_virtio_i2c = {
.class_name = "virtio-i2c",
.vdev_init = virtio_i2c_init,
.vdev_deinit = virtio_i2c_deinit,
.vdev_barwrite = virtio_pci_write,
.vdev_barread = virtio_pci_read,
};
DEFINE_PCI_DEVTYPE(pci_ops_virtio_i2c);
2 changes: 2 additions & 0 deletions devicemodel/include/virtio.h
Expand Up @@ -207,6 +207,7 @@ enum {
#define VIRTIO_TYPE_HDCP 0xFFF9
#define VIRTIO_TYPE_COREU 0xFFF8
#define VIRTIO_TYPE_GPIO 0xFFF7
#define VIRTIO_TYPE_I2C 0xFFF6

/*
* PCI vendor/device IDs
Expand All @@ -230,6 +231,7 @@ enum {
#define VIRTIO_DEV_HDCP 0x8607
#define VIRTIO_DEV_COREU 0x8608
#define VIRTIO_DEV_GPIO 0x8609
#define VIRTIO_DEV_I2C 0x860a

/*
* VIRTIO_CONFIG_S_NEEDS_RESET is not defined
Expand Down

0 comments on commit a450add

Please sign in to comment.