summaryrefslogtreecommitdiffstats
path: root/kernel
diff options
context:
space:
mode:
Diffstat (limited to 'kernel')
-rw-r--r--kernel/include/ioctl.h21
-rw-r--r--kernel/ioctl.c44
-rw-r--r--kernel/main.c280
3 files changed, 307 insertions, 38 deletions
diff --git a/kernel/include/ioctl.h b/kernel/include/ioctl.h
index 4ff3df9..36d28ac 100644
--- a/kernel/include/ioctl.h
+++ b/kernel/include/ioctl.h
@@ -32,6 +32,18 @@
#define NV_VGPU_IOCTL_SET_GSP_FIRMWARE \
_IOWR(NV_VGPU_IOCTL_MAGIC, 0x09, struct nv_vgpu_ioctl_firmware)
+#define NV_VGPU_IOCTL_REGISTER_VGPU_TYPE \
+ _IOWR(NV_VGPU_IOCTL_MAGIC, 0x0A, struct nv_vgpu_ioctl_register_vgpu_type)
+
+/* vGPU type info structure (shared between main.c and ioctl.c) */
+struct nv_vgpu_type_info {
+ char name[64];
+ char description[128];
+ u64 vdev_id;
+ u64 pdev_id;
+ u32 max_instances;
+};
+
struct nv_vgpu_ioctl_get_info {
u32 vgpu_type;
u32 vgpu_id;
@@ -93,6 +105,14 @@ struct nv_vgpu_ioctl_firmware {
u32 firmware_type;
};
+struct nv_vgpu_ioctl_register_vgpu_type {
+ char name[64];
+ char description[128];
+ u64 vdev_id;
+ u64 pdev_id;
+ u32 max_instances;
+};
+
int nv_vgpu_ioctl_get_info(struct nv_vgpu_device *vgpu, void __user *arg);
int nv_vgpu_ioctl_map_bar(struct nv_vgpu_device *vgpu, void __user *arg);
int nv_vgpu_ioctl_unmap_bar(struct nv_vgpu_device *vgpu, void __user *arg);
@@ -101,5 +121,6 @@ int nv_vgpu_ioctl_disable_irq(struct nv_vgpu_device *vgpu, void __user *arg);
int nv_vgpu_ioctl_gsp_rpc(struct nv_vgpu_device *vgpu, void __user *arg);
int nv_vgpu_ioctl_migrate_save(struct nv_vgpu_device *vgpu, void __user *arg);
int nv_vgpu_ioctl_migrate_restore(struct nv_vgpu_device *vgpu, void __user *arg);
+int nv_vgpu_ioctl_register_vgpu_type(void __user *arg);
#endif \ No newline at end of file
diff --git a/kernel/ioctl.c b/kernel/ioctl.c
index 571b209..387a249 100644
--- a/kernel/ioctl.c
+++ b/kernel/ioctl.c
@@ -10,6 +10,12 @@
#include "irq.h"
#include "migration.h"
+/* Forward declarations from main.c */
+extern int nv_vgpu_register_type_info(struct nv_vgpu_type_info *info);
+extern int nv_vgpu_create_mdev_types(void);
+extern void nv_vgpu_free_type_info(void);
+extern struct mdev_driver nv_vgpu_mdev_driver;
+
int nv_vgpu_ioctl_get_info(struct nv_vgpu_device *vgpu, void __user *arg)
{
struct nv_vgpu_ioctl_get_info info;
@@ -260,4 +266,42 @@ int nv_vgpu_ioctl_migrate_restore(struct nv_vgpu_device *vgpu, void __user *arg)
return -EFAULT;
return ret;
+}
+
+int nv_vgpu_ioctl_register_vgpu_type(void __user *arg)
+{
+ struct nv_vgpu_ioctl_register_vgpu_type params;
+ struct nv_vgpu_type_info info;
+ int ret;
+
+ if (copy_from_user(&params, arg, sizeof(params)))
+ return -EFAULT;
+
+ memset(&info, 0, sizeof(info));
+ strncpy(info.name, params.name, sizeof(info.name) - 1);
+ strncpy(info.description, params.description, sizeof(info.description) - 1);
+ info.vdev_id = params.vdev_id;
+ info.pdev_id = params.pdev_id;
+ info.max_instances = params.max_instances;
+
+ ret = nv_vgpu_register_type_info(&info);
+ if (ret)
+ return ret;
+
+ /* Re-create mdev types with updated info */
+ nv_vgpu_free_type_info();
+ ret = nv_vgpu_create_mdev_types();
+ if (ret)
+ return ret;
+
+ /* Re-register mdev driver with new types */
+ mdev_unregister_driver(&nv_vgpu_mdev_driver);
+ ret = mdev_register_driver(&nv_vgpu_mdev_driver);
+ if (ret) {
+ pr_err("Failed to re-register mdev driver: %d\n", ret);
+ return ret;
+ }
+
+ pr_info("vGPU type '%s' registered via ioctl\n", info.name);
+ return 0;
} \ No newline at end of file
diff --git a/kernel/main.c b/kernel/main.c
index a277356..5d9d8ef 100644
--- a/kernel/main.c
+++ b/kernel/main.c
@@ -41,9 +41,16 @@ static int nv_vgpu_config_space_init(struct nv_vgpu_device *vgpu, struct pci_dev
static ssize_t nv_vgpu_config_read(struct nv_vgpu_device *vgpu, char __user *buf, size_t count, loff_t *ppos);
static ssize_t nv_vgpu_config_write(struct nv_vgpu_device *vgpu, const char __user *buf, size_t count, loff_t *ppos);
-static struct mdev_type *nv_vgpu_mdev_types[4];
+/* vGPU type management */
+int nv_vgpu_register_type_info(struct nv_vgpu_type_info *info);
+struct nv_vgpu_type_info *nv_vgpu_find_type_info(const char *name);
-static struct mdev_driver nv_vgpu_mdev_driver = {
+struct mdev_type *nv_vgpu_mdev_types[16];
+struct nv_vgpu_type_info g_vgpu_type_infos[16];
+int g_num_vgpu_types = 0;
+static DEFINE_MUTEX(g_vgpu_type_lock);
+
+struct mdev_driver nv_vgpu_mdev_driver = {
.device_api = VFIO_DEVICE_API_PCI_STRING,
.max_instances = 8,
.probe = nv_vgpu_mdev_create,
@@ -219,6 +226,118 @@ static void populate_rm_ops(void)
g_rm_vgpu_vfio_ops.update_request = nv_vgpu_update_request_callback;
}
+/* ============================================================
+ * vGPU Type Management (userspace provides info via ioctl)
+ * ============================================================ */
+
+int nv_vgpu_register_type_info(struct nv_vgpu_type_info *info)
+{
+ int i;
+
+ mutex_lock(&g_vgpu_type_lock);
+
+ /* Check if already registered */
+ for (i = 0; i < g_num_vgpu_types; i++) {
+ if (strcmp(g_vgpu_type_infos[i].name, info->name) == 0) {
+ /* Update existing */
+ g_vgpu_type_infos[i] = *info;
+ mutex_unlock(&g_vgpu_type_lock);
+ return 0;
+ }
+ }
+
+ /* Add new */
+ if (g_num_vgpu_types >= 16) {
+ mutex_unlock(&g_vgpu_type_lock);
+ return -ENOSPC;
+ }
+
+ g_vgpu_type_infos[g_num_vgpu_types] = *info;
+ g_num_vgpu_types++;
+
+ mutex_unlock(&g_vgpu_type_lock);
+
+ pr_info("Registered vGPU type: name='%s', vdev=0x%llx, pdev=0x%llx, max_inst=%u\n",
+ info->name, info->vdev_id, info->pdev_id, info->max_instances);
+ return 0;
+}
+EXPORT_SYMBOL(nv_vgpu_register_type_info);
+
+struct nv_vgpu_type_info *nv_vgpu_find_type_info(const char *name)
+{
+ int i;
+
+ mutex_lock(&g_vgpu_type_lock);
+ for (i = 0; i < g_num_vgpu_types; i++) {
+ if (strcmp(g_vgpu_type_infos[i].name, name) == 0) {
+ mutex_unlock(&g_vgpu_type_lock);
+ return &g_vgpu_type_infos[i];
+ }
+ }
+ mutex_unlock(&g_vgpu_type_lock);
+ return NULL;
+}
+EXPORT_SYMBOL(nv_vgpu_find_type_info);
+
+static void nv_vgpu_create_static_types(void)
+{
+ int i;
+ struct nv_vgpu_type_info static_types[4] = {
+ { .name = "nvidia-vgpu-ampere", .description = "NVIDIA Ampere vGPU", .vdev_id = 0x10de2235, .pdev_id = 0x10de2235, .max_instances = 1 },
+ { .name = "nvidia-vgpu-hopper", .description = "NVIDIA Hopper vGPU", .vdev_id = 0x10de2331, .pdev_id = 0x10de2331, .max_instances = 1 },
+ { .name = "nvidia-vgpu-turing", .description = "NVIDIA Turing vGPU", .vdev_id = 0x10de1ed3, .pdev_id = 0x10de1ed3, .max_instances = 1 },
+ { .name = "nvidia-vgpu-pascal", .description = "NVIDIA Pascal vGPU", .vdev_id = 0x10de1db1, .pdev_id = 0x10de1db1, .max_instances = 1 },
+ };
+
+ for (i = 0; i < 4; i++) {
+ nv_vgpu_register_type_info(&static_types[i]);
+ }
+}
+
+int nv_vgpu_create_mdev_types(void)
+{
+ int i, ret;
+
+ for (i = 0; i < g_num_vgpu_types; i++) {
+ nv_vgpu_mdev_types[i] = kzalloc(sizeof(struct mdev_type), GFP_KERNEL);
+ if (!nv_vgpu_mdev_types[i]) {
+ ret = -ENOMEM;
+ goto err_types;
+ }
+ nv_vgpu_mdev_types[i]->sysfs_name = kstrdup(g_vgpu_type_infos[i].name, GFP_KERNEL);
+ nv_vgpu_mdev_types[i]->pretty_name = kstrdup(g_vgpu_type_infos[i].description[0] ? g_vgpu_type_infos[i].description : g_vgpu_type_infos[i].name, GFP_KERNEL);
+ if (!nv_vgpu_mdev_types[i]->sysfs_name || !nv_vgpu_mdev_types[i]->pretty_name) {
+ ret = -ENOMEM;
+ goto err_types;
+ }
+ }
+
+ return 0;
+
+err_types:
+ for (i = 0; i < g_num_vgpu_types; i++) {
+ kfree(nv_vgpu_mdev_types[i]->sysfs_name);
+ kfree(nv_vgpu_mdev_types[i]->pretty_name);
+ kfree(nv_vgpu_mdev_types[i]);
+ nv_vgpu_mdev_types[i] = NULL;
+ }
+ return ret;
+}
+EXPORT_SYMBOL(nv_vgpu_create_mdev_types);
+
+void nv_vgpu_free_type_info(void)
+{
+ int i;
+ for (i = 0; i < g_num_vgpu_types; i++) {
+ kfree(nv_vgpu_mdev_types[i]->sysfs_name);
+ kfree(nv_vgpu_mdev_types[i]->pretty_name);
+ kfree(nv_vgpu_mdev_types[i]);
+ nv_vgpu_mdev_types[i] = NULL;
+ }
+ g_num_vgpu_types = 0;
+}
+EXPORT_SYMBOL(nv_vgpu_free_type_info);
+
/* get_ops: called by nvidia-vgpu-vfio to get RM ops */
NV_STATUS nvidia_vgpu_vfio_get_ops(rm_vgpu_vfio_ops_t *ops)
{
@@ -230,6 +349,7 @@ NV_STATUS nvidia_vgpu_vfio_get_ops(rm_vgpu_vfio_ops_t *ops)
pr_info("nvidia-vgpu-vfio: get_ops provided RM ops\n");
return NV_OK;
}
+EXPORT_SYMBOL(nvidia_vgpu_vfio_get_ops);
/* set_ops: called by nvidia-vgpu-vfio to provide VFIO ops */
NV_STATUS nvidia_vgpu_vfio_set_ops(vgpu_vfio_ops_t *ops)
@@ -241,11 +361,68 @@ NV_STATUS nvidia_vgpu_vfio_set_ops(vgpu_vfio_ops_t *ops)
pr_info("nvidia-vgpu-vfio: set_ops received VFIO ops\n");
return NV_OK;
}
+EXPORT_SYMBOL(nvidia_vgpu_vfio_set_ops);
+
+/* mdev driver registration - called by nvidia.ko */
+int nv_vgpu_mdev_driver_register(void)
+{
+ pr_info("nvidia-vgpu-vfio: mdev driver register\n");
+ return mdev_register_driver(&nv_vgpu_mdev_driver);
+}
+EXPORT_SYMBOL(nv_vgpu_mdev_driver_register);
+
+void nv_vgpu_mdev_driver_unregister(void)
+{
+ pr_info("nvidia-vgpu-vfio: mdev driver unregister\n");
+ mdev_unregister_driver(&nv_vgpu_mdev_driver);
+}
+EXPORT_SYMBOL(nv_vgpu_mdev_driver_unregister);
+
+/* mdev parent device registration - called by nvidia.ko */
+
+int nv_vgpu_mdev_register_parent(struct pci_dev *pdev)
+{
+ struct mdev_parent *parent;
+ int ret;
+
+ pr_info("nvidia-vgpu-vfio: mdev parent register for %s\n", pci_name(pdev));
+
+ if (g_mdev_parent) {
+ pr_warn("mdev parent already registered\n");
+ return 0;
+ }
+
+ parent = kzalloc(sizeof(*parent), GFP_KERNEL);
+ if (!parent)
+ return -ENOMEM;
-extern NV_STATUS nv_vgpu_mdev_register_parent(struct pci_dev *pdev);
-extern void nv_vgpu_mdev_unregister_parent(struct pci_dev *pdev);
-extern int nv_vgpu_mdev_driver_register(void);
-extern void nv_vgpu_mdev_driver_unregister(void);
+ parent->dev = &pdev->dev;
+
+ ret = mdev_register_parent(parent, &pdev->dev, &nv_vgpu_mdev_driver,
+ nv_vgpu_mdev_types, g_num_vgpu_types);
+ if (ret) {
+ pr_err("Failed to register mdev parent: %d\n", ret);
+ kfree(parent);
+ return ret;
+ }
+
+ g_mdev_parent = parent;
+ pr_info("mdev parent registered successfully with %d types\n", g_num_vgpu_types);
+ return 0;
+}
+EXPORT_SYMBOL(nv_vgpu_mdev_register_parent);
+
+void nv_vgpu_mdev_unregister_parent(struct pci_dev *pdev)
+{
+ pr_info("nvidia-vgpu-vfio: mdev parent unregister for %s\n", pci_name(pdev));
+
+ if (g_mdev_parent) {
+ mdev_unregister_parent(g_mdev_parent);
+ kfree(g_mdev_parent);
+ g_mdev_parent = NULL;
+ }
+}
+EXPORT_SYMBOL(nv_vgpu_mdev_unregister_parent);
MODULE_SOFTDEP("pre: nvidia");
@@ -342,27 +519,14 @@ static int __init nv_vgpu_init(void)
return ret;
}
- for (i = 0; i < 4; i++) {
- nv_vgpu_mdev_types[i] = kzalloc(sizeof(struct mdev_type), GFP_KERNEL);
- if (!nv_vgpu_mdev_types[i]) {
- ret = -ENOMEM;
- goto err_types;
- }
- }
-
- nv_vgpu_mdev_types[0]->sysfs_name = "nvidia-vgpu-ampere";
- nv_vgpu_mdev_types[0]->pretty_name = "NVIDIA Ampere vGPU";
- nv_vgpu_mdev_types[1]->sysfs_name = "nvidia-vgpu-hopper";
- nv_vgpu_mdev_types[1]->pretty_name = "NVIDIA Hopper vGPU";
- nv_vgpu_mdev_types[2]->sysfs_name = "nvidia-vgpu-turing";
- nv_vgpu_mdev_types[2]->pretty_name = "NVIDIA Turing vGPU";
- nv_vgpu_mdev_types[3]->sysfs_name = "nvidia-vgpu-pascal";
- nv_vgpu_mdev_types[3]->pretty_name = "NVIDIA Pascal vGPU";
+ /* Create static vGPU types as fallback (userspace can override via ioctl) */
+ nv_vgpu_create_static_types();
- ret = mdev_register_driver(&nv_vgpu_mdev_driver);
+ /* Create mdev types from registered vGPU types */
+ ret = nv_vgpu_create_mdev_types();
if (ret) {
- pr_err("Failed to register mdev driver: %d\n", ret);
- goto err_types;
+ pr_err("Failed to create mdev types: %d\n", ret);
+ goto err_class;
}
/* Find the parent PCI device to register mdev parent */
@@ -370,17 +534,25 @@ static int __init nv_vgpu_init(void)
if (!pdev) {
pr_err("Failed to find NVIDIA GPU (10de:1ed3) for mdev parent registration\n");
ret = -ENODEV;
- goto err_driver;
+ goto err_types;
}
/* Register mdev parent via nvidia.ko */
ret = nv_vgpu_mdev_register_parent(pdev);
- pci_dev_put(pdev);
if (ret) {
pr_err("Failed to register mdev parent: %d\n", ret);
- goto err_driver;
+ goto err_put_pdev;
}
+ ret = mdev_register_driver(&nv_vgpu_mdev_driver);
+ if (ret) {
+ pr_err("Failed to register mdev driver: %d\n", ret);
+ goto err_types;
+ }
+
+ pci_dev_put(pdev);
+ pdev = NULL;
+
/* Provide VFIO ops to host driver (nvidia.ko) */
ret = nvidia_vgpu_vfio_set_ops(&nv_vgpu_vfio_ops);
if (ret) {
@@ -394,10 +566,11 @@ static int __init nv_vgpu_init(void)
err_driver:
mdev_unregister_driver(&nv_vgpu_mdev_driver);
err_types:
- for (i = 0; i < 4; i++) {
- kfree(nv_vgpu_mdev_types[i]);
- nv_vgpu_mdev_types[i] = NULL;
- }
+ nv_vgpu_free_type_info();
+err_put_pdev:
+ if (pdev)
+ pci_dev_put(pdev);
+err_class:
class_destroy(nv_vgpu_driver.class);
return ret;
}
@@ -441,10 +614,7 @@ static void __exit nv_vgpu_exit(void)
class_destroy(nv_vgpu_driver.class);
- for (i = 0; i < 4; i++) {
- kfree(nv_vgpu_mdev_types[i]);
- nv_vgpu_mdev_types[i] = NULL;
- }
+ nv_vgpu_free_type_info();
pr_info("NVIDIA vGPU VFIO driver unloaded\n");
}
@@ -558,7 +728,7 @@ static int nv_vgpu_config_space_init(struct nv_vgpu_device *vgpu, struct pci_dev
{
u8 *cfg = vgpu->pci_config;
u16 vendor_id = 0x10de; /* NVIDIA */
- u16 device_id = 0x1ed3; /* TU104 vGPU */
+ u16 device_id = 0x1ed3; /* TU104 vGPU (default) */
u16 subsys_vendor = 0x10de;
u16 subsys_device = 0x12b4;
u8 revision = 0xa1;
@@ -569,9 +739,25 @@ static int nv_vgpu_config_space_init(struct nv_vgpu_device *vgpu, struct pci_dev
u8 latency = 0x00;
u8 header_type = 0x00; /* Normal device */
u8 bist = 0x00;
+ int i;
memset(cfg, 0, 256);
+ /* Look up vGPU type info from mdev type name */
+ if (vgpu->mdev && vgpu->mdev->type && vgpu->mdev->type->sysfs_name) {
+ for (i = 0; i < g_num_vgpu_types; i++) {
+ if (strcmp(vgpu->mdev->type->sysfs_name, g_vgpu_type_infos[i].name) == 0) {
+ vendor_id = (u16)(g_vgpu_type_infos[i].vdev_id & 0xFFFF);
+ device_id = (u16)((g_vgpu_type_infos[i].vdev_id >> 16) & 0xFFFF);
+ subsys_vendor = (u16)(g_vgpu_type_infos[i].pdev_id & 0xFFFF);
+ subsys_device = (u16)((g_vgpu_type_infos[i].pdev_id >> 16) & 0xFFFF);
+ nv_vgpu_info(vgpu, "Using vGPU type: name='%s', vendor=0x%04x, device=0x%04x, subsys_vendor=0x%04x, subsys_device=0x%04x",
+ g_vgpu_type_infos[i].name, vendor_id, device_id, subsys_vendor, subsys_device);
+ break;
+ }
+ }
+ }
+
/* PCI Header (offset 0x00-0x3F) */
cfg[0x00] = vendor_id & 0xff;
cfg[0x01] = (vendor_id >> 8) & 0xff;
@@ -766,7 +952,7 @@ static int nv_vgpu_config_space_init(struct nv_vgpu_device *vgpu, struct pci_dev
cfg[0x9f] = 0x00;
vgpu->config_space_dirty = false;
- nv_vgpu_info(vgpu, "PCI config space initialized (vendor=0x%04x, device=0x%04x)", vendor_id, device_id);
+ nv_vgpu_info(vgpu, "PCI config space initialized (vendor=0x%04x, device=0x%04x, subsys_vendor=0x%04x, subsys_device=0x%04x)", vendor_id, device_id, subsys_vendor, subsys_device);
return 0;
}
@@ -850,5 +1036,23 @@ static ssize_t nv_vgpu_config_write(struct nv_vgpu_device *vgpu, const char __us
return pos - *ppos + count;
}
+/* ============================================================
+ * Exported symbols for nvidia.ko (vGPU VFIO interface)
+ * ============================================================ */
+
+NV_STATUS nvidia_vgpu_vfio_probe(struct pci_dev *pdev)
+{
+ pr_info("nvidia-vgpu-vfio: nvidia_vgpu_vfio_probe called for %s\n", pci_name(pdev));
+ return NV_OK;
+}
+EXPORT_SYMBOL(nvidia_vgpu_vfio_probe);
+
+void nvidia_vgpu_vfio_remove(struct pci_dev *pdev, NvBool remove_device)
+{
+ pr_info("nvidia-vgpu-vfio: nvidia_vgpu_vfio_remove called for %s, remove_device=%d\n",
+ pci_name(pdev), remove_device);
+}
+EXPORT_SYMBOL(nvidia_vgpu_vfio_remove);
+
module_init(nv_vgpu_init);
module_exit(nv_vgpu_exit);