Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit f69bcbf3 authored by Ashutosh Dixit's avatar Ashutosh Dixit Committed by Greg Kroah-Hartman
Browse files

Intel MIC Host Driver Changes for Virtio Devices.



This patch introduces the host "Virtio over PCIe" interface for
Intel MIC. It allows creating user space backends on the host and instantiating
virtio devices for them on the Intel MIC card. It uses the existing VRINGH
infrastructure in the kernel to access virtio rings from the host. A character
device per MIC is exposed with IOCTL, mmap and poll callbacks. This allows the
user space backend to:
(a) add/remove a virtio device via a device page.
(b) map (R/O) virtio rings and device page to user space.
(c) poll for availability of data.
(d) copy a descriptor or entire descriptor chain to/from the card.
(e) modify virtio configuration.
(f) handle virtio device reset.
The buffers are copied over using CPU copies for this initial patch
and host initiated MIC DMA support is planned for future patches.
The avail and desc virtio rings are in host memory and the used ring
is in card memory to maximize writes across PCIe for performance.

Co-author: Sudeep Dutt <sudeep.dutt@intel.com>
Signed-off-by: default avatarAshutosh Dixit <ashutosh.dixit@intel.com>
Signed-off-by: default avatarCaz Yokoyama <Caz.Yokoyama@intel.com>
Signed-off-by: default avatarDasaratharaman Chandramouli <dasaratharaman.chandramouli@intel.com>
Signed-off-by: default avatarNikhil Rao <nikhil.rao@intel.com>
Signed-off-by: default avatarHarshavardhan R Kharche <harshavardhan.r.kharche@intel.com>
Signed-off-by: default avatarSudeep Dutt <sudeep.dutt@intel.com>
Acked-by: default avatarYaozu (Eddie) Dong <eddie.dong@intel.com>
Reviewed-by: default avatarPeter P Waskiewicz Jr <peter.p.waskiewicz.jr@intel.com>
Signed-off-by: default avatarGreg Kroah-Hartman <gregkh@linuxfoundation.org>
parent aa27badd
Loading
Loading
Loading
Loading
+1 −0
Original line number Diff line number Diff line
@@ -3,6 +3,7 @@ comment "Intel MIC Host Driver"
config INTEL_MIC_HOST
	tristate "Intel MIC Host Driver"
	depends on 64BIT && PCI
	select VHOST_RING
	default N
	help
	  This enables Host Driver support for the Intel Many Integrated
