diff options
| -rw-r--r-- | kernel/include/ioctl.h | 21 | ||||
| -rw-r--r-- | kernel/ioctl.c | 44 | ||||
| -rw-r--r-- | kernel/main.c | 280 | ||||
| -rwxr-xr-x | scripts/create_mdev.sh | 6 | ||||
| -rwxr-xr-x | scripts/load_vgpu_stack.sh | 30 |
5 files changed, 321 insertions, 60 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(¶ms, 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); diff --git a/scripts/create_mdev.sh b/scripts/create_mdev.sh index f6c76ed..a6ea91e 100755 --- a/scripts/create_mdev.sh +++ b/scripts/create_mdev.sh @@ -5,10 +5,10 @@ set -euo pipefail PCI_ADDR="${1:-}" -VGPU_TYPE="${2:-nvidia-vgpu-turing}" +VGPU_TYPE="${2:-pci-nvidia-vgpu-turing}" -# Supported vGPU types -VALID_TYPES=("nvidia-vgpu-ampere" "nvidia-vgpu-hopper" "nvidia-vgpu-turing" "nvidia-vgpu-pascal") +# Supported vGPU types (matching the mdev type names) +VALID_TYPES=("pci-nvidia-vgpu-ampere" "pci-nvidia-vgpu-hopper" "pci-nvidia-vgpu-turing" "pci-nvidia-vgpu-pascal") # Find NVIDIA GPU if not specified if [[ -z "$PCI_ADDR" ]]; then diff --git a/scripts/load_vgpu_stack.sh b/scripts/load_vgpu_stack.sh index 36211bc..5e7d6fd 100755 --- a/scripts/load_vgpu_stack.sh +++ b/scripts/load_vgpu_stack.sh @@ -9,32 +9,23 @@ FIRMWARE_NAME="${1:-gsp-570.144.fwimage.bin}" BASE_DIR="$OPEN_IOV_ROOT" NVIDIA_KO="$BASE_DIR/nvidia-open-gpu-kernel-modules/kernel-open/nvidia.ko" VFIO_KO="$BASE_DIR/kernel/open-iov-vfio.ko" -GSP_VGPU_KO="$BASE_DIR/driver/gsp-vgpu.ko" -FIRMWARE_PATH="$BASE_DIR/firmware/570-GSP/$FIRMWARE_NAME" +FIRMWARE_PATH="$BASE_DIR/firmware/57X-GSP/570.144/$FIRMWARE_NAME" echo "==========================================" -echo "Loading vGPU Driver Stack" +echo "Loading vGPU Driver Stack (Refactored: Host-only GSP Emulation)" echo "==========================================" echo "Firmware: $FIRMWARE_NAME" echo "" # Check files exist -for f in "$NVIDIA_KO" "$VFIO_KO" "$GSP_VGPU_KO" "$FIRMWARE_PATH"; do +for f in "$NVIDIA_KO" "$VFIO_KO" "$FIRMWARE_PATH"; do if [[ ! -f "$f" ]]; then echo "ERROR: Missing file: $f" exit 1 fi done -# Check if already loaded -if lsmod | grep -q "^nvidia "; then - echo "nvidia.ko already loaded" -else - echo "Loading nvidia.ko (OpenRM)..." - sudo insmod "$NVIDIA_KO" - echo " OK" -fi - +# Load open-iov-vfio.ko FIRST (provides symbols nvidia.ko needs) if lsmod | grep -q "^open_iov_vfio "; then echo "open-iov-vfio.ko already loaded" else @@ -43,11 +34,12 @@ else echo " OK" fi -if lsmod | grep -q "^gsp_vgpu "; then - echo "gsp-vgpu.ko already loaded" +# Check if already loaded +if lsmod | grep -q "^nvidia "; then + echo "nvidia.ko already loaded" else - echo "Loading gsp-vgpu.ko with firmware=$FIRMWARE_NAME..." - sudo insmod "$GSP_VGPU_KO" firmware_name="$FIRMWARE_NAME" + echo "Loading nvidia.ko (OpenRM)..." + sudo insmod "$NVIDIA_KO" echo " OK" fi @@ -55,10 +47,10 @@ echo "" echo "==========================================" echo "Driver Stack Loaded Successfully" echo "==========================================" -lsmod | grep -E "nvidia|open_iov|gsp_vgpu" +lsmod | grep -E "nvidia|open_iov" echo "" echo "Device nodes:" -ls -la /dev/gsp-vgpu* /dev/nvidia* 2>/dev/null || echo " (none yet - create mdev first)" +ls -la /dev/nvidia* 2>/dev/null || echo " (none yet - create mdev first)" echo "" echo "Next steps:" echo " 1. Create mdev: $BASE_DIR/scripts/create_mdev.sh" |
