From a450add6725e74ed948233f0cf00cb2e6fd5f245 Mon Sep 17 00:00:00 2001 From: Conghui Chen Date: Wed, 22 May 2019 09:43:41 +0800 Subject: [PATCH] DM: virtio-i2c: add support for virtio i2c adapter Add virtio i2c adapter BE driver. Tracked-On: #3357 Signed-off-by: Conghui Chen Reviewed-by: Yuan Liu Reviewed-by: Shuo A Liu Acked-by: Wang Yu --- devicemodel/Makefile | 1 + devicemodel/hw/pci/virtio/virtio_i2c.c | 197 +++++++++++++++++++++++++ devicemodel/include/virtio.h | 2 + 3 files changed, 200 insertions(+) create mode 100644 devicemodel/hw/pci/virtio/virtio_i2c.c diff --git a/devicemodel/Makefile b/devicemodel/Makefile index 44a3e59d9..0c0ae4f3e 100644 --- a/devicemodel/Makefile +++ b/devicemodel/Makefile @@ -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 diff --git a/devicemodel/hw/pci/virtio/virtio_i2c.c b/devicemodel/hw/pci/virtio/virtio_i2c.c new file mode 100644 index 000000000..dbc3fd53f --- /dev/null +++ b/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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#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); diff --git a/devicemodel/include/virtio.h b/devicemodel/include/virtio.h index 37a7c95b0..1c7e12e09 100644 --- a/devicemodel/include/virtio.h +++ b/devicemodel/include/virtio.h @@ -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 @@ -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