+7 −0
Original line number Diff line number Diff line
@@ -41,4 +41,11 @@ struct mic_mw {
#define MIC_DPLO_SPAD 14
#define MIC_DPHI_SPAD 15

/*
 * These values are supposed to be in the config_change field of the
 * device page when the host sends a config change interrupt to the card.
 */
#define MIC_VIRTIO_PARAM_DEV_REMOVE 0x1
#define MIC_VIRTIO_PARAM_CONFIG_CHANGED 0x2

#endif
+2 −0
Original line number Diff line number Diff line
@@ -10,3 +10,5 @@ mic_host-objs += mic_smpt.o
mic_host-objs += mic_intr.o
mic_host-objs += mic_boot.o
mic_host-objs += mic_debugfs.o
mic_host-objs += mic_fops.o
mic_host-objs += mic_virtio.o
+2 −1
Original line number Diff line number Diff line
@@ -20,12 +20,12 @@
 */
#include <linux/delay.h>
#include <linux/firmware.h>
#include <linux/interrupt.h>

#include <linux/mic_common.h>
#include "../common/mic_device.h"
#include "mic_device.h"
#include "mic_smpt.h"
#include "mic_virtio.h"

/**
 * mic_reset - Reset the MIC device.
@@ -117,6 +117,7 @@ void mic_stop(struct mic_device *mdev, bool force)
{
	mutex_lock(&mdev->mic_mutex);
	if (MIC_OFFLINE != mdev->state || force) {
		mic_virtio_reset_devices(mdev);
		mic_bootparam_init(mdev);
		mic_reset(mdev);
		if (MIC_RESET_FAILED == mdev->state)
+140 −0
Original line number Diff line number Diff line
@@ -26,6 +26,7 @@
#include "../common/mic_device.h"
#include "mic_device.h"
#include "mic_smpt.h"
#include "mic_virtio.h"

/* Debugfs parent dir */
static struct dentry *mic_dbg;
@@ -193,7 +194,13 @@ static const struct file_operations post_code_ops = {
static int mic_dp_show(struct seq_file *s, void *pos)
{
	struct mic_device *mdev = s->private;
	struct mic_device_desc *d;
	struct mic_device_ctrl *dc;
	struct mic_vqconfig *vqconfig;
	__u32 *features;
	__u8 *config;
	struct mic_bootparam *bootparam = mdev->dp;
	int i, j;

	seq_printf(s, "Bootparam: magic 0x%x\n",
		bootparam->magic);
@@ -208,6 +215,53 @@ static int mic_dp_show(struct seq_file *s, void *pos)
	seq_printf(s, "Bootparam: shutdown_card %d\n",
		bootparam->shutdown_card);

	for (i = sizeof(*bootparam); i < MIC_DP_SIZE;
	     i += mic_total_desc_size(d)) {
		d = mdev->dp + i;
		dc = (void *)d + mic_aligned_desc_size(d);

		/* end of list */
		if (d->type == 0)
			break;

		if (d->type == -1)
			continue;

		seq_printf(s, "Type %d ", d->type);
		seq_printf(s, "Num VQ %d ", d->num_vq);
		seq_printf(s, "Feature Len %d\n", d->feature_len);
		seq_printf(s, "Config Len %d ", d->config_len);
		seq_printf(s, "Shutdown Status %d\n", d->status);

		for (j = 0; j < d->num_vq; j++) {
			vqconfig = mic_vq_config(d) + j;
			seq_printf(s, "vqconfig[%d]: ", j);
			seq_printf(s, "address 0x%llx ", vqconfig->address);
			seq_printf(s, "num %d ", vqconfig->num);
			seq_printf(s, "used address 0x%llx\n",
				vqconfig->used_address);
		}

		features = (__u32 *) mic_vq_features(d);
		seq_printf(s, "Features: Host 0x%x ", features[0]);
		seq_printf(s, "Guest 0x%x\n", features[1]);

		config = mic_vq_configspace(d);
		for (j = 0; j < d->config_len; j++)
			seq_printf(s, "config[%d]=%d\n", j, config[j]);

		seq_puts(s, "Device control:\n");
		seq_printf(s, "Config Change %d ", dc->config_change);
		seq_printf(s, "Vdev reset %d\n", dc->vdev_reset);
		seq_printf(s, "Guest Ack %d ", dc->guest_ack);
		seq_printf(s, "Host ack %d\n", dc->host_ack);
		seq_printf(s, "Used address updated %d ",
			dc->used_address_updated);
		seq_printf(s, "Vdev 0x%llx\n", dc->vdev);
		seq_printf(s, "c2h doorbell %d ", dc->c2h_vdev_db);
		seq_printf(s, "h2c doorbell %d\n", dc->h2c_vdev_db);
	}

	return 0;
}

@@ -229,6 +283,89 @@ static const struct file_operations dp_ops = {
	.release = mic_dp_debug_release
};

static int mic_vdev_info_show(struct seq_file *s, void *unused)
{
	struct mic_device *mdev = s->private;
	struct list_head *pos, *tmp;
	struct mic_vdev *mvdev;
	int i, j;

	mutex_lock(&mdev->mic_mutex);
	list_for_each_safe(pos, tmp, &mdev->vdev_list) {
		mvdev = list_entry(pos, struct mic_vdev, list);
		seq_printf(s, "VDEV type %d state %s in %ld out %ld\n",
			mvdev->virtio_id,
			mic_vdevup(mvdev) ? "UP" : "DOWN",
			mvdev->in_bytes,
			mvdev->out_bytes);
		for (i = 0; i < MIC_MAX_VRINGS; i++) {
			struct vring_desc *desc;
			struct vring_avail *avail;
			struct vring_used *used;
			struct mic_vringh *mvr = &mvdev->mvr[i];
			struct vringh *vrh = &mvr->vrh;
			int num = vrh->vring.num;
			if (!num)
				continue;
			desc = vrh->vring.desc;
			seq_printf(s, "vring i %d avail_idx %d",
				i, mvr->vring.info->avail_idx & (num - 1));
			seq_printf(s, " vring i %d avail_idx %d\n",
				i, mvr->vring.info->avail_idx);
			seq_printf(s, "vrh i %d weak_barriers %d",
				i, vrh->weak_barriers);
			seq_printf(s, " last_avail_idx %d last_used_idx %d",
				vrh->last_avail_idx, vrh->last_used_idx);
			seq_printf(s, " completed %d\n", vrh->completed);
			for (j = 0; j < num; j++) {
				seq_printf(s, "desc[%d] addr 0x%llx len %d",
					j, desc->addr, desc->len);
				seq_printf(s, " flags 0x%x next %d\n",
					desc->flags,
					desc->next);
				desc++;
			}
			avail = vrh->vring.avail;
			seq_printf(s, "avail flags 0x%x idx %d\n",
				avail->flags, avail->idx & (num - 1));
			seq_printf(s, "avail flags 0x%x idx %d\n",
				avail->flags, avail->idx);
			for (j = 0; j < num; j++)
				seq_printf(s, "avail ring[%d] %d\n",
					j, avail->ring[j]);
			used = vrh->vring.used;
			seq_printf(s, "used flags 0x%x idx %d\n",
				used->flags, used->idx & (num - 1));
			seq_printf(s, "used flags 0x%x idx %d\n",
				used->flags, used->idx);
			for (j = 0; j < num; j++)
				seq_printf(s, "used ring[%d] id %d len %d\n",
					j, used->ring[j].id, used->ring[j].len);
		}
	}
	mutex_unlock(&mdev->mic_mutex);

	return 0;
}

static int mic_vdev_info_debug_open(struct inode *inode, struct file *file)
{
	return single_open(file, mic_vdev_info_show, inode->i_private);
}

static int mic_vdev_info_debug_release(struct inode *inode, struct file *file)
{
	return single_release(inode, file);
}

static const struct file_operations vdev_info_ops = {
	.owner   = THIS_MODULE,
	.open    = mic_vdev_info_debug_open,
	.read    = seq_read,
	.llseek  = seq_lseek,
	.release = mic_vdev_info_debug_release
};

static int mic_msi_irq_info_show(struct seq_file *s, void *pos)
{
	struct mic_device *mdev  = s->private;
@@ -321,6 +458,9 @@ void mic_create_debug_dir(struct mic_device *mdev)
	debugfs_create_file("dp", 0444, mdev->dbg_dir,
		mdev, &dp_ops);

	debugfs_create_file("vdev_info", 0444, mdev->dbg_dir,
		mdev, &vdev_info_ops);

	debugfs_create_file("msi_irq_info", 0444, mdev->dbg_dir,
		mdev, &msi_irq_info_ops);
}
Loading