kvm tools: Separate virtio-pci layer out of virtio-9p

Signed-off-by: Sasha Levin <levinsasha928@gmail.com>
Signed-off-by: Pekka Enberg <penberg@kernel.org>
This commit is contained in:
Sasha Levin
2015-06-01 16:39:47 +01:00
committed by Will Deacon
parent 99c74cf9e2
commit c7838fbd26
3 changed files with 120 additions and 169 deletions
+5 -3
View File
@@ -106,7 +106,7 @@ static int img_name_parser(const struct option *opt, const char *arg, int unset)
char tmp[PATH_MAX];
if (realpath(arg, tmp) == 0 ||
virtio_9p__init(kvm, tmp, "/dev/root") < 0)
virtio_9p__register(kvm, tmp, "/dev/root") < 0)
die("Unable to initialize virtio 9p");
using_rootfs = 1;
return 0;
@@ -144,7 +144,7 @@ static int virtio_9p_rootdir_parser(const struct option *opt, const char *arg, i
tag_name++;
}
if (realpath(arg, tmp)) {
if (virtio_9p__init(kvm, tmp, tag_name) < 0)
if (virtio_9p__register(kvm, tmp, tag_name) < 0)
die("Unable to initialize virtio 9p");
} else
die("Failed resolving 9p path");
@@ -598,7 +598,7 @@ int kvm_cmd_run(int argc, const char **argv, const char *prefix)
strlcat(real_cmdline, kernel_cmdline, sizeof(real_cmdline));
if (!using_rootfs && !image_filename[0]) {
if (virtio_9p__init(kvm, "/", "/dev/root") < 0)
if (virtio_9p__register(kvm, "/", "/dev/root") < 0)
die("Unable to initialize virtio 9p");
using_rootfs = 1;
@@ -650,6 +650,8 @@ int kvm_cmd_run(int argc, const char **argv, const char *prefix)
if (!network)
network = DEFAULT_NETWORK;
virtio_9p__init(kvm);
if (strncmp(network, "none", 4)) {
net_params.guest_ip = guest_ip;
net_params.host_ip = host_ip;
+8 -8
View File
@@ -3,9 +3,11 @@
#include "kvm/virtio.h"
#include "kvm/pci.h"
#include "kvm/threadpool.h"
#include "kvm/virtio-pci.h"
#include <sys/types.h>
#include <dirent.h>
#include <linux/list.h>
#define NUM_VIRT_QUEUES 1
#define VIRTQUEUE_NUM 128
@@ -38,21 +40,18 @@ struct p9_dev_job {
};
struct p9_dev {
u8 status;
u8 isr;
u16 config_vector;
u32 features;
struct list_head list;
struct virtio_pci vpci;
struct virtio_9p_config *config;
u16 base_addr;
int compat_id;
u32 features;
/* virtio queue */
u16 queue_selector;
struct virt_queue vqs[NUM_VIRT_QUEUES];
struct p9_dev_job jobs[NUM_VIRT_QUEUES];
struct p9_fid fids[VIRTIO_P9_MAX_FID];
char root_dir[PATH_MAX];
struct pci_device_header pci_hdr;
};
struct p9_pdu {
@@ -67,7 +66,8 @@ struct p9_pdu {
struct kvm;
int virtio_9p__init(struct kvm *kvm, const char *root, const char *tag_name);
int virtio_9p__register(struct kvm *kvm, const char *root, const char *tag_name);
int virtio_9p__init(struct kvm *kvm);
int virtio_p9_pdu_readf(struct p9_pdu *pdu, const char *fmt, ...);
int virtio_p9_pdu_writef(struct p9_pdu *pdu, const char *fmt, ...);
+107 -158
View File
@@ -19,6 +19,8 @@
#include <linux/virtio_9p.h>
#include <net/9p/9p.h>
static LIST_HEAD(devs);
/* Warning: Immediately use value returned from this function */
static const char *rel_to_abs(struct p9_dev *p9dev,
const char *path, char *abs_path)
@@ -28,62 +30,6 @@ static const char *rel_to_abs(struct p9_dev *p9dev,
return abs_path;
}
static bool virtio_p9_dev_in(struct p9_dev *p9dev, void *data,
unsigned long offset,
int size)
{
u8 *config_space = (u8 *) p9dev->config;
if (size != 1)
return false;
ioport__write8(data, config_space[offset - VIRTIO_MSI_CONFIG_VECTOR]);
return true;
}
static bool virtio_p9_pci_io_in(struct ioport *ioport, struct kvm *kvm,
u16 port, void *data, int size)
{
bool ret = true;
unsigned long offset;
struct p9_dev *p9dev = ioport->priv;
offset = port - p9dev->base_addr;
switch (offset) {
case VIRTIO_PCI_HOST_FEATURES:
ioport__write32(data, p9dev->features);
ret = true;
break;
case VIRTIO_PCI_GUEST_FEATURES:
case VIRTIO_PCI_QUEUE_SEL:
case VIRTIO_PCI_QUEUE_NOTIFY:
ret = false;
break;
case VIRTIO_PCI_QUEUE_PFN:
ioport__write32(data, p9dev->vqs[p9dev->queue_selector].pfn);
break;
case VIRTIO_PCI_QUEUE_NUM:
ioport__write16(data, VIRTQUEUE_NUM);
break;
case VIRTIO_PCI_STATUS:
ioport__write8(data, p9dev->status);
break;
case VIRTIO_PCI_ISR:
ioport__write8(data, p9dev->isr);
kvm__irq_line(kvm, p9dev->pci_hdr.irq_line, VIRTIO_IRQ_LOW);
p9dev->isr = VIRTIO_IRQ_LOW;
break;
default:
ret = virtio_p9_dev_in(p9dev, data, offset, size);
break;
};
return ret;
}
static int omode2uflags(u8 mode)
{
int ret = 0;
@@ -750,8 +696,7 @@ static void virtio_p9_do_io(struct kvm *kvm, void *param)
while (virt_queue__available(vq)) {
virtio_p9_do_io_request(kvm, job);
virt_queue__trigger_irq(vq, p9dev->pci_hdr.irq_line,
&p9dev->isr, kvm);
virtio_pci__signal_vq(kvm, &p9dev->vpci, vq - p9dev->vqs);
}
}
@@ -762,90 +707,115 @@ static void ioevent_callback(struct kvm *kvm, void *param)
thread_pool__do_job(&job->job_id);
}
static bool virtio_p9_pci_io_out(struct ioport *ioport, struct kvm *kvm,
u16 port, void *data, int size)
static void set_config(struct kvm *kvm, void *dev, u8 data, u32 offset)
{
unsigned long offset;
bool ret = true;
struct p9_dev *p9dev;
struct ioevent ioevent;
struct p9_dev *p9dev = dev;
p9dev = ioport->priv;
offset = port - p9dev->base_addr;
switch (offset) {
case VIRTIO_MSI_QUEUE_VECTOR:
case VIRTIO_PCI_GUEST_FEATURES:
break;
case VIRTIO_PCI_QUEUE_PFN: {
void *p;
struct p9_dev_job *job;
struct virt_queue *queue;
compat__remove_message(p9dev->compat_id);
job = &p9dev->jobs[p9dev->queue_selector];
queue = &p9dev->vqs[p9dev->queue_selector];
queue->pfn = ioport__read32(data);
p = guest_pfn_to_host(kvm, queue->pfn);
vring_init(&queue->vring, VIRTQUEUE_NUM, p,
VIRTIO_PCI_VRING_ALIGN);
*job = (struct p9_dev_job) {
.vq = queue,
.p9dev = p9dev,
};
thread_pool__init_job(&job->job_id, kvm, virtio_p9_do_io, job);
ioevent = (struct ioevent) {
.io_addr = p9dev->base_addr + VIRTIO_PCI_QUEUE_NOTIFY,
.io_len = sizeof(u16),
.fn = ioevent_callback,
.datamatch = p9dev->queue_selector,
.fn_ptr = &p9dev->jobs[p9dev->queue_selector],
.fn_kvm = kvm,
.fd = eventfd(0, 0),
};
ioeventfd__add_event(&ioevent);
break;
}
case VIRTIO_PCI_QUEUE_SEL:
p9dev->queue_selector = ioport__read16(data);
break;
case VIRTIO_PCI_QUEUE_NOTIFY: {
u16 queue_index;
queue_index = ioport__read16(data);
thread_pool__do_job(&p9dev->jobs[queue_index].job_id);
break;
}
case VIRTIO_PCI_STATUS:
p9dev->status = ioport__read8(data);
break;
case VIRTIO_MSI_CONFIG_VECTOR:
p9dev->config_vector = VIRTIO_MSI_NO_VECTOR;
break;
default:
ret = false;
break;
};
return ret;
((u8 *)(p9dev->config))[offset] = data;
}
static struct ioport_operations virtio_p9_io_ops = {
.io_in = virtio_p9_pci_io_in,
.io_out = virtio_p9_pci_io_out,
};
static u8 get_config(struct kvm *kvm, void *dev, u32 offset)
{
struct p9_dev *p9dev = dev;
int virtio_9p__init(struct kvm *kvm, const char *root, const char *tag_name)
return ((u8 *)(p9dev->config))[offset];
}
static u32 get_host_features(struct kvm *kvm, void *dev)
{
return 1 << VIRTIO_9P_MOUNT_TAG;
}
static void set_guest_features(struct kvm *kvm, void *dev, u32 features)
{
struct p9_dev *p9dev = dev;
p9dev->features = features;
}
static int init_vq(struct kvm *kvm, void *dev, u32 vq, u32 pfn)
{
struct p9_dev *p9dev = dev;
struct p9_dev_job *job;
struct virt_queue *queue;
void *p;
struct ioevent ioevent;
compat__remove_message(p9dev->compat_id);
queue = &p9dev->vqs[vq];
queue->pfn = pfn;
p = guest_pfn_to_host(kvm, queue->pfn);
job = &p9dev->jobs[vq];
vring_init(&queue->vring, VIRTQUEUE_NUM, p, VIRTIO_PCI_VRING_ALIGN);
*job = (struct p9_dev_job) {
.vq = queue,
.p9dev = p9dev,
};
thread_pool__init_job(&job->job_id, kvm, virtio_p9_do_io, job);
ioevent = (struct ioevent) {
.io_addr = p9dev->vpci.base_addr + VIRTIO_PCI_QUEUE_NOTIFY,
.io_len = sizeof(u16),
.fn = ioevent_callback,
.fn_ptr = &p9dev->jobs[vq],
.datamatch = vq,
.fn_kvm = kvm,
.fd = eventfd(0, 0),
};
ioeventfd__add_event(&ioevent);
return 0;
}
static int notify_vq(struct kvm *kvm, void *dev, u32 vq)
{
struct p9_dev *p9dev = dev;
thread_pool__do_job(&p9dev->jobs[vq].job_id);
return 0;
}
static int get_pfn_vq(struct kvm *kvm, void *dev, u32 vq)
{
struct p9_dev *p9dev = dev;
return p9dev->vqs[vq].pfn;
}
static int get_size_vq(struct kvm *kvm, void *dev, u32 vq)
{
return VIRTQUEUE_NUM;
}
int virtio_9p__init(struct kvm *kvm)
{
struct p9_dev *p9dev;
list_for_each_entry(p9dev, &devs, list) {
virtio_pci__init(kvm, &p9dev->vpci, p9dev, PCI_DEVICE_ID_VIRTIO_P9, VIRTIO_ID_9P);
p9dev->vpci.ops = (struct virtio_pci_ops) {
.set_config = set_config,
.get_config = get_config,
.get_host_features = get_host_features,
.set_guest_features = set_guest_features,
.init_vq = init_vq,
.notify_vq = notify_vq,
.get_pfn_vq = get_pfn_vq,
.get_size_vq = get_size_vq,
};
}
return 0;
}
int virtio_9p__register(struct kvm *kvm, const char *root, const char *tag_name)
{
struct p9_dev *p9dev;
u8 pin, line, dev;
u16 p9_base_addr;
u32 i, root_len;
int err = 0;
@@ -878,30 +848,9 @@ int virtio_9p__init(struct kvm *kvm, const char *root, const char *tag_name)
goto free_p9dev_config;
}
memcpy(p9dev->config->tag, tag_name, strlen(tag_name));
p9dev->features |= 1 << VIRTIO_9P_MOUNT_TAG;
memcpy(&p9dev->config->tag, tag_name, strlen(tag_name));
err = irq__register_device(VIRTIO_ID_9P, &dev, &pin, &line);
if (err < 0)
goto free_p9dev_config;
p9_base_addr = ioport__register(IOPORT_EMPTY, &virtio_p9_io_ops, IOPORT_SIZE, p9dev);
p9dev->base_addr = p9_base_addr;
p9dev->pci_hdr = (struct pci_device_header) {
.vendor_id = PCI_VENDOR_ID_REDHAT_QUMRANET,
.device_id = PCI_DEVICE_ID_VIRTIO_P9,
.header_type = PCI_HEADER_TYPE_NORMAL,
.revision_id = 0,
.class = 0x010000,
.subsys_vendor_id = PCI_SUBSYSTEM_VENDOR_ID_REDHAT_QUMRANET,
.subsys_id = VIRTIO_ID_9P,
.irq_pin = pin,
.irq_line = line,
.bar[0] = p9_base_addr | PCI_BASE_ADDRESS_SPACE_IO,
};
pci__register(&p9dev->pci_hdr, dev);
list_add(&p9dev->list, &devs);
p9dev->compat_id = compat__add_message("virtio-9p device was not detected",
"While you have requested a virtio-9p device, "