mirror of
git://nv-tegra.nvidia.com/linux-nvgpu.git
synced 2025-12-22 09:12:24 +03:00
gpu: nvgpu: mig: Defer dev_nodes creation and create new power node to support MIG
- This is deferring the dev_nodes creation after power_on to select the MIG config and to create the dev_nodes as per the selected MIG config. - The patch is adding a device node to issue power on. The nodes are: for igpu :/dev/nvgpu/igpu0/power for dgpu:/dev/nvgpu/dgpu-0001:01:00.0/power To issue power on : echo "1" > /dev/nvgpu/igpu0/power echo "1" > /dev/nvgpu/dgpu-0001:01:00.0/power JIRA NVGPU-6633 Change-Id: Ic4f1f3e42724cc788dcfaf0e881d188fd3bd1ce1 Signed-off-by: dt <dt@nvidia.com> Reviewed-on: https://git-master.nvidia.com/r/c/linux-nvgpu/+/2512647 Tested-by: mobile promotions <svcmobile_promotions@nvidia.com> Reviewed-by: mobile promotions <svcmobile_promotions@nvidia.com>
This commit is contained in:
@@ -120,7 +120,9 @@ ioctl:
|
|||||||
os/linux/ioctl_prof.c,
|
os/linux/ioctl_prof.c,
|
||||||
os/linux/ioctl_prof.h,
|
os/linux/ioctl_prof.h,
|
||||||
os/linux/ioctl_tsg.c,
|
os/linux/ioctl_tsg.c,
|
||||||
os/linux/ioctl_tsg.h ]
|
os/linux/ioctl_tsg.h,
|
||||||
|
os/linux/power_ops.c,
|
||||||
|
os/linux/power_ops.h ]
|
||||||
|
|
||||||
kmem:
|
kmem:
|
||||||
sources: [ os/linux/kmem.c, os/linux/kmem_priv.h ]
|
sources: [ os/linux/kmem.c, os/linux/kmem_priv.h ]
|
||||||
|
|||||||
@@ -419,7 +419,8 @@ nvgpu-y += \
|
|||||||
os/linux/ecc_sysfs.o \
|
os/linux/ecc_sysfs.o \
|
||||||
os/linux/bsearch.o \
|
os/linux/bsearch.o \
|
||||||
os/linux/sdl/sdl_stub.o \
|
os/linux/sdl/sdl_stub.o \
|
||||||
os/linux/dmabuf_priv.o
|
os/linux/dmabuf_priv.o \
|
||||||
|
os/linux/power_ops.o
|
||||||
|
|
||||||
nvgpu-$(CONFIG_NVGPU_VPR) += os/linux/vpr.o
|
nvgpu-$(CONFIG_NVGPU_VPR) += os/linux/vpr.o
|
||||||
|
|
||||||
|
|||||||
@@ -268,6 +268,7 @@ int nvgpu_probe(struct gk20a *g,
|
|||||||
{
|
{
|
||||||
struct device *dev = dev_from_gk20a(g);
|
struct device *dev = dev_from_gk20a(g);
|
||||||
struct gk20a_platform *platform = dev_get_drvdata(dev);
|
struct gk20a_platform *platform = dev_get_drvdata(dev);
|
||||||
|
struct nvgpu_os_linux *l = nvgpu_os_linux_from_gk20a(g);
|
||||||
int err = 0;
|
int err = 0;
|
||||||
|
|
||||||
nvgpu_init_vars(g);
|
nvgpu_init_vars(g);
|
||||||
@@ -294,11 +295,22 @@ int nvgpu_probe(struct gk20a *g,
|
|||||||
}
|
}
|
||||||
|
|
||||||
nvgpu_init_mm_vars(g);
|
nvgpu_init_mm_vars(g);
|
||||||
|
err = gk20a_power_node_init(dev);
|
||||||
/* platform probe can defer do user init only if probe succeeds */
|
if (err) {
|
||||||
err = gk20a_user_init(dev);
|
nvgpu_err(g, "power_node creation failed");
|
||||||
if (err)
|
|
||||||
return err;
|
return err;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* TODO: While removing the legacy nodes the following condition
|
||||||
|
* need to be removed.
|
||||||
|
*/
|
||||||
|
if (platform->platform_chip_id == TEGRA_210) {
|
||||||
|
err = gk20a_user_init(dev);
|
||||||
|
if (err)
|
||||||
|
return err;
|
||||||
|
l->dev_nodes_created = true;
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Note that for runtime suspend to work the clocks have to be setup
|
* Note that for runtime suspend to work the clocks have to be setup
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
/*
|
/*
|
||||||
* NVGPU IOCTLs
|
* NVGPU IOCTLs
|
||||||
*
|
*
|
||||||
* Copyright (c) 2011-2020, NVIDIA CORPORATION. All rights reserved.
|
* Copyright (c) 2011-2021, NVIDIA CORPORATION. All rights reserved.
|
||||||
*
|
*
|
||||||
* This program is free software; you can redistribute it and/or modify it
|
* This program is free software; you can redistribute it and/or modify it
|
||||||
* under the terms and conditions of the GNU General Public License,
|
* under the terms and conditions of the GNU General Public License,
|
||||||
@@ -30,12 +30,21 @@
|
|||||||
#include "ioctl_tsg.h"
|
#include "ioctl_tsg.h"
|
||||||
#include "ioctl_dbg.h"
|
#include "ioctl_dbg.h"
|
||||||
#include "ioctl_prof.h"
|
#include "ioctl_prof.h"
|
||||||
|
#include "power_ops.h"
|
||||||
#include "ioctl.h"
|
#include "ioctl.h"
|
||||||
#include "module.h"
|
#include "module.h"
|
||||||
#include "os_linux.h"
|
#include "os_linux.h"
|
||||||
#include "fecs_trace_linux.h"
|
#include "fecs_trace_linux.h"
|
||||||
#include "platform_gk20a.h"
|
#include "platform_gk20a.h"
|
||||||
|
|
||||||
|
const struct file_operations gk20a_power_node_ops = {
|
||||||
|
.owner = THIS_MODULE,
|
||||||
|
.release = gk20a_power_release,
|
||||||
|
.open = gk20a_power_open,
|
||||||
|
.read = gk20a_power_read,
|
||||||
|
.write = gk20a_power_write,
|
||||||
|
};
|
||||||
|
|
||||||
const struct file_operations gk20a_channel_ops = {
|
const struct file_operations gk20a_channel_ops = {
|
||||||
.owner = THIS_MODULE,
|
.owner = THIS_MODULE,
|
||||||
.release = gk20a_channel_release,
|
.release = gk20a_channel_release,
|
||||||
@@ -161,6 +170,7 @@ struct nvgpu_dev_node {
|
|||||||
};
|
};
|
||||||
|
|
||||||
static const struct nvgpu_dev_node dev_node_list[] = {
|
static const struct nvgpu_dev_node dev_node_list[] = {
|
||||||
|
{"power", &gk20a_power_node_ops, false },
|
||||||
{"as", &gk20a_as_ops, false },
|
{"as", &gk20a_as_ops, false },
|
||||||
{"channel", &gk20a_channel_ops, false },
|
{"channel", &gk20a_channel_ops, false },
|
||||||
{"ctrl", &gk20a_ctrl_ops, true },
|
{"ctrl", &gk20a_ctrl_ops, true },
|
||||||
@@ -332,6 +342,8 @@ void gk20a_user_deinit(struct device *dev)
|
|||||||
class_destroy(class->class);
|
class_destroy(class->class);
|
||||||
nvgpu_kfree(g, class);
|
nvgpu_kfree(g, class);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
l->dev_nodes_created = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
static struct nvgpu_class *nvgpu_create_class(struct gk20a *g, const char *class_name)
|
static struct nvgpu_class *nvgpu_create_class(struct gk20a *g, const char *class_name)
|
||||||
@@ -463,20 +475,31 @@ static int nvgpu_prepare_mig_dev_node_class_list(struct gk20a *g, u32 *num_class
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int nvgpu_prepare_default_dev_node_class_list(struct gk20a *g, u32 *num_classes)
|
static int nvgpu_prepare_default_dev_node_class_list(struct gk20a *g,
|
||||||
|
u32 *num_classes, bool power_node)
|
||||||
{
|
{
|
||||||
struct nvgpu_class *class;
|
struct nvgpu_class *class;
|
||||||
u32 count = 0U;
|
u32 count = 0U;
|
||||||
|
|
||||||
if (g->pci_class != 0U) {
|
if (g->pci_class != 0U) {
|
||||||
class = nvgpu_create_class(g, "nvidia-pci-gpu");
|
if (power_node) {
|
||||||
|
class = nvgpu_create_class(g, "nvidia-pci-gpu-power");
|
||||||
|
} else {
|
||||||
|
class = nvgpu_create_class(g, "nvidia-pci-gpu");
|
||||||
|
}
|
||||||
|
|
||||||
if (class == NULL) {
|
if (class == NULL) {
|
||||||
return -ENOMEM;
|
return -ENOMEM;
|
||||||
}
|
}
|
||||||
class->class->devnode = nvgpu_pci_devnode;
|
class->class->devnode = nvgpu_pci_devnode;
|
||||||
count++;
|
count++;
|
||||||
} else {
|
} else {
|
||||||
class = nvgpu_create_class(g, "nvidia-gpu");
|
if (power_node) {
|
||||||
|
class = nvgpu_create_class(g, "nvidia-gpu-power");
|
||||||
|
} else {
|
||||||
|
class = nvgpu_create_class(g, "nvidia-gpu");
|
||||||
|
}
|
||||||
|
|
||||||
if (class == NULL) {
|
if (class == NULL) {
|
||||||
return -ENOMEM;
|
return -ENOMEM;
|
||||||
}
|
}
|
||||||
@@ -484,20 +507,34 @@ static int nvgpu_prepare_default_dev_node_class_list(struct gk20a *g, u32 *num_c
|
|||||||
count++;
|
count++;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (power_node) {
|
||||||
|
class->power_node = true;
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* V2 device node names hierarchy.
|
* V2 device node names hierarchy.
|
||||||
* This hierarchy will replace above hierarchy in second phase.
|
* This hierarchy will replace above hierarchy in second phase.
|
||||||
* Both legacy and V2 device node hierarchies will co-exist until then.
|
* Both legacy and V2 device node hierarchies will co-exist until then.
|
||||||
*/
|
*/
|
||||||
if (g->pci_class != 0U) {
|
if (g->pci_class != 0U) {
|
||||||
class = nvgpu_create_class(g, "nvidia-pci-gpu-v2");
|
if (power_node) {
|
||||||
|
class = nvgpu_create_class(g, "nvidia-pci-gpu-v2-power");
|
||||||
|
} else {
|
||||||
|
class = nvgpu_create_class(g, "nvidia-pci-gpu-v2");
|
||||||
|
}
|
||||||
|
|
||||||
if (class == NULL) {
|
if (class == NULL) {
|
||||||
return -ENOMEM;
|
return -ENOMEM;
|
||||||
}
|
}
|
||||||
class->class->devnode = nvgpu_pci_devnode_v2;
|
class->class->devnode = nvgpu_pci_devnode_v2;
|
||||||
count++;
|
count++;
|
||||||
} else {
|
} else {
|
||||||
class = nvgpu_create_class(g, "nvidia-gpu-v2");
|
if (power_node) {
|
||||||
|
class = nvgpu_create_class(g, "nvidia-gpu-v2-power");
|
||||||
|
} else {
|
||||||
|
class = nvgpu_create_class(g, "nvidia-gpu-v2");
|
||||||
|
}
|
||||||
|
|
||||||
if (class == NULL) {
|
if (class == NULL) {
|
||||||
return -ENOMEM;
|
return -ENOMEM;
|
||||||
}
|
}
|
||||||
@@ -505,18 +542,23 @@ static int nvgpu_prepare_default_dev_node_class_list(struct gk20a *g, u32 *num_c
|
|||||||
count++;
|
count++;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (power_node) {
|
||||||
|
class->power_node = true;
|
||||||
|
}
|
||||||
|
|
||||||
*num_classes = count;
|
*num_classes = count;
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int nvgpu_prepare_dev_node_class_list(struct gk20a *g, u32 *num_classes)
|
static int nvgpu_prepare_dev_node_class_list(struct gk20a *g, u32 *num_classes,
|
||||||
|
bool power_node)
|
||||||
{
|
{
|
||||||
int err;
|
int err;
|
||||||
|
|
||||||
if (nvgpu_is_enabled(g, NVGPU_SUPPORT_MIG)) {
|
if (nvgpu_is_enabled(g, NVGPU_SUPPORT_MIG)) {
|
||||||
err = nvgpu_prepare_mig_dev_node_class_list(g, num_classes);
|
err = nvgpu_prepare_mig_dev_node_class_list(g, num_classes);
|
||||||
} else {
|
} else {
|
||||||
err = nvgpu_prepare_default_dev_node_class_list(g, num_classes);
|
err = nvgpu_prepare_default_dev_node_class_list(g, num_classes, power_node);
|
||||||
}
|
}
|
||||||
|
|
||||||
return err;
|
return err;
|
||||||
@@ -537,8 +579,12 @@ static bool check_valid_dev_node(struct gk20a *g, struct nvgpu_class *class,
|
|||||||
|
|
||||||
static bool check_valid_class(struct gk20a *g, struct nvgpu_class *class)
|
static bool check_valid_class(struct gk20a *g, struct nvgpu_class *class)
|
||||||
{
|
{
|
||||||
|
if (class->power_node) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
if (nvgpu_is_enabled(g, NVGPU_SUPPORT_MIG)) {
|
if (nvgpu_is_enabled(g, NVGPU_SUPPORT_MIG)) {
|
||||||
if (class->instance_type == NVGPU_MIG_TYPE_PHYSICAL) {
|
if ((class->instance_type == NVGPU_MIG_TYPE_PHYSICAL)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -546,6 +592,70 @@ static bool check_valid_class(struct gk20a *g, struct nvgpu_class *class)
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int gk20a_power_node_init(struct device *dev)
|
||||||
|
{
|
||||||
|
int err;
|
||||||
|
dev_t devno;
|
||||||
|
struct gk20a *g = gk20a_from_dev(dev);
|
||||||
|
struct nvgpu_os_linux *l = nvgpu_os_linux_from_gk20a(g);
|
||||||
|
struct nvgpu_class *class;
|
||||||
|
u32 total_cdevs;
|
||||||
|
u32 num_classes;
|
||||||
|
struct nvgpu_cdev *cdev;
|
||||||
|
|
||||||
|
if (!l->cdev_list_init_done) {
|
||||||
|
nvgpu_init_list_node(&l->cdev_list_head);
|
||||||
|
nvgpu_init_list_node(&l->class_list_head);
|
||||||
|
l->cdev_list_init_done = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
err = nvgpu_prepare_dev_node_class_list(g, &num_classes, true);
|
||||||
|
if (err != 0) {
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
|
||||||
|
total_cdevs = num_classes;
|
||||||
|
err = alloc_chrdev_region(&devno, 0, total_cdevs, dev_name(dev));
|
||||||
|
|
||||||
|
if (err) {
|
||||||
|
dev_err(dev, "failed to allocate devno\n");
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
|
|
||||||
|
l->cdev_region = devno;
|
||||||
|
nvgpu_list_for_each_entry(class, &l->class_list_head, nvgpu_class, list_entry) {
|
||||||
|
cdev = nvgpu_kzalloc(g, sizeof(*cdev));
|
||||||
|
if (cdev == NULL) {
|
||||||
|
dev_err(dev, "failed to allocate cdev\n");
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* dev_node_list[0] is the power node to issue
|
||||||
|
* power-on to the GPU.
|
||||||
|
*/
|
||||||
|
err = gk20a_create_device(dev, devno++,
|
||||||
|
dev_node_list[0].name,
|
||||||
|
&cdev->cdev, &cdev->node,
|
||||||
|
dev_node_list[0].fops,
|
||||||
|
class);
|
||||||
|
if (err) {
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
|
|
||||||
|
cdev->class = class->class;
|
||||||
|
nvgpu_init_list_node(&cdev->list_entry);
|
||||||
|
nvgpu_list_add(&cdev->list_entry, &l->cdev_list_head);
|
||||||
|
}
|
||||||
|
|
||||||
|
l->num_cdevs = total_cdevs;
|
||||||
|
return 0;
|
||||||
|
fail:
|
||||||
|
gk20a_user_deinit(dev);
|
||||||
|
return err;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
int gk20a_user_init(struct device *dev)
|
int gk20a_user_init(struct device *dev)
|
||||||
{
|
{
|
||||||
int err;
|
int err;
|
||||||
@@ -558,10 +668,13 @@ int gk20a_user_init(struct device *dev)
|
|||||||
struct nvgpu_cdev *cdev;
|
struct nvgpu_cdev *cdev;
|
||||||
u32 cdev_index;
|
u32 cdev_index;
|
||||||
|
|
||||||
nvgpu_init_list_node(&l->cdev_list_head);
|
if (!l->cdev_list_init_done) {
|
||||||
nvgpu_init_list_node(&l->class_list_head);
|
nvgpu_init_list_node(&l->cdev_list_head);
|
||||||
|
nvgpu_init_list_node(&l->class_list_head);
|
||||||
|
l->cdev_list_init_done = true;
|
||||||
|
}
|
||||||
|
|
||||||
err = nvgpu_prepare_dev_node_class_list(g, &num_classes);
|
err = nvgpu_prepare_dev_node_class_list(g, &num_classes, false);
|
||||||
if (err != 0) {
|
if (err != 0) {
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
@@ -581,7 +694,11 @@ int gk20a_user_init(struct device *dev)
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
for (cdev_index = 0; cdev_index < num_cdevs; cdev_index++) {
|
/*
|
||||||
|
* As we created the power node with power class already, the
|
||||||
|
* index is starting from one.
|
||||||
|
*/
|
||||||
|
for (cdev_index = 1; cdev_index < num_cdevs; cdev_index++) {
|
||||||
if (!check_valid_dev_node(g, class, &dev_node_list[cdev_index])) {
|
if (!check_valid_dev_node(g, class, &dev_node_list[cdev_index])) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
@@ -607,7 +724,7 @@ int gk20a_user_init(struct device *dev)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
l->num_cdevs = total_cdevs;
|
l->num_cdevs += total_cdevs;
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
fail:
|
fail:
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright (c) 2017, NVIDIA CORPORATION. All rights reserved.
|
* Copyright (c) 2017-2021, NVIDIA CORPORATION. All rights reserved.
|
||||||
*
|
*
|
||||||
* This program is free software; you can redistribute it and/or modify it
|
* This program is free software; you can redistribute it and/or modify it
|
||||||
* under the terms and conditions of the GNU General Public License,
|
* under the terms and conditions of the GNU General Public License,
|
||||||
@@ -50,6 +50,7 @@ struct nvgpu_class {
|
|||||||
struct nvgpu_cdev_class_priv_data *priv_data;
|
struct nvgpu_cdev_class_priv_data *priv_data;
|
||||||
|
|
||||||
enum nvgpu_mig_gpu_instance_type instance_type;
|
enum nvgpu_mig_gpu_instance_type instance_type;
|
||||||
|
bool power_node;
|
||||||
};
|
};
|
||||||
|
|
||||||
static inline struct nvgpu_class *
|
static inline struct nvgpu_class *
|
||||||
@@ -60,6 +61,7 @@ nvgpu_class_from_list_entry(struct nvgpu_list_node *node)
|
|||||||
};
|
};
|
||||||
|
|
||||||
int gk20a_user_init(struct device *dev);
|
int gk20a_user_init(struct device *dev);
|
||||||
|
int gk20a_power_node_init(struct device *dev);
|
||||||
void gk20a_user_deinit(struct device *dev);
|
void gk20a_user_deinit(struct device *dev);
|
||||||
|
|
||||||
struct gk20a *nvgpu_get_gk20a_from_cdev(struct nvgpu_cdev *cdev);
|
struct gk20a *nvgpu_get_gk20a_from_cdev(struct nvgpu_cdev *cdev);
|
||||||
|
|||||||
@@ -438,6 +438,18 @@ int gk20a_pm_finalize_poweron(struct device *dev)
|
|||||||
if (err)
|
if (err)
|
||||||
goto done;
|
goto done;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* TODO: Need to add nvgpu_early_poweron() sequence before
|
||||||
|
* creating device nodes.
|
||||||
|
*/
|
||||||
|
if (!l->dev_nodes_created) {
|
||||||
|
err = gk20a_user_init(dev);
|
||||||
|
if (err) {
|
||||||
|
goto done;
|
||||||
|
}
|
||||||
|
l->dev_nodes_created = true;
|
||||||
|
}
|
||||||
|
|
||||||
if (g->sim) {
|
if (g->sim) {
|
||||||
if (g->sim->sim_init_late)
|
if (g->sim->sim_init_late)
|
||||||
err = g->sim->sim_init_late(g);
|
err = g->sim->sim_init_late(g);
|
||||||
@@ -530,6 +542,9 @@ done:
|
|||||||
if (err != 0) {
|
if (err != 0) {
|
||||||
nvgpu_disable_irqs(g);
|
nvgpu_disable_irqs(g);
|
||||||
nvgpu_remove_sim_support_linux(g);
|
nvgpu_remove_sim_support_linux(g);
|
||||||
|
if (l->dev_nodes_created) {
|
||||||
|
gk20a_user_deinit(dev);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
nvgpu_mutex_release(&g->power_lock);
|
nvgpu_mutex_release(&g->power_lock);
|
||||||
|
|||||||
@@ -78,6 +78,8 @@ struct nvgpu_os_linux {
|
|||||||
struct nvgpu_list_node class_list_head;
|
struct nvgpu_list_node class_list_head;
|
||||||
struct nvgpu_list_node cdev_list_head;
|
struct nvgpu_list_node cdev_list_head;
|
||||||
u32 num_cdevs;
|
u32 num_cdevs;
|
||||||
|
bool dev_nodes_created;
|
||||||
|
bool cdev_list_init_done;
|
||||||
|
|
||||||
dev_t cdev_region;
|
dev_t cdev_region;
|
||||||
|
|
||||||
|
|||||||
154
drivers/gpu/nvgpu/os/linux/power_ops.c
Normal file
154
drivers/gpu/nvgpu/os/linux/power_ops.c
Normal file
@@ -0,0 +1,154 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2021, NVIDIA Corporation. All rights reserved.
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or modify it
|
||||||
|
* under the terms and conditions of the GNU General Public License,
|
||||||
|
* version 2, as published by the Free Software Foundation.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope it will be useful, but WITHOUT
|
||||||
|
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||||
|
* more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <linux/uaccess.h>
|
||||||
|
#include <linux/cdev.h>
|
||||||
|
#include <linux/file.h>
|
||||||
|
#include <linux/slab.h>
|
||||||
|
#include <linux/anon_inodes.h>
|
||||||
|
#include <linux/fs.h>
|
||||||
|
#include <uapi/linux/nvgpu.h>
|
||||||
|
|
||||||
|
#include <nvgpu/kmem.h>
|
||||||
|
#include <nvgpu/log.h>
|
||||||
|
#include <nvgpu/enabled.h>
|
||||||
|
#include <nvgpu/sizes.h>
|
||||||
|
#include <nvgpu/list.h>
|
||||||
|
#include <nvgpu/gk20a.h>
|
||||||
|
#include <nvgpu/nvgpu_init.h>
|
||||||
|
|
||||||
|
#include "ioctl.h"
|
||||||
|
|
||||||
|
#include "platform_gk20a.h"
|
||||||
|
#include "os_linux.h"
|
||||||
|
|
||||||
|
#define NVGPU_DRIVER_POWER_ON_NEEDED 1
|
||||||
|
|
||||||
|
int gk20a_power_open(struct inode *inode, struct file *filp)
|
||||||
|
{
|
||||||
|
struct gk20a *g;
|
||||||
|
struct nvgpu_cdev *cdev;
|
||||||
|
|
||||||
|
cdev = container_of(inode->i_cdev, struct nvgpu_cdev, cdev);
|
||||||
|
g = nvgpu_get_gk20a_from_cdev(cdev);
|
||||||
|
filp->private_data = g;
|
||||||
|
|
||||||
|
g = nvgpu_get(g);
|
||||||
|
if (!g) {
|
||||||
|
return -ENODEV;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int gk20a_power_read(struct file *filp, char __user *buf,
|
||||||
|
size_t size, loff_t *off)
|
||||||
|
{
|
||||||
|
struct gk20a *g = filp->private_data;
|
||||||
|
u32 power_status = 0U;
|
||||||
|
char power_out[2] = "";
|
||||||
|
|
||||||
|
if (!g) {
|
||||||
|
return -ENODEV;
|
||||||
|
}
|
||||||
|
|
||||||
|
power_status = g->power_on_state;
|
||||||
|
power_out[0] = power_status + '0';
|
||||||
|
|
||||||
|
if (size < sizeof(power_out)) {
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (*off >= (loff_t)sizeof(power_out)) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (*off + (loff_t)size > (loff_t)sizeof(power_out)) {
|
||||||
|
size = sizeof(u32) - *off;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (copy_to_user(buf, (char *)power_out + *off, size)) {
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
|
||||||
|
*off += size;
|
||||||
|
return size;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
int gk20a_power_write(struct file *filp, const char __user *buf,
|
||||||
|
size_t size, loff_t *off)
|
||||||
|
{
|
||||||
|
struct gk20a *g = filp->private_data;
|
||||||
|
u32 power_status = 0U;
|
||||||
|
int err = 0;
|
||||||
|
unsigned char *userinput = NULL;
|
||||||
|
|
||||||
|
if (!g) {
|
||||||
|
return -ENODEV;
|
||||||
|
}
|
||||||
|
|
||||||
|
userinput = (unsigned char *)kzalloc(size, GFP_KERNEL);
|
||||||
|
if (!userinput) {
|
||||||
|
return -ENOMEM;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (copy_from_user(userinput, buf, size)) {
|
||||||
|
kfree(userinput);
|
||||||
|
return -EFAULT;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (kstrtouint(userinput, 10, &power_status)) {
|
||||||
|
kfree(userinput);
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (power_status == NVGPU_DRIVER_POWER_ON_NEEDED) {
|
||||||
|
if ((g->power_on_state == NVGPU_STATE_POWERING_ON) ||
|
||||||
|
(g->power_on_state == NVGPU_STATE_POWERED_ON)) {
|
||||||
|
goto free_input;
|
||||||
|
}
|
||||||
|
|
||||||
|
err = gk20a_busy(g);
|
||||||
|
if (err) {
|
||||||
|
nvgpu_err(g, "power_node_write failed at busy");
|
||||||
|
kfree(userinput);
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
|
||||||
|
gk20a_idle(g);
|
||||||
|
} else {
|
||||||
|
nvgpu_err(g, "1 is the valid value to power-on the GPU");
|
||||||
|
kfree(userinput);
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
|
||||||
|
free_input:
|
||||||
|
*off += size;
|
||||||
|
kfree(userinput);
|
||||||
|
return size;
|
||||||
|
}
|
||||||
|
|
||||||
|
int gk20a_power_release(struct inode *inode, struct file *filp)
|
||||||
|
{
|
||||||
|
struct gk20a *g;
|
||||||
|
struct nvgpu_cdev *cdev;
|
||||||
|
|
||||||
|
cdev = container_of(inode->i_cdev, struct nvgpu_cdev, cdev);
|
||||||
|
g = nvgpu_get_gk20a_from_cdev(cdev);
|
||||||
|
nvgpu_put(g);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
29
drivers/gpu/nvgpu/os/linux/power_ops.h
Normal file
29
drivers/gpu/nvgpu/os/linux/power_ops.h
Normal file
@@ -0,0 +1,29 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2021, NVIDIA Corporation. All rights reserved.
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or modify it
|
||||||
|
* under the terms and conditions of the GNU General Public License,
|
||||||
|
* version 2, as published by the Free Software Foundation.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope it will be useful, but WITHOUT
|
||||||
|
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||||
|
* more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef NVGPU_POWER_LINUX_H
|
||||||
|
#define NVGPU_POWER_LINUX_H
|
||||||
|
|
||||||
|
#include <nvgpu/types.h>
|
||||||
|
|
||||||
|
int gk20a_power_open(struct inode *inode, struct file *filp);
|
||||||
|
ssize_t gk20a_power_read(struct file *filp, char __user *buf,
|
||||||
|
size_t size, loff_t *off);
|
||||||
|
ssize_t gk20a_power_write(struct file *filp, const char __user *buf,
|
||||||
|
size_t size, loff_t *off);
|
||||||
|
int gk20a_power_release(struct inode *inode, struct file *filp);
|
||||||
|
|
||||||
|
#endif
|
||||||
Reference in New Issue
Block a user