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.h,
|
||||
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:
|
||||
sources: [ os/linux/kmem.c, os/linux/kmem_priv.h ]
|
||||
|
||||
@@ -419,7 +419,8 @@ nvgpu-y += \
|
||||
os/linux/ecc_sysfs.o \
|
||||
os/linux/bsearch.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
|
||||
|
||||
|
||||
@@ -268,6 +268,7 @@ int nvgpu_probe(struct gk20a *g,
|
||||
{
|
||||
struct device *dev = dev_from_gk20a(g);
|
||||
struct gk20a_platform *platform = dev_get_drvdata(dev);
|
||||
struct nvgpu_os_linux *l = nvgpu_os_linux_from_gk20a(g);
|
||||
int err = 0;
|
||||
|
||||
nvgpu_init_vars(g);
|
||||
@@ -294,11 +295,22 @@ int nvgpu_probe(struct gk20a *g,
|
||||
}
|
||||
|
||||
nvgpu_init_mm_vars(g);
|
||||
err = gk20a_power_node_init(dev);
|
||||
if (err) {
|
||||
nvgpu_err(g, "power_node creation failed");
|
||||
return err;
|
||||
}
|
||||
|
||||
/* platform probe can defer do user init only if probe succeeds */
|
||||
/*
|
||||
* 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
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
/*
|
||||
* 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
|
||||
* under the terms and conditions of the GNU General Public License,
|
||||
@@ -30,12 +30,21 @@
|
||||
#include "ioctl_tsg.h"
|
||||
#include "ioctl_dbg.h"
|
||||
#include "ioctl_prof.h"
|
||||
#include "power_ops.h"
|
||||
#include "ioctl.h"
|
||||
#include "module.h"
|
||||
#include "os_linux.h"
|
||||
#include "fecs_trace_linux.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 = {
|
||||
.owner = THIS_MODULE,
|
||||
.release = gk20a_channel_release,
|
||||
@@ -161,6 +170,7 @@ struct nvgpu_dev_node {
|
||||
};
|
||||
|
||||
static const struct nvgpu_dev_node dev_node_list[] = {
|
||||
{"power", &gk20a_power_node_ops, false },
|
||||
{"as", &gk20a_as_ops, false },
|
||||
{"channel", &gk20a_channel_ops, false },
|
||||
{"ctrl", &gk20a_ctrl_ops, true },
|
||||
@@ -332,6 +342,8 @@ void gk20a_user_deinit(struct device *dev)
|
||||
class_destroy(class->class);
|
||||
nvgpu_kfree(g, class);
|
||||
}
|
||||
|
||||
l->dev_nodes_created = false;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
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;
|
||||
u32 count = 0U;
|
||||
|
||||
if (g->pci_class != 0U) {
|
||||
if (power_node) {
|
||||
class = nvgpu_create_class(g, "nvidia-pci-gpu-power");
|
||||
} else {
|
||||
class = nvgpu_create_class(g, "nvidia-pci-gpu");
|
||||
}
|
||||
|
||||
if (class == NULL) {
|
||||
return -ENOMEM;
|
||||
}
|
||||
class->class->devnode = nvgpu_pci_devnode;
|
||||
count++;
|
||||
} else {
|
||||
if (power_node) {
|
||||
class = nvgpu_create_class(g, "nvidia-gpu-power");
|
||||
} else {
|
||||
class = nvgpu_create_class(g, "nvidia-gpu");
|
||||
}
|
||||
|
||||
if (class == NULL) {
|
||||
return -ENOMEM;
|
||||
}
|
||||
@@ -484,20 +507,34 @@ static int nvgpu_prepare_default_dev_node_class_list(struct gk20a *g, u32 *num_c
|
||||
count++;
|
||||
}
|
||||
|
||||
if (power_node) {
|
||||
class->power_node = true;
|
||||
}
|
||||
|
||||
/*
|
||||
* V2 device node names hierarchy.
|
||||
* This hierarchy will replace above hierarchy in second phase.
|
||||
* Both legacy and V2 device node hierarchies will co-exist until then.
|
||||
*/
|
||||
if (g->pci_class != 0U) {
|
||||
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) {
|
||||
return -ENOMEM;
|
||||
}
|
||||
class->class->devnode = nvgpu_pci_devnode_v2;
|
||||
count++;
|
||||
} else {
|
||||
if (power_node) {
|
||||
class = nvgpu_create_class(g, "nvidia-gpu-v2-power");
|
||||
} else {
|
||||
class = nvgpu_create_class(g, "nvidia-gpu-v2");
|
||||
}
|
||||
|
||||
if (class == NULL) {
|
||||
return -ENOMEM;
|
||||
}
|
||||
@@ -505,18 +542,23 @@ static int nvgpu_prepare_default_dev_node_class_list(struct gk20a *g, u32 *num_c
|
||||
count++;
|
||||
}
|
||||
|
||||
if (power_node) {
|
||||
class->power_node = true;
|
||||
}
|
||||
|
||||
*num_classes = count;
|
||||
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;
|
||||
|
||||
if (nvgpu_is_enabled(g, NVGPU_SUPPORT_MIG)) {
|
||||
err = nvgpu_prepare_mig_dev_node_class_list(g, num_classes);
|
||||
} 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;
|
||||
@@ -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)
|
||||
{
|
||||
if (class->power_node) {
|
||||
return false;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
||||
@@ -546,6 +592,70 @@ static bool check_valid_class(struct gk20a *g, struct nvgpu_class *class)
|
||||
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 err;
|
||||
@@ -558,10 +668,13 @@ int gk20a_user_init(struct device *dev)
|
||||
struct nvgpu_cdev *cdev;
|
||||
u32 cdev_index;
|
||||
|
||||
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);
|
||||
err = nvgpu_prepare_dev_node_class_list(g, &num_classes, false);
|
||||
if (err != 0) {
|
||||
return err;
|
||||
}
|
||||
@@ -581,7 +694,11 @@ int gk20a_user_init(struct device *dev)
|
||||
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])) {
|
||||
continue;
|
||||
}
|
||||
@@ -607,7 +724,7 @@ int gk20a_user_init(struct device *dev)
|
||||
}
|
||||
}
|
||||
|
||||
l->num_cdevs = total_cdevs;
|
||||
l->num_cdevs += total_cdevs;
|
||||
|
||||
return 0;
|
||||
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
|
||||
* 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;
|
||||
|
||||
enum nvgpu_mig_gpu_instance_type instance_type;
|
||||
bool power_node;
|
||||
};
|
||||
|
||||
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_power_node_init(struct device *dev);
|
||||
void gk20a_user_deinit(struct device *dev);
|
||||
|
||||
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)
|
||||
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->sim_init_late)
|
||||
err = g->sim->sim_init_late(g);
|
||||
@@ -530,6 +542,9 @@ done:
|
||||
if (err != 0) {
|
||||
nvgpu_disable_irqs(g);
|
||||
nvgpu_remove_sim_support_linux(g);
|
||||
if (l->dev_nodes_created) {
|
||||
gk20a_user_deinit(dev);
|
||||
}
|
||||
}
|
||||
|
||||
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 cdev_list_head;
|
||||
u32 num_cdevs;
|
||||
bool dev_nodes_created;
|
||||
bool cdev_list_init_done;
|
||||
|
||||
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