From ff3cafa134a8ba13c799107ee4ddad76e4c8c4e8 Mon Sep 17 00:00:00 2001 From: Nitin Kumbhar Date: Wed, 19 Sep 2018 22:31:45 +0530 Subject: [PATCH] gpu: nvgpu: add nvgpu power off/on sysfs nodes Add sysfs nodes to manage power of dGPU. Writing pci dev name to poweroff/poweron sysfs node powers off/on dGPU. The format of pci dev name is DDDD:BB:DD.F i.e. domain:bus:device.function echo 0001:01:00.0 > /sys/bus/pci/drivers/nvgpu/poweroff echo 0001:01:00.0 > /sys/bus/pci/drivers/nvgpu/poweron The permissions of nodes are set such that only root user can write to the sysfs node to control dGPU power state. JIRA NVGPU-1100 Change-Id: I904881cab58c5f553e94510a3a10000194238433 Signed-off-by: Nitin Kumbhar Reviewed-on: https://git-master.nvidia.com/r/1749848 Reviewed-by: Deepak Nibade GVS: Gerrit_Virtual_Submit Reviewed-by: Bharat Nihalani Reviewed-by: mobile promotions Tested-by: mobile promotions --- drivers/gpu/nvgpu/os/linux/pci_power.c | 85 ++++++++++++++++++++++++++ 1 file changed, 85 insertions(+) diff --git a/drivers/gpu/nvgpu/os/linux/pci_power.c b/drivers/gpu/nvgpu/os/linux/pci_power.c index 1c1ab0904..52d6e63a9 100644 --- a/drivers/gpu/nvgpu/os/linux/pci_power.c +++ b/drivers/gpu/nvgpu/os/linux/pci_power.c @@ -133,6 +133,22 @@ int nvgpu_pci_clear_pci_power(const char *dev_name) return -ENODEV; } +static int nvgpu_pci_parse_dev_name(const char *buf, size_t count, char *name) +{ + int domain, bus, device, func; + int ret; + + /* DDDD:BB:DD.F for domain:bus:device.function */ + ret = sscanf(buf, "%x:%x:%x.%x", &domain, &bus, &device, &func); + if (ret < 4) + return -EINVAL; + + snprintf(name, PCI_DEV_NAME_MAX, "%04x:%02x:%02x.%1x", + domain, bus, device, func); + + return 0; +} + static char *nvgpu_pci_gpio_name(int g) { switch (g) { @@ -565,6 +581,59 @@ int nvgpu_pci_set_powerstate(char *dev_name, int powerstate) return ret; } +static ssize_t poweroff_store(struct device_driver *drv, + const char *buf, size_t count) +{ + struct nvgpu_pci_power *pp; + char dev_name[PCI_DEV_NAME_MAX]; + int ret; + + ret = nvgpu_pci_parse_dev_name(buf, count, dev_name); + if (ret) + return ret; + + pp = nvgpu_pci_get_pci_power(dev_name); + if (!pp) + return -ENODEV; + + ret = nvgpu_pci_set_powerstate(dev_name, NVGPU_POWER_OFF); + if (ret) { + pr_err("nvgpu: GPU(%s) POWER OFF failed\n", dev_name); + return ret; + } + + pr_debug("nvgpu: GPU(%s) POWER OFF done\n", dev_name); + return count; +} + +static DRIVER_ATTR_WO(poweroff); + +static ssize_t poweron_store(struct device_driver *drv, + const char *buf, size_t count) +{ + struct nvgpu_pci_power *pp; + char dev_name[PCI_DEV_NAME_MAX]; + int ret; + + ret = nvgpu_pci_parse_dev_name(buf, count, dev_name); + if (ret) + return ret; + + pp = nvgpu_pci_get_pci_power(dev_name); + if (!pp) + return -ENODEV; + + ret = nvgpu_pci_set_powerstate(dev_name, NVGPU_POWER_ON); + if (ret) { + pr_err("nvgpu: GPU(%s) POWER ON failed\n", dev_name); + return ret; + } + + pr_debug("nvgpu: GPU(%s) POWER ON done\n", dev_name); + return count; +} + +static DRIVER_ATTR_WO(poweron); int __init nvgpu_pci_power_init(struct pci_driver *nvgpu_pci_driver) { @@ -584,8 +653,21 @@ int __init nvgpu_pci_power_init(struct pci_driver *nvgpu_pci_driver) } pci_power_stats_dbgfs_dentry = d; + ret = driver_create_file(driver, &driver_attr_poweroff); + if (ret) + goto err_poweroff; + + ret = driver_create_file(driver, &driver_attr_poweron); + if (ret) + goto err_poweron; + return 0; +err_poweron: + driver_remove_file(driver, &driver_attr_poweroff); +err_poweroff: + debugfs_remove(d); + pci_power_stats_dbgfs_dentry = NULL; err_power_stats: driver_remove_file(driver, &driver_attr_probed_gpus); err_probed_gpus: @@ -596,6 +678,9 @@ void __exit nvgpu_pci_power_exit(struct pci_driver *nvgpu_pci_driver) { struct device_driver *driver = &nvgpu_pci_driver->driver; + driver_remove_file(driver, &driver_attr_poweroff); + driver_remove_file(driver, &driver_attr_poweron); + debugfs_remove(pci_power_stats_dbgfs_dentry); driver_remove_file(driver, &driver_attr_probed_gpus);