From patchwork Mon Nov 4 12:39:47 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Jason Wang X-Patchwork-Id: 11225729 Return-Path: Received: from mail.kernel.org (pdx-korg-mail-1.web.codeaurora.org [172.30.200.123]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id B5DC513A4 for ; Mon, 4 Nov 2019 12:43:12 +0000 (UTC) Received: from gabe.freedesktop.org (gabe.freedesktop.org [131.252.210.177]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by mail.kernel.org (Postfix) with ESMTPS id 9DF1021D7D for ; Mon, 4 Nov 2019 12:43:12 +0000 (UTC) DMARC-Filter: OpenDMARC Filter v1.3.2 mail.kernel.org 9DF1021D7D Authentication-Results: mail.kernel.org; dmarc=fail (p=none dis=none) header.from=redhat.com Authentication-Results: mail.kernel.org; spf=none smtp.mailfrom=dri-devel-bounces@lists.freedesktop.org Received: from gabe.freedesktop.org (localhost [127.0.0.1]) by gabe.freedesktop.org (Postfix) with ESMTP id 57DAD6E3A4; Mon, 4 Nov 2019 12:43:10 +0000 (UTC) X-Original-To: dri-devel@lists.freedesktop.org Delivered-To: dri-devel@lists.freedesktop.org Received: from us-smtp-1.mimecast.com (us-smtp-delivery-1.mimecast.com [205.139.110.120]) by gabe.freedesktop.org (Postfix) with ESMTPS id EBFDD6E379 for ; Mon, 4 Nov 2019 12:43:08 +0000 (UTC) Received: from mimecast-mx01.redhat.com (mimecast-mx01.redhat.com [209.132.183.4]) (Using TLS) by relay.mimecast.com with ESMTP id us-mta-28-2G__RSVRPBKBWJJih5i-Fw-1; Mon, 04 Nov 2019 07:43:04 -0500 Received: from smtp.corp.redhat.com (int-mx02.intmail.prod.int.phx2.redhat.com [10.5.11.12]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by mimecast-mx01.redhat.com (Postfix) with ESMTPS id 67699800C73; Mon, 4 Nov 2019 12:43:00 +0000 (UTC) Received: from jason-ThinkPad-X1-Carbon-6th.redhat.com (ovpn-12-65.pek2.redhat.com [10.72.12.65]) by smtp.corp.redhat.com (Postfix) with ESMTP id EA45B60CD0; Mon, 4 Nov 2019 12:41:26 +0000 (UTC) From: Jason Wang To: kvm@vger.kernel.org, linux-s390@vger.kernel.org, linux-kernel@vger.kernel.org, dri-devel@lists.freedesktop.org, intel-gfx@lists.freedesktop.org, intel-gvt-dev@lists.freedesktop.org, kwankhede@nvidia.com, alex.williamson@redhat.com, mst@redhat.com, tiwei.bie@intel.com Subject: [PATCH V7 1/6] mdev: class id support Date: Mon, 4 Nov 2019 20:39:47 +0800 Message-Id: <20191104123952.17276-2-jasowang@redhat.com> In-Reply-To: <20191104123952.17276-1-jasowang@redhat.com> References: <20191104123952.17276-1-jasowang@redhat.com> MIME-Version: 1.0 X-Scanned-By: MIMEDefang 2.79 on 10.5.11.12 X-MC-Unique: 2G__RSVRPBKBWJJih5i-Fw-1 X-Mimecast-Spam-Score: 0 X-Mailman-Original-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1572871387; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version:content-type:content-type: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=j3uX4xKUPpnTCQ7S+H5OVBiI//DbCpSXZrAOsfut9UQ=; b=aRjZjkt+RtPAZP3H++M03wAzBCWTwvg0oEWkdiVheWZoTPUybZo4MycAt92fU8VL60WuGu Ijg//Zsy6A0qsT6kXvJ73TK23LZQHVHJAZ6mLVg0cgoacjcXGubNxbMjPG6ETPIe7ZfgDV m/wO/vZc+hH6aWSPNbxae3e7Dv+RO7I= X-BeenThere: dri-devel@lists.freedesktop.org X-Mailman-Version: 2.1.23 Precedence: list List-Id: Direct Rendering Infrastructure - Development List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: christophe.de.dinechin@gmail.com, sebott@linux.ibm.com, airlied@linux.ie, Jason Wang , heiko.carstens@de.ibm.com, kevin.tian@intel.com, virtualization@lists.linux-foundation.org, rob.miller@broadcom.com, lulu@redhat.com, eperezma@redhat.com, pasic@linux.ibm.com, borntraeger@de.ibm.com, haotian.wang@sifive.com, zhi.a.wang@intel.com, farman@linux.ibm.com, idos@mellanox.com, gor@linux.ibm.com, cunming.liang@intel.com, rodrigo.vivi@intel.com, xiao.w.wang@intel.com, freude@linux.ibm.com, parav@mellanox.com, zhihong.wang@intel.com, stefanha@redhat.com, akrowiak@linux.ibm.com, netdev@vger.kernel.org, cohuck@redhat.com, oberpar@linux.ibm.com, maxime.coquelin@redhat.com, lingshan.zhu@intel.com Errors-To: dri-devel-bounces@lists.freedesktop.org Sender: "dri-devel" Mdev bus only supports vfio driver right now, so it doesn't implement match method. But in the future, we may add drivers other than vfio, the first driver could be virtio-mdev. This means we need to add device class id support in bus match method to pair the mdev device and mdev driver correctly. So this patch adds id_table to mdev_driver and class_id for mdev device with the match method for mdev bus. Reviewed-by: Parav Pandit Signed-off-by: Jason Wang --- .../driver-api/vfio-mediated-device.rst | 5 ++++ drivers/gpu/drm/i915/gvt/kvmgt.c | 1 + drivers/s390/cio/vfio_ccw_ops.c | 1 + drivers/s390/crypto/vfio_ap_ops.c | 1 + drivers/vfio/mdev/mdev_core.c | 16 ++++++++++++ drivers/vfio/mdev/mdev_driver.c | 25 +++++++++++++++++++ drivers/vfio/mdev/mdev_private.h | 1 + drivers/vfio/mdev/vfio_mdev.c | 6 +++++ include/linux/mdev.h | 8 ++++++ include/linux/mod_devicetable.h | 8 ++++++ samples/vfio-mdev/mbochs.c | 1 + samples/vfio-mdev/mdpy.c | 1 + samples/vfio-mdev/mtty.c | 1 + 13 files changed, 75 insertions(+) diff --git a/Documentation/driver-api/vfio-mediated-device.rst b/Documentation/driver-api/vfio-mediated-device.rst index 25eb7d5b834b..6709413bee29 100644 --- a/Documentation/driver-api/vfio-mediated-device.rst +++ b/Documentation/driver-api/vfio-mediated-device.rst @@ -102,12 +102,14 @@ structure to represent a mediated device's driver:: * @probe: called when new device created * @remove: called when device removed * @driver: device driver structure + * @id_table: the ids serviced by this driver */ struct mdev_driver { const char *name; int (*probe) (struct device *dev); void (*remove) (struct device *dev); struct device_driver driver; + const struct mdev_class_id *id_table; }; A mediated bus driver for mdev should use this structure in the function calls @@ -170,6 +172,9 @@ that a driver should use to unregister itself with the mdev core driver:: extern void mdev_unregister_device(struct device *dev); +It is also required to specify the class_id in create() callback through:: + + int mdev_set_class(struct mdev_device *mdev, u16 id); Mediated Device Management Interface Through sysfs ================================================== diff --git a/drivers/gpu/drm/i915/gvt/kvmgt.c b/drivers/gpu/drm/i915/gvt/kvmgt.c index 343d79c1cb7e..6420f0dbd31b 100644 --- a/drivers/gpu/drm/i915/gvt/kvmgt.c +++ b/drivers/gpu/drm/i915/gvt/kvmgt.c @@ -678,6 +678,7 @@ static int intel_vgpu_create(struct kobject *kobj, struct mdev_device *mdev) dev_name(mdev_dev(mdev))); ret = 0; + mdev_set_class(mdev, MDEV_CLASS_ID_VFIO); out: return ret; } diff --git a/drivers/s390/cio/vfio_ccw_ops.c b/drivers/s390/cio/vfio_ccw_ops.c index f0d71ab77c50..cf2c013ae32f 100644 --- a/drivers/s390/cio/vfio_ccw_ops.c +++ b/drivers/s390/cio/vfio_ccw_ops.c @@ -129,6 +129,7 @@ static int vfio_ccw_mdev_create(struct kobject *kobj, struct mdev_device *mdev) private->sch->schid.ssid, private->sch->schid.sch_no); + mdev_set_class(mdev, MDEV_CLASS_ID_VFIO); return 0; } diff --git a/drivers/s390/crypto/vfio_ap_ops.c b/drivers/s390/crypto/vfio_ap_ops.c index 5c0f53c6dde7..07c31070afeb 100644 --- a/drivers/s390/crypto/vfio_ap_ops.c +++ b/drivers/s390/crypto/vfio_ap_ops.c @@ -343,6 +343,7 @@ static int vfio_ap_mdev_create(struct kobject *kobj, struct mdev_device *mdev) list_add(&matrix_mdev->node, &matrix_dev->mdev_list); mutex_unlock(&matrix_dev->lock); + mdev_set_class(mdev, MDEV_CLASS_ID_VFIO); return 0; } diff --git a/drivers/vfio/mdev/mdev_core.c b/drivers/vfio/mdev/mdev_core.c index b558d4cfd082..d23ca39e3be6 100644 --- a/drivers/vfio/mdev/mdev_core.c +++ b/drivers/vfio/mdev/mdev_core.c @@ -45,6 +45,16 @@ void mdev_set_drvdata(struct mdev_device *mdev, void *data) } EXPORT_SYMBOL(mdev_set_drvdata); +/* Specify the class for the mdev device, this must be called during + * create() callback. + */ +void mdev_set_class(struct mdev_device *mdev, u16 id) +{ + WARN_ON(mdev->class_id); + mdev->class_id = id; +} +EXPORT_SYMBOL(mdev_set_class); + struct device *mdev_dev(struct mdev_device *mdev) { return &mdev->dev; @@ -324,6 +334,12 @@ int mdev_device_create(struct kobject *kobj, if (ret) goto ops_create_fail; + if (!mdev->class_id) { + ret = -EINVAL; + dev_warn(dev, "mdev vendor driver failed to specify device class\n"); + goto add_fail; + } + ret = device_add(&mdev->dev); if (ret) goto add_fail; diff --git a/drivers/vfio/mdev/mdev_driver.c b/drivers/vfio/mdev/mdev_driver.c index 0d3223aee20b..ed06433693e8 100644 --- a/drivers/vfio/mdev/mdev_driver.c +++ b/drivers/vfio/mdev/mdev_driver.c @@ -69,8 +69,33 @@ static int mdev_remove(struct device *dev) return 0; } +static int mdev_match(struct device *dev, struct device_driver *drv) +{ + unsigned int i; + struct mdev_device *mdev = to_mdev_device(dev); + struct mdev_driver *mdrv = to_mdev_driver(drv); + const struct mdev_class_id *ids = mdrv->id_table; + + if (!ids) + return 0; + + for (i = 0; ids[i].id; i++) + if (ids[i].id == mdev->class_id) + return 1; + return 0; +} + +static int mdev_uevent(struct device *dev, struct kobj_uevent_env *env) +{ + struct mdev_device *mdev = to_mdev_device(dev); + + return add_uevent_var(env, "MODALIAS=mdev:c%02X", mdev->class_id); +} + struct bus_type mdev_bus_type = { .name = "mdev", + .match = mdev_match, + .uevent = mdev_uevent, .probe = mdev_probe, .remove = mdev_remove, }; diff --git a/drivers/vfio/mdev/mdev_private.h b/drivers/vfio/mdev/mdev_private.h index 7d922950caaf..c65f436c1869 100644 --- a/drivers/vfio/mdev/mdev_private.h +++ b/drivers/vfio/mdev/mdev_private.h @@ -33,6 +33,7 @@ struct mdev_device { struct kobject *type_kobj; struct device *iommu_device; bool active; + u16 class_id; }; #define to_mdev_device(dev) container_of(dev, struct mdev_device, dev) diff --git a/drivers/vfio/mdev/vfio_mdev.c b/drivers/vfio/mdev/vfio_mdev.c index 30964a4e0a28..38431e9ef7f5 100644 --- a/drivers/vfio/mdev/vfio_mdev.c +++ b/drivers/vfio/mdev/vfio_mdev.c @@ -120,10 +120,16 @@ static void vfio_mdev_remove(struct device *dev) vfio_del_group_dev(dev); } +static const struct mdev_class_id vfio_id_table[] = { + { MDEV_CLASS_ID_VFIO }, + { 0 }, +}; + static struct mdev_driver vfio_mdev_driver = { .name = "vfio_mdev", .probe = vfio_mdev_probe, .remove = vfio_mdev_remove, + .id_table = vfio_id_table, }; static int __init vfio_mdev_init(void) diff --git a/include/linux/mdev.h b/include/linux/mdev.h index 0ce30ca78db0..78b69d09eb54 100644 --- a/include/linux/mdev.h +++ b/include/linux/mdev.h @@ -118,6 +118,7 @@ struct mdev_type_attribute mdev_type_attr_##_name = \ * @probe: called when new device created * @remove: called when device removed * @driver: device driver structure + * @id_table: the ids serviced by this driver * **/ struct mdev_driver { @@ -125,6 +126,7 @@ struct mdev_driver { int (*probe)(struct device *dev); void (*remove)(struct device *dev); struct device_driver driver; + const struct mdev_class_id *id_table; }; #define to_mdev_driver(drv) container_of(drv, struct mdev_driver, driver) @@ -132,6 +134,7 @@ struct mdev_driver { void *mdev_get_drvdata(struct mdev_device *mdev); void mdev_set_drvdata(struct mdev_device *mdev, void *data); const guid_t *mdev_uuid(struct mdev_device *mdev); +void mdev_set_class(struct mdev_device *mdev, u16 id); extern struct bus_type mdev_bus_type; @@ -145,4 +148,9 @@ struct device *mdev_parent_dev(struct mdev_device *mdev); struct device *mdev_dev(struct mdev_device *mdev); struct mdev_device *mdev_from_dev(struct device *dev); +enum { + MDEV_CLASS_ID_VFIO = 1, + /* New entries must be added here */ +}; + #endif /* MDEV_H */ diff --git a/include/linux/mod_devicetable.h b/include/linux/mod_devicetable.h index 5714fd35a83c..f32c6e44fb1a 100644 --- a/include/linux/mod_devicetable.h +++ b/include/linux/mod_devicetable.h @@ -821,4 +821,12 @@ struct wmi_device_id { const void *context; }; +/** + * struct mdev_class_id - MDEV device class identifier + * @id: Used to identify a specific class of device, e.g vfio-mdev device. + */ +struct mdev_class_id { + __u16 id; +}; + #endif /* LINUX_MOD_DEVICETABLE_H */ diff --git a/samples/vfio-mdev/mbochs.c b/samples/vfio-mdev/mbochs.c index ac5c8c17b1ff..115bc5074656 100644 --- a/samples/vfio-mdev/mbochs.c +++ b/samples/vfio-mdev/mbochs.c @@ -561,6 +561,7 @@ static int mbochs_create(struct kobject *kobj, struct mdev_device *mdev) mbochs_reset(mdev); mbochs_used_mbytes += type->mbytes; + mdev_set_class(mdev, MDEV_CLASS_ID_VFIO); return 0; err_mem: diff --git a/samples/vfio-mdev/mdpy.c b/samples/vfio-mdev/mdpy.c index cc86bf6566e4..665614574d50 100644 --- a/samples/vfio-mdev/mdpy.c +++ b/samples/vfio-mdev/mdpy.c @@ -269,6 +269,7 @@ static int mdpy_create(struct kobject *kobj, struct mdev_device *mdev) mdpy_reset(mdev); mdpy_count++; + mdev_set_class(mdev, MDEV_CLASS_ID_VFIO); return 0; } diff --git a/samples/vfio-mdev/mtty.c b/samples/vfio-mdev/mtty.c index ce84a300a4da..90da12ff7fd9 100644 --- a/samples/vfio-mdev/mtty.c +++ b/samples/vfio-mdev/mtty.c @@ -755,6 +755,7 @@ static int mtty_create(struct kobject *kobj, struct mdev_device *mdev) list_add(&mdev_state->next, &mdev_devices_list); mutex_unlock(&mdev_list_lock); + mdev_set_class(mdev, MDEV_CLASS_ID_VFIO); return 0; } From patchwork Mon Nov 4 12:39:48 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Jason Wang X-Patchwork-Id: 11225737 Return-Path: Received: from mail.kernel.org (pdx-korg-mail-1.web.codeaurora.org [172.30.200.123]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id 9FDFB15AB for ; Mon, 4 Nov 2019 12:44:07 +0000 (UTC) Received: from gabe.freedesktop.org (gabe.freedesktop.org [131.252.210.177]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by mail.kernel.org (Postfix) with ESMTPS id 879AE22477 for ; Mon, 4 Nov 2019 12:44:07 +0000 (UTC) DMARC-Filter: OpenDMARC Filter v1.3.2 mail.kernel.org 879AE22477 Authentication-Results: mail.kernel.org; dmarc=fail (p=none dis=none) header.from=redhat.com Authentication-Results: mail.kernel.org; spf=none smtp.mailfrom=dri-devel-bounces@lists.freedesktop.org Received: from gabe.freedesktop.org (localhost [127.0.0.1]) by gabe.freedesktop.org (Postfix) with ESMTP id 665436E3A8; Mon, 4 Nov 2019 12:44:06 +0000 (UTC) X-Original-To: dri-devel@lists.freedesktop.org Delivered-To: dri-devel@lists.freedesktop.org Received: from us-smtp-delivery-1.mimecast.com (us-smtp-2.mimecast.com [205.139.110.61]) by gabe.freedesktop.org (Postfix) with ESMTPS id 6A8816E379 for ; Mon, 4 Nov 2019 12:44:04 +0000 (UTC) Received: from mimecast-mx01.redhat.com (mimecast-mx01.redhat.com [209.132.183.4]) (Using TLS) by relay.mimecast.com with ESMTP id us-mta-28-vRISspVuMJ6kcJukeiQ94w-1; Mon, 04 Nov 2019 07:43:57 -0500 Received: from smtp.corp.redhat.com (int-mx02.intmail.prod.int.phx2.redhat.com [10.5.11.12]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by mimecast-mx01.redhat.com (Postfix) with ESMTPS id 738DC1005500; Mon, 4 Nov 2019 12:43:53 +0000 (UTC) Received: from jason-ThinkPad-X1-Carbon-6th.redhat.com (ovpn-12-65.pek2.redhat.com [10.72.12.65]) by smtp.corp.redhat.com (Postfix) with ESMTP id 2DDB060CD0; Mon, 4 Nov 2019 12:43:00 +0000 (UTC) From: Jason Wang To: kvm@vger.kernel.org, linux-s390@vger.kernel.org, linux-kernel@vger.kernel.org, dri-devel@lists.freedesktop.org, intel-gfx@lists.freedesktop.org, intel-gvt-dev@lists.freedesktop.org, kwankhede@nvidia.com, alex.williamson@redhat.com, mst@redhat.com, tiwei.bie@intel.com Subject: [PATCH V7 2/6] modpost: add support for mdev class id Date: Mon, 4 Nov 2019 20:39:48 +0800 Message-Id: <20191104123952.17276-3-jasowang@redhat.com> In-Reply-To: <20191104123952.17276-1-jasowang@redhat.com> References: <20191104123952.17276-1-jasowang@redhat.com> MIME-Version: 1.0 X-Scanned-By: MIMEDefang 2.79 on 10.5.11.12 X-MC-Unique: vRISspVuMJ6kcJukeiQ94w-1 X-Mimecast-Spam-Score: 0 X-Mailman-Original-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1572871443; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version:content-type:content-type: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=kyIvhY3BXMqZ4TEtR3KTmpEF86AeFHO8xa0fKWzJeAE=; b=hQx3J7wwzZYathJFMs1CPLKp1dRrrstUaIudRdC+DnrIXwucqXpAi+Y6Ek/jH2RPqDeUfZ MyEzihIjzH5I+gTCnwjoEJ9QwLuGsdfkaf31ajfnv8mj1LB9IbV4ab+9Ph6vsKIRKzx/+z WaSzWT6q+c4a31yuuV61/pZvoJfketk= X-BeenThere: dri-devel@lists.freedesktop.org X-Mailman-Version: 2.1.23 Precedence: list List-Id: Direct Rendering Infrastructure - Development List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: christophe.de.dinechin@gmail.com, sebott@linux.ibm.com, airlied@linux.ie, Jason Wang , heiko.carstens@de.ibm.com, kevin.tian@intel.com, virtualization@lists.linux-foundation.org, rob.miller@broadcom.com, lulu@redhat.com, eperezma@redhat.com, pasic@linux.ibm.com, borntraeger@de.ibm.com, haotian.wang@sifive.com, zhi.a.wang@intel.com, farman@linux.ibm.com, idos@mellanox.com, gor@linux.ibm.com, cunming.liang@intel.com, rodrigo.vivi@intel.com, xiao.w.wang@intel.com, freude@linux.ibm.com, parav@mellanox.com, zhihong.wang@intel.com, stefanha@redhat.com, akrowiak@linux.ibm.com, netdev@vger.kernel.org, cohuck@redhat.com, oberpar@linux.ibm.com, maxime.coquelin@redhat.com, lingshan.zhu@intel.com Errors-To: dri-devel-bounces@lists.freedesktop.org Sender: "dri-devel" Add support to parse mdev class id table. Reviewed-by: Parav Pandit Signed-off-by: Jason Wang --- drivers/vfio/mdev/vfio_mdev.c | 2 ++ scripts/mod/devicetable-offsets.c | 3 +++ scripts/mod/file2alias.c | 11 +++++++++++ 3 files changed, 16 insertions(+) diff --git a/drivers/vfio/mdev/vfio_mdev.c b/drivers/vfio/mdev/vfio_mdev.c index 38431e9ef7f5..a6641cd8b5a3 100644 --- a/drivers/vfio/mdev/vfio_mdev.c +++ b/drivers/vfio/mdev/vfio_mdev.c @@ -125,6 +125,8 @@ static const struct mdev_class_id vfio_id_table[] = { { 0 }, }; +MODULE_DEVICE_TABLE(mdev, vfio_id_table); + static struct mdev_driver vfio_mdev_driver = { .name = "vfio_mdev", .probe = vfio_mdev_probe, diff --git a/scripts/mod/devicetable-offsets.c b/scripts/mod/devicetable-offsets.c index 054405b90ba4..6cbb1062488a 100644 --- a/scripts/mod/devicetable-offsets.c +++ b/scripts/mod/devicetable-offsets.c @@ -231,5 +231,8 @@ int main(void) DEVID(wmi_device_id); DEVID_FIELD(wmi_device_id, guid_string); + DEVID(mdev_class_id); + DEVID_FIELD(mdev_class_id, id); + return 0; } diff --git a/scripts/mod/file2alias.c b/scripts/mod/file2alias.c index c91eba751804..45f1c22f49be 100644 --- a/scripts/mod/file2alias.c +++ b/scripts/mod/file2alias.c @@ -1335,6 +1335,16 @@ static int do_wmi_entry(const char *filename, void *symval, char *alias) return 1; } +/* looks like: "mdev:cN" */ +static int do_mdev_entry(const char *filename, void *symval, char *alias) +{ + DEF_FIELD(symval, mdev_class_id, id); + + sprintf(alias, "mdev:c%02X", id); + add_wildcard(alias); + return 1; +} + /* Does namelen bytes of name exactly match the symbol? */ static bool sym_is(const char *name, unsigned namelen, const char *symbol) { @@ -1407,6 +1417,7 @@ static const struct devtable devtable[] = { {"typec", SIZE_typec_device_id, do_typec_entry}, {"tee", SIZE_tee_client_device_id, do_tee_entry}, {"wmi", SIZE_wmi_device_id, do_wmi_entry}, + {"mdev", SIZE_mdev_class_id, do_mdev_entry}, }; /* Create MODULE_ALIAS() statements. From patchwork Mon Nov 4 12:39:52 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Jason Wang X-Patchwork-Id: 11225753 Return-Path: Received: from mail.kernel.org (pdx-korg-mail-1.web.codeaurora.org [172.30.200.123]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id D42021390 for ; Mon, 4 Nov 2019 12:50:40 +0000 (UTC) Received: from gabe.freedesktop.org (gabe.freedesktop.org [131.252.210.177]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by mail.kernel.org (Postfix) with ESMTPS id BBBCA218BA for ; Mon, 4 Nov 2019 12:50:40 +0000 (UTC) DMARC-Filter: OpenDMARC Filter v1.3.2 mail.kernel.org BBBCA218BA Authentication-Results: mail.kernel.org; dmarc=fail (p=none dis=none) header.from=redhat.com Authentication-Results: mail.kernel.org; spf=none smtp.mailfrom=dri-devel-bounces@lists.freedesktop.org Received: from gabe.freedesktop.org (localhost [127.0.0.1]) by gabe.freedesktop.org (Postfix) with ESMTP id 6AAE66E3BC; Mon, 4 Nov 2019 12:50:38 +0000 (UTC) X-Original-To: dri-devel@lists.freedesktop.org Delivered-To: dri-devel@lists.freedesktop.org Received: from us-smtp-1.mimecast.com (us-smtp-delivery-1.mimecast.com [205.139.110.120]) by gabe.freedesktop.org (Postfix) with ESMTPS id 153FC6E3C1 for ; Mon, 4 Nov 2019 12:50:36 +0000 (UTC) Received: from mimecast-mx01.redhat.com (mimecast-mx01.redhat.com [209.132.183.4]) (Using TLS) by relay.mimecast.com with ESMTP id us-mta-78-XePKxd0ZOQmD0VAcDLvKwQ-1; Mon, 04 Nov 2019 07:50:26 -0500 Received: from smtp.corp.redhat.com (int-mx02.intmail.prod.int.phx2.redhat.com [10.5.11.12]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by mimecast-mx01.redhat.com (Postfix) with ESMTPS id 2CBD4800C73; Mon, 4 Nov 2019 12:50:22 +0000 (UTC) Received: from jason-ThinkPad-X1-Carbon-6th.redhat.com (ovpn-12-65.pek2.redhat.com [10.72.12.65]) by smtp.corp.redhat.com (Postfix) with ESMTP id 1FED260CD0; Mon, 4 Nov 2019 12:48:33 +0000 (UTC) From: Jason Wang To: kvm@vger.kernel.org, linux-s390@vger.kernel.org, linux-kernel@vger.kernel.org, dri-devel@lists.freedesktop.org, intel-gfx@lists.freedesktop.org, intel-gvt-dev@lists.freedesktop.org, kwankhede@nvidia.com, alex.williamson@redhat.com, mst@redhat.com, tiwei.bie@intel.com Subject: [PATCH V7 6/6] docs: sample driver to demonstrate how to implement virtio-mdev framework Date: Mon, 4 Nov 2019 20:39:52 +0800 Message-Id: <20191104123952.17276-7-jasowang@redhat.com> In-Reply-To: <20191104123952.17276-1-jasowang@redhat.com> References: <20191104123952.17276-1-jasowang@redhat.com> MIME-Version: 1.0 X-Scanned-By: MIMEDefang 2.79 on 10.5.11.12 X-MC-Unique: XePKxd0ZOQmD0VAcDLvKwQ-1 X-Mimecast-Spam-Score: 0 X-Mailman-Original-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1572871836; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version:content-type:content-type: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=TkiuDRWB1+5F9idWLlyseLcRx9kvyKP88HZ/eSVlgQ8=; b=A3FmZ9CrMHunj2WF2rU698EjtjngUqIc9cTeMA3O3kTfykbtEzO5w2KMIChqOMgBrBiwWM quYqIEjSKTJEG2Iy07W2wmEjc1ydRVRHeL8Z8EhWAc2Dcu8PKtb2JEHi8r+gHcWjEPKiYI 3/S2NQZAueJ79SsssMioRLiX0YrRKqs= X-BeenThere: dri-devel@lists.freedesktop.org X-Mailman-Version: 2.1.23 Precedence: list List-Id: Direct Rendering Infrastructure - Development List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: christophe.de.dinechin@gmail.com, sebott@linux.ibm.com, airlied@linux.ie, Jason Wang , heiko.carstens@de.ibm.com, kevin.tian@intel.com, virtualization@lists.linux-foundation.org, rob.miller@broadcom.com, lulu@redhat.com, eperezma@redhat.com, pasic@linux.ibm.com, borntraeger@de.ibm.com, haotian.wang@sifive.com, zhi.a.wang@intel.com, farman@linux.ibm.com, idos@mellanox.com, gor@linux.ibm.com, cunming.liang@intel.com, rodrigo.vivi@intel.com, xiao.w.wang@intel.com, freude@linux.ibm.com, parav@mellanox.com, zhihong.wang@intel.com, stefanha@redhat.com, akrowiak@linux.ibm.com, netdev@vger.kernel.org, cohuck@redhat.com, oberpar@linux.ibm.com, maxime.coquelin@redhat.com, lingshan.zhu@intel.com Errors-To: dri-devel-bounces@lists.freedesktop.org Sender: "dri-devel" This sample driver creates mdev device that simulate virtio net device over virtio mdev transport. The device is implemented through vringh and workqueue. A device specific dma ops is to make sure HVA is used directly as the IOVA. This should be sufficient for kernel virtio driver to work. Only 'virtio' type is supported right now. I plan to add 'vhost' type on top which requires some virtual IOMMU implemented in this sample driver. Signed-off-by: Jason Wang --- MAINTAINERS | 1 + samples/Kconfig | 7 + samples/vfio-mdev/Makefile | 1 + samples/vfio-mdev/mvnet.c | 691 +++++++++++++++++++++++++++++++++++++ 4 files changed, 700 insertions(+) create mode 100644 samples/vfio-mdev/mvnet.c diff --git a/MAINTAINERS b/MAINTAINERS index f661d13344d6..35e9204d5c68 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -17248,6 +17248,7 @@ F: include/linux/virtio*.h F: include/uapi/linux/virtio_*.h F: drivers/crypto/virtio/ F: mm/balloon_compaction.c +F: samples/vfio-mdev/mvnet.c VIRTIO BLOCK AND SCSI DRIVERS M: "Michael S. Tsirkin" diff --git a/samples/Kconfig b/samples/Kconfig index c8dacb4dda80..a1a1ca2c00b7 100644 --- a/samples/Kconfig +++ b/samples/Kconfig @@ -131,6 +131,13 @@ config SAMPLE_VFIO_MDEV_MDPY mediated device. It is a simple framebuffer and supports the region display interface (VFIO_GFX_PLANE_TYPE_REGION). +config SAMPLE_VIRTIO_MDEV_NET + tristate "Build virtio mdev net example mediated device sample code -- loadable modules only" + depends on VIRTIO_MDEV_DEVICE && VHOST_RING && m + help + Build a networking sample device for use as a virtio + mediated device. + config SAMPLE_VFIO_MDEV_MDPY_FB tristate "Build VFIO mdpy example guest fbdev driver -- loadable module only" depends on FB && m diff --git a/samples/vfio-mdev/Makefile b/samples/vfio-mdev/Makefile index 10d179c4fdeb..f34af90ed0a0 100644 --- a/samples/vfio-mdev/Makefile +++ b/samples/vfio-mdev/Makefile @@ -3,3 +3,4 @@ obj-$(CONFIG_SAMPLE_VFIO_MDEV_MTTY) += mtty.o obj-$(CONFIG_SAMPLE_VFIO_MDEV_MDPY) += mdpy.o obj-$(CONFIG_SAMPLE_VFIO_MDEV_MDPY_FB) += mdpy-fb.o obj-$(CONFIG_SAMPLE_VFIO_MDEV_MBOCHS) += mbochs.o +obj-$(CONFIG_SAMPLE_VIRTIO_MDEV_NET) += mvnet.o diff --git a/samples/vfio-mdev/mvnet.c b/samples/vfio-mdev/mvnet.c new file mode 100644 index 000000000000..e8d84462ae47 --- /dev/null +++ b/samples/vfio-mdev/mvnet.c @@ -0,0 +1,691 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Mediated virtual virtio-net device driver. + * + * Copyright (c) 2019, Red Hat Inc. All rights reserved. + * Author: Jason Wang + * + * Sample driver that creates mdev device that simulates ethernet loopback + * device. + * + * Usage: + * + * # modprobe virtio_mdev + * # modprobe mvnet + * # cd /sys/devices/virtual/mvnet/mvnet/mdev_supported_types/mvnet-virtio + * # echo "83b8f4f2-509f-382f-3c1e-e6bfe0fa1001" > ./create + * # cd devices/83b8f4f2-509f-382f-3c1e-e6bfe0fa1001 + * # ls -d virtio0 + * virtio0 + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define VERSION_STRING "0.1" +#define DRIVER_AUTHOR "Red Hat Corporation" + +#define MVNET_CLASS_NAME "mvnet" +#define MVNET_NAME "mvnet" + +/* + * Global Structures + */ + +static struct mvnet_dev { + struct class *vd_class; + struct idr vd_idr; + struct device dev; +} mvnet_dev; + +struct mvnet_virtqueue { + struct vringh vring; + struct vringh_kiov iov; + unsigned short head; + bool ready; + u64 desc_addr; + u64 device_addr; + u64 driver_addr; + u32 num; + void *private; + irqreturn_t (*cb)(void *data); +}; + +#define MVNET_QUEUE_ALIGN PAGE_SIZE +#define MVNET_QUEUE_MAX 256 +#define MVNET_DEVICE_ID 0x1 +#define MVNET_VENDOR_ID 0 + +u64 mvnet_features = (1ULL << VIRTIO_F_ANY_LAYOUT) | + (1ULL << VIRTIO_F_VERSION_1) | + (1ULL << VIRTIO_F_IOMMU_PLATFORM); + +/* State of each mdev device */ +struct mvnet_state { + struct mvnet_virtqueue vqs[2]; + struct work_struct work; + spinlock_t lock; + struct mdev_device *mdev; + struct virtio_net_config config; + void *buffer; + u32 status; + u32 generation; + u64 features; + struct list_head next; +}; + +static struct mutex mdev_list_lock; +static struct list_head mdev_devices_list; + +static void mvnet_queue_ready(struct mvnet_state *mvnet, unsigned int idx) +{ + struct mvnet_virtqueue *vq = &mvnet->vqs[idx]; + int ret; + + ret = vringh_init_kern(&vq->vring, mvnet_features, MVNET_QUEUE_MAX, + false, (struct vring_desc *)vq->desc_addr, + (struct vring_avail *)vq->driver_addr, + (struct vring_used *)vq->device_addr); +} + +static void mvnet_vq_reset(struct mvnet_virtqueue *vq) +{ + vq->ready = 0; + vq->desc_addr = 0; + vq->driver_addr = 0; + vq->device_addr = 0; + vq->cb = NULL; + vq->private = NULL; + vringh_init_kern(&vq->vring, mvnet_features, MVNET_QUEUE_MAX, + false, 0, 0, 0); +} + +static void mvnet_reset(struct mvnet_state *mvnet) +{ + int i; + + for (i = 0; i < 2; i++) + mvnet_vq_reset(&mvnet->vqs[i]); + + mvnet->features = 0; + mvnet->status = 0; + ++mvnet->generation; +} + +static void mvnet_work(struct work_struct *work) +{ + struct mvnet_state *mvnet = container_of(work, struct + mvnet_state, work); + struct mvnet_virtqueue *txq = &mvnet->vqs[1]; + struct mvnet_virtqueue *rxq = &mvnet->vqs[0]; + size_t read, write, total_write; + int err; + int pkts = 0; + + spin_lock(&mvnet->lock); + + if (!txq->ready || !rxq->ready) + goto out; + + while (true) { + total_write = 0; + err = vringh_getdesc_kern(&txq->vring, &txq->iov, NULL, + &txq->head, GFP_ATOMIC); + if (err <= 0) + break; + + err = vringh_getdesc_kern(&rxq->vring, NULL, &rxq->iov, + &rxq->head, GFP_ATOMIC); + if (err <= 0) { + vringh_complete_kern(&txq->vring, txq->head, 0); + break; + } + + while (true) { + read = vringh_iov_pull_kern(&txq->iov, mvnet->buffer, + PAGE_SIZE); + if (read <= 0) + break; + + write = vringh_iov_push_kern(&rxq->iov, mvnet->buffer, + read); + if (write <= 0) + break; + + total_write += write; + } + + /* Make sure data is wrote before advancing index */ + smp_wmb(); + + vringh_complete_kern(&txq->vring, txq->head, 0); + vringh_complete_kern(&rxq->vring, rxq->head, total_write); + + /* Make sure used is visible before rasing the interrupt. */ + smp_wmb(); + + local_bh_disable(); + if (txq->cb) + txq->cb(txq->private); + if (rxq->cb) + rxq->cb(rxq->private); + local_bh_enable(); + + if (++pkts > 4) { + schedule_work(&mvnet->work); + goto out; + } + } + +out: + spin_unlock(&mvnet->lock); +} + +static dma_addr_t mvnet_map_page(struct device *dev, struct page *page, + unsigned long offset, size_t size, + enum dma_data_direction dir, + unsigned long attrs) +{ + /* Vringh can only use HVA */ + return (dma_addr_t)(page_address(page) + offset); +} + +static void mvnet_unmap_page(struct device *dev, dma_addr_t dma_addr, + size_t size, enum dma_data_direction dir, + unsigned long attrs) +{ +} + +static void *mvnet_alloc_coherent(struct device *dev, size_t size, + dma_addr_t *dma_addr, gfp_t flag, + unsigned long attrs) +{ + void *addr = kmalloc(size, flag); + + if (addr == NULL) + *dma_addr = DMA_MAPPING_ERROR; + else + *dma_addr = (dma_addr_t) addr; + + return addr; +} + +static void mvnet_free_coherent(struct device *dev, size_t size, + void *vaddr, dma_addr_t dma_addr, + unsigned long attrs) +{ + kfree((void *)dma_addr); +} + +static const struct dma_map_ops mvnet_dma_ops = { + .map_page = mvnet_map_page, + .unmap_page = mvnet_unmap_page, + .alloc = mvnet_alloc_coherent, + .free = mvnet_free_coherent, +}; + +static const struct mdev_virtio_device_ops mdev_virtio_ops; + +static int mvnet_create(struct kobject *kobj, struct mdev_device *mdev) +{ + struct mvnet_state *mvnet; + struct virtio_net_config *config; + struct device *dev = mdev_dev(mdev); + + if (!mdev) + return -EINVAL; + + mvnet = kzalloc(sizeof(struct mvnet_state), GFP_KERNEL); + if (mvnet == NULL) + return -ENOMEM; + + mvnet->buffer = kmalloc(PAGE_SIZE, GFP_KERNEL); + if (!mvnet->buffer) { + kfree(mvnet); + return -ENOMEM; + } + + config = &mvnet->config; + config->mtu = 1500; + config->status = VIRTIO_NET_S_LINK_UP; + eth_random_addr(config->mac); + + INIT_WORK(&mvnet->work, mvnet_work); + + spin_lock_init(&mvnet->lock); + mvnet->mdev = mdev; + mdev_set_drvdata(mdev, mvnet); + + mutex_lock(&mdev_list_lock); + list_add(&mvnet->next, &mdev_devices_list); + mutex_unlock(&mdev_list_lock); + + dev->coherent_dma_mask = DMA_BIT_MASK(64); + set_dma_ops(dev, &mvnet_dma_ops); + + mdev_set_virtio_ops(mdev, &mdev_virtio_ops); + + return 0; +} + +static int mvnet_remove(struct mdev_device *mdev) +{ + struct mvnet_state *mds, *tmp_mds; + struct mvnet_state *mvnet = mdev_get_drvdata(mdev); + int ret = -EINVAL; + + mutex_lock(&mdev_list_lock); + list_for_each_entry_safe(mds, tmp_mds, &mdev_devices_list, next) { + if (mvnet == mds) { + list_del(&mvnet->next); + mdev_set_drvdata(mdev, NULL); + kfree(mvnet->buffer); + kfree(mvnet); + ret = 0; + break; + } + } + mutex_unlock(&mdev_list_lock); + + return ret; +} + +static ssize_t +sample_mvnet_dev_show(struct device *dev, struct device_attribute *attr, + char *buf) +{ + if (mdev_from_dev(dev)) + return sprintf(buf, "This is MDEV %s\n", dev_name(dev)); + + return sprintf(buf, "\n"); +} + +static DEVICE_ATTR_RO(sample_mvnet_dev); + +static struct attribute *mvnet_dev_attrs[] = { + &dev_attr_sample_mvnet_dev.attr, + NULL, +}; + +static const struct attribute_group mvnet_dev_group = { + .name = "mvnet_dev", + .attrs = mvnet_dev_attrs, +}; + +static const struct attribute_group *mvnet_dev_groups[] = { + &mvnet_dev_group, + NULL, +}; + +static ssize_t +sample_mdev_dev_show(struct device *dev, struct device_attribute *attr, + char *buf) +{ + if (mdev_from_dev(dev)) + return sprintf(buf, "This is MDEV %s\n", dev_name(dev)); + + return sprintf(buf, "\n"); +} + +static DEVICE_ATTR_RO(sample_mdev_dev); + +static struct attribute *mdev_dev_attrs[] = { + &dev_attr_sample_mdev_dev.attr, + NULL, +}; + +static const struct attribute_group mdev_dev_group = { + .name = "vendor", + .attrs = mdev_dev_attrs, +}; + +static const struct attribute_group *mdev_dev_groups[] = { + &mdev_dev_group, + NULL, +}; + +#define MVNET_STRING_LEN 16 + +static ssize_t +name_show(struct kobject *kobj, struct device *dev, char *buf) +{ + char name[MVNET_STRING_LEN]; + const char *name_str = "virtio-net"; + + snprintf(name, MVNET_STRING_LEN, "%s", dev_driver_string(dev)); + if (!strcmp(kobj->name, name)) + return sprintf(buf, "%s\n", name_str); + + return -EINVAL; +} + +static MDEV_TYPE_ATTR_RO(name); + +static ssize_t +available_instances_show(struct kobject *kobj, struct device *dev, char *buf) +{ + return sprintf(buf, "%d\n", INT_MAX); +} + +static MDEV_TYPE_ATTR_RO(available_instances); + +static ssize_t device_api_show(struct kobject *kobj, struct device *dev, + char *buf) +{ + return sprintf(buf, "%s\n", VIRTIO_MDEV_DEVICE_API_STRING); +} + +static MDEV_TYPE_ATTR_RO(device_api); + +static struct attribute *mdev_types_attrs[] = { + &mdev_type_attr_name.attr, + &mdev_type_attr_device_api.attr, + &mdev_type_attr_available_instances.attr, + NULL, +}; + +static struct attribute_group mdev_type_group = { + .name = "virtio", + .attrs = mdev_types_attrs, +}; + +/* TBD: "vhost" type */ + +static struct attribute_group *mdev_type_groups[] = { + &mdev_type_group, + NULL, +}; + +static int mvnet_set_vq_address(struct mdev_device *mdev, u16 idx, + u64 desc_area, u64 driver_area, u64 device_area) +{ + struct mvnet_state *mvnet = mdev_get_drvdata(mdev); + struct mvnet_virtqueue *vq = &mvnet->vqs[idx]; + + vq->desc_addr = desc_area; + vq->driver_addr = driver_area; + vq->device_addr = device_area; + + return 0; +} + +static void mvnet_set_vq_num(struct mdev_device *mdev, u16 idx, u32 num) +{ + struct mvnet_state *mvnet = mdev_get_drvdata(mdev); + struct mvnet_virtqueue *vq = &mvnet->vqs[idx]; + + vq->num = num; +} + +static void mvnet_kick_vq(struct mdev_device *mdev, u16 idx) +{ + struct mvnet_state *mvnet = mdev_get_drvdata(mdev); + struct mvnet_virtqueue *vq = &mvnet->vqs[idx]; + + if (vq->ready) + schedule_work(&mvnet->work); +} + +static void mvnet_set_vq_cb(struct mdev_device *mdev, u16 idx, + struct virtio_mdev_callback *cb) +{ + struct mvnet_state *mvnet = mdev_get_drvdata(mdev); + struct mvnet_virtqueue *vq = &mvnet->vqs[idx]; + + vq->cb = cb->callback; + vq->private = cb->private; +} + +static void mvnet_set_vq_ready(struct mdev_device *mdev, u16 idx, bool ready) +{ + struct mvnet_state *mvnet = mdev_get_drvdata(mdev); + struct mvnet_virtqueue *vq = &mvnet->vqs[idx]; + + spin_lock(&mvnet->lock); + vq->ready = ready; + if (vq->ready) + mvnet_queue_ready(mvnet, idx); + spin_unlock(&mvnet->lock); +} + +static bool mvnet_get_vq_ready(struct mdev_device *mdev, u16 idx) +{ + struct mvnet_state *mvnet = mdev_get_drvdata(mdev); + struct mvnet_virtqueue *vq = &mvnet->vqs[idx]; + + return vq->ready; +} + +static int mvnet_set_vq_state(struct mdev_device *mdev, u16 idx, u64 state) +{ + struct mvnet_state *mvnet = mdev_get_drvdata(mdev); + struct mvnet_virtqueue *vq = &mvnet->vqs[idx]; + struct vringh *vrh = &vq->vring; + + spin_lock(&mvnet->lock); + vrh->last_avail_idx = state; + spin_unlock(&mvnet->lock); + + return 0; +} + +static u64 mvnet_get_vq_state(struct mdev_device *mdev, u16 idx) +{ + struct mvnet_state *mvnet = mdev_get_drvdata(mdev); + struct mvnet_virtqueue *vq = &mvnet->vqs[idx]; + struct vringh *vrh = &vq->vring; + + return vrh->last_avail_idx; +} + +static u16 mvnet_get_vq_align(struct mdev_device *mdev) +{ + return MVNET_QUEUE_ALIGN; +} + +static u64 mvnet_get_features(struct mdev_device *mdev) +{ + return mvnet_features; +} + +static int mvnet_set_features(struct mdev_device *mdev, u64 features) +{ + struct mvnet_state *mvnet = mdev_get_drvdata(mdev); + + /* DMA mapping must be done by driver */ + if (!(features & (1ULL << VIRTIO_F_IOMMU_PLATFORM))) + return -EINVAL; + + mvnet->features = features & mvnet_features; + + return 0; +} + +static void mvnet_set_config_cb(struct mdev_device *mdev, + struct virtio_mdev_callback *cb) +{ + /* We don't support config interrupt */ +} + +static u16 mvnet_get_vq_num_max(struct mdev_device *mdev) +{ + return MVNET_QUEUE_MAX; +} + +static u32 mvnet_get_device_id(struct mdev_device *mdev) +{ + return MVNET_DEVICE_ID; +} + +static u32 mvnet_get_vendor_id(struct mdev_device *mdev) +{ + return MVNET_VENDOR_ID; +} + +static u8 mvnet_get_status(struct mdev_device *mdev) +{ + struct mvnet_state *mvnet = mdev_get_drvdata(mdev); + + return mvnet->status; +} + +static void mvnet_set_status(struct mdev_device *mdev, u8 status) +{ + struct mvnet_state *mvnet = mdev_get_drvdata(mdev); + + mvnet->status = status; + + if (status == 0) { + spin_lock(&mvnet->lock); + mvnet_reset(mvnet); + spin_unlock(&mvnet->lock); + } +} + +static void mvnet_get_config(struct mdev_device *mdev, unsigned int offset, + void *buf, unsigned int len) +{ + struct mvnet_state *mvnet = mdev_get_drvdata(mdev); + + if (offset + len < sizeof(struct virtio_net_config)) + memcpy(buf, &mvnet->config + offset, len); +} + +static void mvnet_set_config(struct mdev_device *mdev, unsigned int offset, + const void *buf, unsigned int len) +{ + /* No writable config supportted by mvnet */ +} + +static u64 mvnet_get_mdev_features(struct mdev_device *mdev) +{ + return VIRTIO_MDEV_F_VERSION_1; +} + +static u32 mvnet_get_generation(struct mdev_device *mdev) +{ + struct mvnet_state *mvnet = mdev_get_drvdata(mdev); + + return mvnet->generation; +} + +static const struct mdev_virtio_device_ops mdev_virtio_ops = { + .set_vq_address = mvnet_set_vq_address, + .set_vq_num = mvnet_set_vq_num, + .kick_vq = mvnet_kick_vq, + .set_vq_cb = mvnet_set_vq_cb, + .set_vq_ready = mvnet_set_vq_ready, + .get_vq_ready = mvnet_get_vq_ready, + .set_vq_state = mvnet_set_vq_state, + .get_vq_state = mvnet_get_vq_state, + .get_vq_align = mvnet_get_vq_align, + .get_features = mvnet_get_features, + .set_features = mvnet_set_features, + .set_config_cb = mvnet_set_config_cb, + .get_vq_num_max = mvnet_get_vq_num_max, + .get_device_id = mvnet_get_device_id, + .get_vendor_id = mvnet_get_vendor_id, + .get_status = mvnet_get_status, + .set_status = mvnet_set_status, + .get_config = mvnet_get_config, + .set_config = mvnet_set_config, + .get_mdev_features = mvnet_get_mdev_features, + .get_generation = mvnet_get_generation, +}; + +static const struct mdev_parent_ops mdev_fops = { + .owner = THIS_MODULE, + .dev_attr_groups = mvnet_dev_groups, + .mdev_attr_groups = mdev_dev_groups, + .supported_type_groups = mdev_type_groups, + .create = mvnet_create, + .remove = mvnet_remove, +}; + +static void mvnet_device_release(struct device *dev) +{ + dev_dbg(dev, "mvnet: released\n"); +} + +static int __init mvnet_dev_init(void) +{ + int ret = 0; + + pr_info("mvnet_dev: %s\n", __func__); + + memset(&mvnet_dev, 0, sizeof(mvnet_dev)); + + idr_init(&mvnet_dev.vd_idr); + + mvnet_dev.vd_class = class_create(THIS_MODULE, MVNET_CLASS_NAME); + + if (IS_ERR(mvnet_dev.vd_class)) { + pr_err("Error: failed to register mvnet_dev class\n"); + ret = PTR_ERR(mvnet_dev.vd_class); + goto failed1; + } + + mvnet_dev.dev.class = mvnet_dev.vd_class; + mvnet_dev.dev.release = mvnet_device_release; + dev_set_name(&mvnet_dev.dev, "%s", MVNET_NAME); + + ret = device_register(&mvnet_dev.dev); + if (ret) + goto failed2; + + ret = mdev_register_device(&mvnet_dev.dev, &mdev_fops); + if (ret) + goto failed3; + + mutex_init(&mdev_list_lock); + INIT_LIST_HEAD(&mdev_devices_list); + + goto all_done; + +failed3: + + device_unregister(&mvnet_dev.dev); +failed2: + class_destroy(mvnet_dev.vd_class); + +failed1: +all_done: + return ret; +} + +static void __exit mvnet_dev_exit(void) +{ + mvnet_dev.dev.bus = NULL; + mdev_unregister_device(&mvnet_dev.dev); + + device_unregister(&mvnet_dev.dev); + idr_destroy(&mvnet_dev.vd_idr); + class_destroy(mvnet_dev.vd_class); + mvnet_dev.vd_class = NULL; + pr_info("mvnet_dev: Unloaded!\n"); +} + +module_init(mvnet_dev_init) +module_exit(mvnet_dev_exit) + +MODULE_LICENSE("GPL v2"); +MODULE_INFO(supported, "Simulate loopback ethernet device over mdev"); +MODULE_VERSION(VERSION_STRING); +MODULE_AUTHOR(DRIVER_AUTHOR);