clear-pkgs-linux-iot-lts2018/0496-VBS-K-added-VHM-wrappe...

577 lines
16 KiB
Diff

From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Hao Li <hao.l.li@intel.com>
Date: Thu, 25 Jan 2018 10:12:26 -0500
Subject: [PATCH] VBS-K: added VHM wrapper APIs
This patch added 3 VHM wrapper APIs to the VBS-K framework:
- long virtio_dev_register(struct virtio_dev_info *dev);
- long virtio_dev_deregister(struct virtio_dev_info *dev);
- int virtio_vq_index_get(struct virtio_dev_info *dev, int req_cnt);
VBS-K modules could use the APIs above to register kick callback
handlers to VHM.
This patch also updated the reference driver with the new APIs
usage.
Change-Id: I6a92a36eb785d55c1a4aa09bba46c67ed5dd2194
Signed-off-by: Hao Li <hao.l.li@intel.com>
---
drivers/vbs/vbs.c | 121 ++++++++++++++++++++++++
drivers/vbs/vbs_rng.c | 199 ++++++++++------------------------------
include/linux/vbs/vbs.h | 16 +++-
3 files changed, 181 insertions(+), 155 deletions(-)
diff --git a/drivers/vbs/vbs.c b/drivers/vbs/vbs.c
index 1e7a9645a353..9d96f45b9644 100644
--- a/drivers/vbs/vbs.c
+++ b/drivers/vbs/vbs.c
@@ -67,6 +67,127 @@
#include <linux/vbs/vbs.h>
#include <linux/vbs/vq.h>
+long virtio_dev_register(struct virtio_dev_info *dev)
+{
+ struct vm_info info;
+ int ret;
+
+ pr_debug("vmid is %d\n", dev->_ctx.vmid);
+
+ if (dev->dev_notify == NULL) {
+ pr_err("%s dev_notify empty!\n", dev->name);
+ goto err;
+ }
+
+ /*
+ * dev->name is 32 chars while vhm only accepts 16 chars
+ * at most, so we make sure there will be a NULL
+ * terminator for the chars.
+ */
+ dev->name[15] = '\0';
+ dev->_ctx.vhm_client_id =
+ acrn_ioreq_create_client(dev->_ctx.vmid,
+ dev->dev_notify,
+ dev->name);
+ if (dev->_ctx.vhm_client_id < 0) {
+ pr_err("failed to create client of acrn ioreq!\n");
+ goto err;
+ }
+
+ ret = acrn_ioreq_add_iorange(dev->_ctx.vhm_client_id,
+ dev->io_range_type ? REQ_MMIO : REQ_PORTIO,
+ dev->io_range_start,
+ dev->io_range_start + dev->io_range_len - 1);
+ if (ret < 0) {
+ pr_err("failed to add iorange to acrn ioreq!\n");
+ goto err;
+ }
+
+ /* feed up max_cpu and req_buf */
+ ret = vhm_get_vm_info(dev->_ctx.vmid, &info);
+ if (ret < 0) {
+ pr_err("failed in vhm_get_vm_info!\n");
+ goto range_err;
+ }
+ dev->_ctx.max_vcpu = info.max_vcpu;
+
+ dev->_ctx.req_buf = acrn_ioreq_get_reqbuf(dev->_ctx.vhm_client_id);
+ if (dev->_ctx.req_buf == NULL) {
+ pr_err("failed in acrn_ioreq_get_reqbuf!\n");
+ goto range_err;
+ }
+
+ acrn_ioreq_attach_client(dev->_ctx.vhm_client_id, 0);
+
+ return 0;
+
+range_err:
+ acrn_ioreq_del_iorange(dev->_ctx.vhm_client_id,
+ dev->io_range_type ? REQ_MMIO : REQ_PORTIO,
+ dev->io_range_start,
+ dev->io_range_start + dev->io_range_len);
+
+err:
+ acrn_ioreq_destroy_client(dev->_ctx.vhm_client_id);
+
+ return -EINVAL;
+}
+
+long virtio_dev_deregister(struct virtio_dev_info *dev)
+{
+ acrn_ioreq_del_iorange(dev->_ctx.vhm_client_id,
+ dev->io_range_type ? REQ_MMIO : REQ_PORTIO,
+ dev->io_range_start,
+ dev->io_range_start + dev->io_range_len);
+
+ acrn_ioreq_destroy_client(dev->_ctx.vhm_client_id);
+
+ return 0;
+}
+
+int virtio_vq_index_get(struct virtio_dev_info *dev, int req_cnt)
+{
+ int val = -1;
+ struct vhm_request *req;
+ int i;
+
+ if (unlikely(req_cnt <= 0))
+ return -EINVAL;
+
+ if (dev == NULL) {
+ pr_err("%s: dev is NULL!\n", __func__);
+ return -EINVAL;
+ }
+
+ for (i = 0; i < dev->_ctx.max_vcpu; i++) {
+ req = &dev->_ctx.req_buf[i];
+ if (req->valid && req->processed == REQ_STATE_PROCESSING &&
+ req->client == dev->_ctx.vhm_client_id) {
+ if (req->reqs.pio_request.direction == REQUEST_READ) {
+ /* currently we handle kick only,
+ * so read will return 0
+ */
+ pr_debug("%s: read request!\n", __func__);
+ if (dev->io_range_type == PIO_RANGE)
+ req->reqs.pio_request.value = 0;
+ else
+ req->reqs.mmio_request.value = 0;
+ } else {
+ pr_debug("%s: write request! type %d\n",
+ __func__, req->type);
+ if (dev->io_range_type == PIO_RANGE)
+ val = req->reqs.pio_request.value;
+ else
+ val = req->reqs.mmio_request.value;
+ }
+ req->processed = REQ_STATE_SUCCESS;
+ acrn_ioreq_complete_request(dev->_ctx.vhm_client_id, i);
+ }
+ }
+
+ return val;
+}
+
static long virtio_vqs_info_set(struct virtio_dev_info *dev,
struct vbs_vqs_info __user *i)
{
diff --git a/drivers/vbs/vbs_rng.c b/drivers/vbs/vbs_rng.c
index f2234e73034d..87965bafbbb3 100644
--- a/drivers/vbs/vbs_rng.c
+++ b/drivers/vbs/vbs_rng.c
@@ -74,8 +74,6 @@
#include <linux/vbs/vq.h>
#include <linux/vbs/vbs.h>
-#include <linux/vhm/acrn_common.h>
-#include <linux/vhm/acrn_vhm_ioreq.h>
#include <linux/hashtable.h>
enum {
@@ -96,26 +94,14 @@ enum {
struct vbs_rng {
struct virtio_dev_info dev;
struct virtio_vq_info vqs[VBS_K_RNG_VQ_MAX];
- int vhm_client_id;
/* Below could be device specific members */
struct hwrng hwrng;
-};
-
-/*
- * Each VBS-K module might serve multiple connections from multiple
- * guests/device models/VBS-Us, so better to maintain the connections
- * in a list, and here we use hashtalble as an example.
- */
-struct vbs_rng_client {
- struct vbs_rng *rng;
- int vhm_client_id;
- int max_vcpu;
- struct vhm_request *req_buf;
-};
-
-/* instances malloced/freed by hashtable routines */
-struct vbs_rng_hash_entry {
- struct vbs_rng_client *info;
+ /*
+ * Each VBS-K module might serve multiple connections
+ * from multiple guests/device models/VBS-Us, so better
+ * to maintain the connections in a list, and here we
+ * use hashtable as an example.
+ */
struct hlist_node node;
};
@@ -149,30 +135,20 @@ static void vbs_rng_hash_init(void)
vbs_rng_hash_initialized = 1;
}
-static int vbs_rng_hash_add(struct vbs_rng_client *client)
+static int vbs_rng_hash_add(struct vbs_rng *entry)
{
- struct vbs_rng_hash_entry *entry;
-
if (!vbs_rng_hash_initialized) {
pr_err("RNG hash table not initialized!\n");
return -1;
}
- entry = kmalloc(sizeof(*entry), GFP_KERNEL);
- if (!entry) {
- pr_err("Failed to alloc memory for rng hash entry!\n");
- return -1;
- }
-
- entry->info = client;
-
- hash_add(HASH_NAME, &entry->node, entry->info->vhm_client_id);
+ hash_add(HASH_NAME, &entry->node, virtio_dev_client_id(&entry->dev));
return 0;
}
-static struct vbs_rng_client *vbs_rng_hash_find(int client_id)
+static struct vbs_rng *vbs_rng_hash_find(int client_id)
{
- struct vbs_rng_hash_entry *entry;
+ struct vbs_rng *entry;
int bkt;
if (!vbs_rng_hash_initialized) {
@@ -181,8 +157,8 @@ static struct vbs_rng_client *vbs_rng_hash_find(int client_id)
}
hash_for_each(HASH_NAME, bkt, entry, node)
- if (entry->info->vhm_client_id == client_id)
- return entry->info;
+ if (virtio_dev_client_id(&entry->dev) == client_id)
+ return entry;
pr_err("Not found item matching client_id!\n");
return NULL;
@@ -190,7 +166,7 @@ static struct vbs_rng_client *vbs_rng_hash_find(int client_id)
static int vbs_rng_hash_del(int client_id)
{
- struct vbs_rng_hash_entry *entry;
+ struct vbs_rng *entry;
int bkt;
if (!vbs_rng_hash_initialized) {
@@ -199,9 +175,8 @@ static int vbs_rng_hash_del(int client_id)
}
hash_for_each(HASH_NAME, bkt, entry, node)
- if (entry->info->vhm_client_id == client_id) {
+ if (virtio_dev_client_id(&entry->dev) == client_id) {
hash_del(&entry->node);
- kfree(entry);
return 0;
}
@@ -212,7 +187,7 @@ static int vbs_rng_hash_del(int client_id)
static int vbs_rng_hash_del_all(void)
{
- struct vbs_rng_hash_entry *entry;
+ struct vbs_rng *entry;
int bkt;
if (!vbs_rng_hash_initialized) {
@@ -221,75 +196,11 @@ static int vbs_rng_hash_del_all(void)
}
hash_for_each(HASH_NAME, bkt, entry, node)
- if (1) {
- hash_del(&entry->node);
- kfree(entry);
- }
+ hash_del(&entry->node);
return 0;
}
-static int register_vhm_client(struct virtio_dev_info *dev)
-{
- unsigned int vmid;
- struct vm_info info;
- struct vbs_rng_client *client;
- int ret;
-
- client = kcalloc(1, sizeof(*client), GFP_KERNEL);
- if (!client) {
- pr_err("failed to malloc vbs_rng_client!\n");
- return -EINVAL;
- }
-
- client->rng = container_of(dev, struct vbs_rng, dev);
- vmid = dev->_ctx.vmid;
- pr_debug("vmid is %d\n", vmid);
-
- client->vhm_client_id = acrn_ioreq_create_client(vmid, handle_kick,
- "vbs_rng kick init\n");
- if (client->vhm_client_id < 0) {
- pr_err("failed to create client of acrn ioreq!\n");
- goto err;
- }
-
- ret = acrn_ioreq_add_iorange(client->vhm_client_id,
- dev->io_range_type ? REQ_MMIO : REQ_PORTIO,
- dev->io_range_start,
- dev->io_range_start + dev->io_range_len);
- if (ret < 0) {
- pr_err("failed to add iorange to acrn ioreq!\n");
- goto err;
- }
-
- /* feed up max_cpu and req_buf */
- ret = vhm_get_vm_info(vmid, &info);
- if (ret < 0) {
- pr_err("failed in vhm_get_vm_info!\n");
- goto err;
- }
- client->max_vcpu = info.max_vcpu;
-
- client->req_buf = acrn_ioreq_get_reqbuf(client->vhm_client_id);
- if (client->req_buf == NULL) {
- pr_err("failed in acrn_ioreq_get_reqbuf!\n");
- goto err;
- }
-
- /* just attach once as vhm will kick kthread */
- acrn_ioreq_attach_client(client->vhm_client_id, 0);
-
- client->rng->vhm_client_id = client->vhm_client_id;
- vbs_rng_hash_add(client);
-
- return 0;
-err:
- acrn_ioreq_destroy_client(client->vhm_client_id);
- kfree(client);
-
- return -EINVAL;
-}
-
static void handle_vq_kick(struct vbs_rng *rng, int vq_idx)
{
struct iovec iov;
@@ -309,8 +220,6 @@ static void handle_vq_kick(struct vbs_rng *rng, int vq_idx)
vq = &(sc->vqs[vq_idx]);
- pr_debug("before vq_has_desc!\n");
-
while (virtio_vq_has_descs(vq)) {
virtio_vq_getchain(vq, &idx, &iov, 1, NULL);
@@ -334,47 +243,25 @@ static void handle_vq_kick(struct vbs_rng *rng, int vq_idx)
static int handle_kick(int client_id, int req_cnt)
{
int val = -1;
- struct vhm_request *req;
- struct vbs_rng_client *client;
- int i;
+ struct vbs_rng *rng;
if (unlikely(req_cnt <= 0))
return -EINVAL;
- pr_debug("%s!\n", __func__);
+ pr_debug("%s: handle kick!\n", __func__);
- client = vbs_rng_hash_find(client_id);
- if (!client) {
- pr_err("Ooops! client %d not found!\n", client_id);
+ rng = vbs_rng_hash_find(client_id);
+ if (rng == NULL) {
+ pr_err("%s: client %d not found!\n",
+ __func__, client_id);
return -EINVAL;
}
- for (i = 0; i < client->max_vcpu; i++) {
- req = &client->req_buf[i];
- if (req->valid && req->processed == REQ_STATE_PROCESSING &&
- req->client == client->vhm_client_id) {
- if (req->reqs.pio_request.direction == REQUEST_READ)
- /* currently we handle kick only,
- * so read will return 0
- */
- req->reqs.pio_request.value = 0;
- else
- val = req->reqs.pio_request.value;
- pr_debug("%s: ioreq type %d, direction %d, "
- "addr 0x%lx, size 0x%lx, value 0x%x\n",
- __func__,
- req->type,
- req->reqs.pio_request.direction,
- req->reqs.pio_request.address,
- req->reqs.pio_request.size,
- req->reqs.pio_request.value);
- req->processed = REQ_STATE_SUCCESS;
- acrn_ioreq_complete_request(client->vhm_client_id, i);
- }
- }
+ val = virtio_vq_index_get(&rng->dev, req_cnt);
if (val >= 0)
- handle_vq_kick(client->rng, val);
+ handle_vq_kick(rng, val);
+
return 0;
}
@@ -385,15 +272,15 @@ static int vbs_rng_open(struct inode *inode, struct file *f)
struct virtio_vq_info *vqs;
int i;
- pr_debug("%s!\n", __func__);
-
rng = kmalloc(sizeof(*rng), GFP_KERNEL);
- if (!rng) {
+ if (rng == NULL) {
pr_err("Failed to allocate memory for vbs_rng!\n");
return -ENOMEM;
}
dev = &rng->dev;
+ strncpy(dev->name, "vbs_rng", VBS_NAME_LEN);
+ dev->dev_notify = handle_kick;
vqs = (struct virtio_vq_info *)&rng->vqs;
for (i = 0; i < VBS_K_RNG_VQ_MAX; i++) {
@@ -411,6 +298,8 @@ static int vbs_rng_open(struct inode *inode, struct file *f)
virtio_dev_init(dev, vqs, VBS_K_RNG_VQ_MAX);
f->private_data = rng;
+
+ /* init a hash table to maintain multi-connections */
vbs_rng_hash_init();
return 0;
@@ -419,14 +308,10 @@ static int vbs_rng_open(struct inode *inode, struct file *f)
static int vbs_rng_release(struct inode *inode, struct file *f)
{
struct vbs_rng *rng = f->private_data;
- struct vbs_rng_client *client;
int i;
- pr_debug("%s!\n", __func__);
-
- client = vbs_rng_hash_find(rng->vhm_client_id);
- if (!client)
- pr_err("%s: UNLIKELY not found client!\n",
+ if (!rng)
+ pr_err("%s: UNLIKELY rng NULL!\n",
__func__);
vbs_rng_stop(rng);
@@ -437,16 +322,16 @@ static int vbs_rng_release(struct inode *inode, struct file *f)
/* device specific release */
vbs_rng_reset(rng);
- pr_debug("vbs_rng_connection cnt is %d\n", vbs_rng_connection_cnt);
+ pr_debug("vbs_rng_connection cnt is %d\n",
+ vbs_rng_connection_cnt);
- if (client && vbs_rng_connection_cnt--)
- vbs_rng_hash_del(client->vhm_client_id);
+ if (rng && vbs_rng_connection_cnt--)
+ vbs_rng_hash_del(virtio_dev_client_id(&rng->dev));
if (!vbs_rng_connection_cnt) {
pr_debug("vbs_rng remove all hash entries\n");
vbs_rng_hash_del_all();
}
- kfree(client);
kfree(rng);
pr_debug("%s done\n", __func__);
@@ -488,7 +373,8 @@ static long vbs_rng_ioctl(struct file *f, unsigned int ioctl,
* return vhost_net_set_features(n, features);
*/
case VBS_SET_VQ:
- /* we handle this here because we want to register VHM client
+ /*
+ * we handle this here because we want to register VHM client
* after handling VBS_K_SET_VQ request
*/
pr_debug("VBS_K_SET_VQ ioctl:\n");
@@ -498,10 +384,16 @@ static long vbs_rng_ioctl(struct file *f, unsigned int ioctl,
return -EFAULT;
}
/* Register VHM client */
- if (register_vhm_client(&rng->dev) < 0) {
+ if (virtio_dev_register(&rng->dev) < 0) {
pr_err("failed to register VHM client!\n");
return -EFAULT;
}
+ /* Added to local hash table */
+ if (vbs_rng_hash_add(rng) < 0) {
+ pr_err("failed to add to hashtable!\n");
+ return -EFAULT;
+ }
+ /* Increment counter */
vbs_rng_connection_cnt++;
return r;
default:
@@ -544,6 +436,7 @@ static void vbs_rng_stop_vq(struct vbs_rng *rng,
/* device specific function */
static void vbs_rng_stop(struct vbs_rng *rng)
{
+ virtio_dev_deregister(&rng->dev);
}
/* device specific function */
diff --git a/include/linux/vbs/vbs.h b/include/linux/vbs/vbs.h
index 715c49156a1a..b2e185e115c8 100644
--- a/include/linux/vbs/vbs.h
+++ b/include/linux/vbs/vbs.h
@@ -63,6 +63,8 @@
#define _VBS_H_
#include <linux/vbs/vbs_common_if.h>
+#include <linux/vhm/acrn_common.h>
+#include <linux/vhm/acrn_vhm_ioreq.h>
/*
* VBS-K device needs to handle frontend driver's kick in kernel.
@@ -78,6 +80,9 @@ enum IORangeType {
struct ctx {
/* VHM required info */
int vmid;
+ int vhm_client_id;
+ int max_vcpu;
+ struct vhm_request *req_buf;
};
struct virtio_desc { /* AKA vring_desc */
@@ -138,12 +143,16 @@ struct virtio_dev_info {
enum IORangeType io_range_type; /* IO range type, PIO or MMIO */
/* members created in kernel space VBS */
- void (*dev_notify)(void *, struct virtio_vq_info *);
- /* device-wide notification */
+ int (*dev_notify)(int, int); /* device-wide notification */
struct virtio_vq_info *vqs; /* virtqueue(s) */
int curq; /* current virtqueue index */
};
+static inline int virtio_dev_client_id(struct virtio_dev_info *dev)
+{
+ return dev->_ctx.vhm_client_id;
+}
+
/* VBS Runtime Control APIs */
long virtio_dev_init(struct virtio_dev_info *dev, struct virtio_vq_info *vqs,
int nvq);
@@ -151,5 +160,8 @@ long virtio_dev_ioctl(struct virtio_dev_info *dev, unsigned int ioctl,
void __user *argp);
long virtio_vqs_ioctl(struct virtio_dev_info *dev, unsigned int ioctl,
void __user *argp);
+long virtio_dev_register(struct virtio_dev_info *dev);
+long virtio_dev_deregister(struct virtio_dev_info *dev);
+int virtio_vq_index_get(struct virtio_dev_info *dev, int req_cnt);
#endif
--
https://clearlinux.org