mirror of
git://nv-tegra.nvidia.com/linux-nvgpu.git
synced 2025-12-23 09:57:08 +03:00
gpu: nvgpu: Move devnode creation to Linux module
Move Linux specific code to create devnodes to Linux module. JIRA NVGPU-16 Change-Id: I7f8f74d72f16857973da029b9f949ee8b553eb59 Signed-off-by: Terje Bergstrom <tbergstrom@nvidia.com> Reviewed-on: http://git-master/r/1330801 Reviewed-by: svccoveritychecker <svccoveritychecker@nvidia.com> GVS: Gerrit_Virtual_Submit
This commit is contained in:
committed by
mobile promotions
parent
dd88aed5cc
commit
9adc49f94b
@@ -25,6 +25,7 @@ obj-$(CONFIG_GK20A) := nvgpu.o
|
|||||||
nvgpu-y := \
|
nvgpu-y := \
|
||||||
common/linux/kmem.o \
|
common/linux/kmem.o \
|
||||||
common/linux/timers.o \
|
common/linux/timers.o \
|
||||||
|
common/linux/ioctl.o \
|
||||||
common/mm/nvgpu_allocator.o \
|
common/mm/nvgpu_allocator.o \
|
||||||
common/mm/bitmap_allocator.o \
|
common/mm/bitmap_allocator.o \
|
||||||
common/mm/buddy_allocator.o \
|
common/mm/buddy_allocator.o \
|
||||||
|
|||||||
285
drivers/gpu/nvgpu/common/linux/ioctl.c
Normal file
285
drivers/gpu/nvgpu/common/linux/ioctl.c
Normal file
@@ -0,0 +1,285 @@
|
|||||||
|
/*
|
||||||
|
* NVGPU IOCTLs
|
||||||
|
*
|
||||||
|
* Copyright (c) 2011-2017, 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/file.h>
|
||||||
|
|
||||||
|
#include <nvgpu/nvgpu_common.h>
|
||||||
|
|
||||||
|
#include "gk20a/gk20a.h"
|
||||||
|
#include "gk20a/dbg_gpu_gk20a.h"
|
||||||
|
#include "gk20a/ctxsw_trace_gk20a.h"
|
||||||
|
#include "gk20a/channel_gk20a.h"
|
||||||
|
#include "gk20a/ctrl_gk20a.h"
|
||||||
|
#include "gk20a/as_gk20a.h"
|
||||||
|
#include "gk20a/tsg_gk20a.h"
|
||||||
|
|
||||||
|
#define GK20A_NUM_CDEVS 7
|
||||||
|
|
||||||
|
const struct file_operations gk20a_channel_ops = {
|
||||||
|
.owner = THIS_MODULE,
|
||||||
|
.release = gk20a_channel_release,
|
||||||
|
.open = gk20a_channel_open,
|
||||||
|
#ifdef CONFIG_COMPAT
|
||||||
|
.compat_ioctl = gk20a_channel_ioctl,
|
||||||
|
#endif
|
||||||
|
.unlocked_ioctl = gk20a_channel_ioctl,
|
||||||
|
};
|
||||||
|
|
||||||
|
static const struct file_operations gk20a_ctrl_ops = {
|
||||||
|
.owner = THIS_MODULE,
|
||||||
|
.release = gk20a_ctrl_dev_release,
|
||||||
|
.open = gk20a_ctrl_dev_open,
|
||||||
|
.unlocked_ioctl = gk20a_ctrl_dev_ioctl,
|
||||||
|
#ifdef CONFIG_COMPAT
|
||||||
|
.compat_ioctl = gk20a_ctrl_dev_ioctl,
|
||||||
|
#endif
|
||||||
|
};
|
||||||
|
|
||||||
|
static const struct file_operations gk20a_dbg_ops = {
|
||||||
|
.owner = THIS_MODULE,
|
||||||
|
.release = gk20a_dbg_gpu_dev_release,
|
||||||
|
.open = gk20a_dbg_gpu_dev_open,
|
||||||
|
.unlocked_ioctl = gk20a_dbg_gpu_dev_ioctl,
|
||||||
|
.poll = gk20a_dbg_gpu_dev_poll,
|
||||||
|
#ifdef CONFIG_COMPAT
|
||||||
|
.compat_ioctl = gk20a_dbg_gpu_dev_ioctl,
|
||||||
|
#endif
|
||||||
|
};
|
||||||
|
|
||||||
|
static const struct file_operations gk20a_as_ops = {
|
||||||
|
.owner = THIS_MODULE,
|
||||||
|
.release = gk20a_as_dev_release,
|
||||||
|
.open = gk20a_as_dev_open,
|
||||||
|
#ifdef CONFIG_COMPAT
|
||||||
|
.compat_ioctl = gk20a_as_dev_ioctl,
|
||||||
|
#endif
|
||||||
|
.unlocked_ioctl = gk20a_as_dev_ioctl,
|
||||||
|
};
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Note: We use a different 'open' to trigger handling of the profiler session.
|
||||||
|
* Most of the code is shared between them... Though, at some point if the
|
||||||
|
* code does get too tangled trying to handle each in the same path we can
|
||||||
|
* separate them cleanly.
|
||||||
|
*/
|
||||||
|
static const struct file_operations gk20a_prof_ops = {
|
||||||
|
.owner = THIS_MODULE,
|
||||||
|
.release = gk20a_dbg_gpu_dev_release,
|
||||||
|
.open = gk20a_prof_gpu_dev_open,
|
||||||
|
.unlocked_ioctl = gk20a_dbg_gpu_dev_ioctl,
|
||||||
|
#ifdef CONFIG_COMPAT
|
||||||
|
.compat_ioctl = gk20a_dbg_gpu_dev_ioctl,
|
||||||
|
#endif
|
||||||
|
};
|
||||||
|
|
||||||
|
static const struct file_operations gk20a_tsg_ops = {
|
||||||
|
.owner = THIS_MODULE,
|
||||||
|
.release = gk20a_tsg_dev_release,
|
||||||
|
.open = gk20a_tsg_dev_open,
|
||||||
|
#ifdef CONFIG_COMPAT
|
||||||
|
.compat_ioctl = gk20a_tsg_dev_ioctl,
|
||||||
|
#endif
|
||||||
|
.unlocked_ioctl = gk20a_tsg_dev_ioctl,
|
||||||
|
};
|
||||||
|
|
||||||
|
static const struct file_operations gk20a_ctxsw_ops = {
|
||||||
|
.owner = THIS_MODULE,
|
||||||
|
.release = gk20a_ctxsw_dev_release,
|
||||||
|
.open = gk20a_ctxsw_dev_open,
|
||||||
|
#ifdef CONFIG_COMPAT
|
||||||
|
.compat_ioctl = gk20a_ctxsw_dev_ioctl,
|
||||||
|
#endif
|
||||||
|
.unlocked_ioctl = gk20a_ctxsw_dev_ioctl,
|
||||||
|
.poll = gk20a_ctxsw_dev_poll,
|
||||||
|
.read = gk20a_ctxsw_dev_read,
|
||||||
|
.mmap = gk20a_ctxsw_dev_mmap,
|
||||||
|
};
|
||||||
|
|
||||||
|
static const struct file_operations gk20a_sched_ops = {
|
||||||
|
.owner = THIS_MODULE,
|
||||||
|
.release = gk20a_sched_dev_release,
|
||||||
|
.open = gk20a_sched_dev_open,
|
||||||
|
#ifdef CONFIG_COMPAT
|
||||||
|
.compat_ioctl = gk20a_sched_dev_ioctl,
|
||||||
|
#endif
|
||||||
|
.unlocked_ioctl = gk20a_sched_dev_ioctl,
|
||||||
|
.poll = gk20a_sched_dev_poll,
|
||||||
|
.read = gk20a_sched_dev_read,
|
||||||
|
};
|
||||||
|
|
||||||
|
static int gk20a_create_device(
|
||||||
|
struct device *dev, int devno,
|
||||||
|
const char *interface_name, const char *cdev_name,
|
||||||
|
struct cdev *cdev, struct device **out,
|
||||||
|
const struct file_operations *ops,
|
||||||
|
struct class *class)
|
||||||
|
{
|
||||||
|
struct device *subdev;
|
||||||
|
int err;
|
||||||
|
|
||||||
|
gk20a_dbg_fn("");
|
||||||
|
|
||||||
|
cdev_init(cdev, ops);
|
||||||
|
cdev->owner = THIS_MODULE;
|
||||||
|
|
||||||
|
err = cdev_add(cdev, devno, 1);
|
||||||
|
if (err) {
|
||||||
|
dev_err(dev, "failed to add %s cdev\n", cdev_name);
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
|
||||||
|
subdev = device_create(class, NULL, devno, NULL,
|
||||||
|
interface_name, cdev_name);
|
||||||
|
|
||||||
|
if (IS_ERR(subdev)) {
|
||||||
|
err = PTR_ERR(dev);
|
||||||
|
cdev_del(cdev);
|
||||||
|
dev_err(dev, "failed to create %s device for %s\n",
|
||||||
|
cdev_name, dev_name(dev));
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
|
||||||
|
*out = subdev;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void gk20a_user_deinit(struct device *dev, struct class *class)
|
||||||
|
{
|
||||||
|
struct gk20a *g = gk20a_from_dev(dev);
|
||||||
|
|
||||||
|
if (g->channel.node) {
|
||||||
|
device_destroy(class, g->channel.cdev.dev);
|
||||||
|
cdev_del(&g->channel.cdev);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (g->as.node) {
|
||||||
|
device_destroy(class, g->as.cdev.dev);
|
||||||
|
cdev_del(&g->as.cdev);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (g->ctrl.node) {
|
||||||
|
device_destroy(class, g->ctrl.cdev.dev);
|
||||||
|
cdev_del(&g->ctrl.cdev);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (g->dbg.node) {
|
||||||
|
device_destroy(class, g->dbg.cdev.dev);
|
||||||
|
cdev_del(&g->dbg.cdev);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (g->prof.node) {
|
||||||
|
device_destroy(class, g->prof.cdev.dev);
|
||||||
|
cdev_del(&g->prof.cdev);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (g->tsg.node) {
|
||||||
|
device_destroy(class, g->tsg.cdev.dev);
|
||||||
|
cdev_del(&g->tsg.cdev);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (g->ctxsw.node) {
|
||||||
|
device_destroy(class, g->ctxsw.cdev.dev);
|
||||||
|
cdev_del(&g->ctxsw.cdev);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (g->sched.node) {
|
||||||
|
device_destroy(class, g->sched.cdev.dev);
|
||||||
|
cdev_del(&g->sched.cdev);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (g->cdev_region)
|
||||||
|
unregister_chrdev_region(g->cdev_region, GK20A_NUM_CDEVS);
|
||||||
|
}
|
||||||
|
|
||||||
|
int gk20a_user_init(struct device *dev, const char *interface_name,
|
||||||
|
struct class *class)
|
||||||
|
{
|
||||||
|
int err;
|
||||||
|
dev_t devno;
|
||||||
|
struct gk20a *g = gk20a_from_dev(dev);
|
||||||
|
|
||||||
|
err = alloc_chrdev_region(&devno, 0, GK20A_NUM_CDEVS, dev_name(dev));
|
||||||
|
if (err) {
|
||||||
|
dev_err(dev, "failed to allocate devno\n");
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
|
g->cdev_region = devno;
|
||||||
|
|
||||||
|
err = gk20a_create_device(dev, devno++, interface_name, "",
|
||||||
|
&g->channel.cdev, &g->channel.node,
|
||||||
|
&gk20a_channel_ops,
|
||||||
|
class);
|
||||||
|
if (err)
|
||||||
|
goto fail;
|
||||||
|
|
||||||
|
err = gk20a_create_device(dev, devno++, interface_name, "-as",
|
||||||
|
&g->as.cdev, &g->as.node,
|
||||||
|
&gk20a_as_ops,
|
||||||
|
class);
|
||||||
|
if (err)
|
||||||
|
goto fail;
|
||||||
|
|
||||||
|
err = gk20a_create_device(dev, devno++, interface_name, "-ctrl",
|
||||||
|
&g->ctrl.cdev, &g->ctrl.node,
|
||||||
|
&gk20a_ctrl_ops,
|
||||||
|
class);
|
||||||
|
if (err)
|
||||||
|
goto fail;
|
||||||
|
|
||||||
|
err = gk20a_create_device(dev, devno++, interface_name, "-dbg",
|
||||||
|
&g->dbg.cdev, &g->dbg.node,
|
||||||
|
&gk20a_dbg_ops,
|
||||||
|
class);
|
||||||
|
if (err)
|
||||||
|
goto fail;
|
||||||
|
|
||||||
|
err = gk20a_create_device(dev, devno++, interface_name, "-prof",
|
||||||
|
&g->prof.cdev, &g->prof.node,
|
||||||
|
&gk20a_prof_ops,
|
||||||
|
class);
|
||||||
|
if (err)
|
||||||
|
goto fail;
|
||||||
|
|
||||||
|
err = gk20a_create_device(dev, devno++, interface_name, "-tsg",
|
||||||
|
&g->tsg.cdev, &g->tsg.node,
|
||||||
|
&gk20a_tsg_ops,
|
||||||
|
class);
|
||||||
|
if (err)
|
||||||
|
goto fail;
|
||||||
|
|
||||||
|
#ifdef CONFIG_GK20A_CTXSW_TRACE
|
||||||
|
err = gk20a_create_device(dev, devno++, interface_name, "-ctxsw",
|
||||||
|
&g->ctxsw.cdev, &g->ctxsw.node,
|
||||||
|
&gk20a_ctxsw_ops,
|
||||||
|
class);
|
||||||
|
if (err)
|
||||||
|
goto fail;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
err = gk20a_create_device(dev, devno++, interface_name, "-sched",
|
||||||
|
&g->sched.cdev, &g->sched.node,
|
||||||
|
&gk20a_sched_ops,
|
||||||
|
class);
|
||||||
|
if (err)
|
||||||
|
goto fail;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
fail:
|
||||||
|
gk20a_user_deinit(dev, &nvgpu_class);
|
||||||
|
return err;
|
||||||
|
}
|
||||||
@@ -19,12 +19,10 @@
|
|||||||
#include <linux/module.h>
|
#include <linux/module.h>
|
||||||
#include <linux/dma-mapping.h>
|
#include <linux/dma-mapping.h>
|
||||||
#include <linux/string.h>
|
#include <linux/string.h>
|
||||||
#include <linux/cdev.h>
|
|
||||||
#include <linux/delay.h>
|
#include <linux/delay.h>
|
||||||
#include <linux/interrupt.h>
|
#include <linux/interrupt.h>
|
||||||
#include <linux/irq.h>
|
#include <linux/irq.h>
|
||||||
#include <linux/export.h>
|
#include <linux/export.h>
|
||||||
#include <linux/file.h>
|
|
||||||
#include <linux/of.h>
|
#include <linux/of.h>
|
||||||
#include <linux/of_device.h>
|
#include <linux/of_device.h>
|
||||||
#include <linux/of_platform.h>
|
#include <linux/of_platform.h>
|
||||||
@@ -48,7 +46,6 @@
|
|||||||
|
|
||||||
#include "gk20a.h"
|
#include "gk20a.h"
|
||||||
#include "debug_gk20a.h"
|
#include "debug_gk20a.h"
|
||||||
#include "ctrl_gk20a.h"
|
|
||||||
#include "channel_sync_gk20a.h"
|
#include "channel_sync_gk20a.h"
|
||||||
|
|
||||||
#include "gk20a_scale.h"
|
#include "gk20a_scale.h"
|
||||||
@@ -167,100 +164,6 @@ static inline void set_gk20a(struct platform_device *pdev, struct gk20a *gk20a)
|
|||||||
gk20a_get_platform(&pdev->dev)->g = gk20a;
|
gk20a_get_platform(&pdev->dev)->g = gk20a;
|
||||||
}
|
}
|
||||||
|
|
||||||
const struct file_operations gk20a_channel_ops = {
|
|
||||||
.owner = THIS_MODULE,
|
|
||||||
.release = gk20a_channel_release,
|
|
||||||
.open = gk20a_channel_open,
|
|
||||||
#ifdef CONFIG_COMPAT
|
|
||||||
.compat_ioctl = gk20a_channel_ioctl,
|
|
||||||
#endif
|
|
||||||
.unlocked_ioctl = gk20a_channel_ioctl,
|
|
||||||
};
|
|
||||||
|
|
||||||
static const struct file_operations gk20a_ctrl_ops = {
|
|
||||||
.owner = THIS_MODULE,
|
|
||||||
.release = gk20a_ctrl_dev_release,
|
|
||||||
.open = gk20a_ctrl_dev_open,
|
|
||||||
.unlocked_ioctl = gk20a_ctrl_dev_ioctl,
|
|
||||||
#ifdef CONFIG_COMPAT
|
|
||||||
.compat_ioctl = gk20a_ctrl_dev_ioctl,
|
|
||||||
#endif
|
|
||||||
};
|
|
||||||
|
|
||||||
static const struct file_operations gk20a_dbg_ops = {
|
|
||||||
.owner = THIS_MODULE,
|
|
||||||
.release = gk20a_dbg_gpu_dev_release,
|
|
||||||
.open = gk20a_dbg_gpu_dev_open,
|
|
||||||
.unlocked_ioctl = gk20a_dbg_gpu_dev_ioctl,
|
|
||||||
.poll = gk20a_dbg_gpu_dev_poll,
|
|
||||||
#ifdef CONFIG_COMPAT
|
|
||||||
.compat_ioctl = gk20a_dbg_gpu_dev_ioctl,
|
|
||||||
#endif
|
|
||||||
};
|
|
||||||
|
|
||||||
static const struct file_operations gk20a_as_ops = {
|
|
||||||
.owner = THIS_MODULE,
|
|
||||||
.release = gk20a_as_dev_release,
|
|
||||||
.open = gk20a_as_dev_open,
|
|
||||||
#ifdef CONFIG_COMPAT
|
|
||||||
.compat_ioctl = gk20a_as_dev_ioctl,
|
|
||||||
#endif
|
|
||||||
.unlocked_ioctl = gk20a_as_dev_ioctl,
|
|
||||||
};
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Note: We use a different 'open' to trigger handling of the profiler session.
|
|
||||||
* Most of the code is shared between them... Though, at some point if the
|
|
||||||
* code does get too tangled trying to handle each in the same path we can
|
|
||||||
* separate them cleanly.
|
|
||||||
*/
|
|
||||||
static const struct file_operations gk20a_prof_ops = {
|
|
||||||
.owner = THIS_MODULE,
|
|
||||||
.release = gk20a_dbg_gpu_dev_release,
|
|
||||||
.open = gk20a_prof_gpu_dev_open,
|
|
||||||
.unlocked_ioctl = gk20a_dbg_gpu_dev_ioctl,
|
|
||||||
/* .mmap = gk20a_prof_gpu_dev_mmap,*/
|
|
||||||
/*int (*mmap) (struct file *, struct vm_area_struct *);*/
|
|
||||||
#ifdef CONFIG_COMPAT
|
|
||||||
.compat_ioctl = gk20a_dbg_gpu_dev_ioctl,
|
|
||||||
#endif
|
|
||||||
};
|
|
||||||
|
|
||||||
static const struct file_operations gk20a_tsg_ops = {
|
|
||||||
.owner = THIS_MODULE,
|
|
||||||
.release = gk20a_tsg_dev_release,
|
|
||||||
.open = gk20a_tsg_dev_open,
|
|
||||||
#ifdef CONFIG_COMPAT
|
|
||||||
.compat_ioctl = gk20a_tsg_dev_ioctl,
|
|
||||||
#endif
|
|
||||||
.unlocked_ioctl = gk20a_tsg_dev_ioctl,
|
|
||||||
};
|
|
||||||
|
|
||||||
static const struct file_operations gk20a_ctxsw_ops = {
|
|
||||||
.owner = THIS_MODULE,
|
|
||||||
.release = gk20a_ctxsw_dev_release,
|
|
||||||
.open = gk20a_ctxsw_dev_open,
|
|
||||||
#ifdef CONFIG_COMPAT
|
|
||||||
.compat_ioctl = gk20a_ctxsw_dev_ioctl,
|
|
||||||
#endif
|
|
||||||
.unlocked_ioctl = gk20a_ctxsw_dev_ioctl,
|
|
||||||
.poll = gk20a_ctxsw_dev_poll,
|
|
||||||
.read = gk20a_ctxsw_dev_read,
|
|
||||||
.mmap = gk20a_ctxsw_dev_mmap,
|
|
||||||
};
|
|
||||||
|
|
||||||
static const struct file_operations gk20a_sched_ops = {
|
|
||||||
.owner = THIS_MODULE,
|
|
||||||
.release = gk20a_sched_dev_release,
|
|
||||||
.open = gk20a_sched_dev_open,
|
|
||||||
#ifdef CONFIG_COMPAT
|
|
||||||
.compat_ioctl = gk20a_sched_dev_ioctl,
|
|
||||||
#endif
|
|
||||||
.unlocked_ioctl = gk20a_sched_dev_ioctl,
|
|
||||||
.poll = gk20a_sched_dev_poll,
|
|
||||||
.read = gk20a_sched_dev_read,
|
|
||||||
};
|
|
||||||
|
|
||||||
void __nvgpu_check_gpu_state(struct gk20a *g)
|
void __nvgpu_check_gpu_state(struct gk20a *g)
|
||||||
{
|
{
|
||||||
u32 boot_0 = g->ops.mc.boot_0(g, NULL, NULL, NULL);
|
u32 boot_0 = g->ops.mc.boot_0(g, NULL, NULL, NULL);
|
||||||
@@ -773,168 +676,6 @@ static struct of_device_id tegra_gk20a_of_match[] = {
|
|||||||
{ },
|
{ },
|
||||||
};
|
};
|
||||||
|
|
||||||
static int gk20a_create_device(
|
|
||||||
struct device *dev, int devno,
|
|
||||||
const char *interface_name, const char *cdev_name,
|
|
||||||
struct cdev *cdev, struct device **out,
|
|
||||||
const struct file_operations *ops,
|
|
||||||
struct class *class)
|
|
||||||
{
|
|
||||||
struct device *subdev;
|
|
||||||
int err;
|
|
||||||
|
|
||||||
gk20a_dbg_fn("");
|
|
||||||
|
|
||||||
cdev_init(cdev, ops);
|
|
||||||
cdev->owner = THIS_MODULE;
|
|
||||||
|
|
||||||
err = cdev_add(cdev, devno, 1);
|
|
||||||
if (err) {
|
|
||||||
dev_err(dev, "failed to add %s cdev\n", cdev_name);
|
|
||||||
return err;
|
|
||||||
}
|
|
||||||
|
|
||||||
subdev = device_create(class, NULL, devno, NULL,
|
|
||||||
interface_name, cdev_name);
|
|
||||||
|
|
||||||
if (IS_ERR(subdev)) {
|
|
||||||
err = PTR_ERR(dev);
|
|
||||||
cdev_del(cdev);
|
|
||||||
dev_err(dev, "failed to create %s device\n",
|
|
||||||
cdev_name);
|
|
||||||
return err;
|
|
||||||
}
|
|
||||||
|
|
||||||
*out = subdev;
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
void gk20a_user_deinit(struct device *dev, struct class *class)
|
|
||||||
{
|
|
||||||
struct gk20a *g = gk20a_from_dev(dev);
|
|
||||||
|
|
||||||
if (g->channel.node) {
|
|
||||||
device_destroy(class, g->channel.cdev.dev);
|
|
||||||
cdev_del(&g->channel.cdev);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (g->as.node) {
|
|
||||||
device_destroy(class, g->as.cdev.dev);
|
|
||||||
cdev_del(&g->as.cdev);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (g->ctrl.node) {
|
|
||||||
device_destroy(class, g->ctrl.cdev.dev);
|
|
||||||
cdev_del(&g->ctrl.cdev);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (g->dbg.node) {
|
|
||||||
device_destroy(class, g->dbg.cdev.dev);
|
|
||||||
cdev_del(&g->dbg.cdev);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (g->prof.node) {
|
|
||||||
device_destroy(class, g->prof.cdev.dev);
|
|
||||||
cdev_del(&g->prof.cdev);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (g->tsg.node) {
|
|
||||||
device_destroy(class, g->tsg.cdev.dev);
|
|
||||||
cdev_del(&g->tsg.cdev);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (g->ctxsw.node) {
|
|
||||||
device_destroy(class, g->ctxsw.cdev.dev);
|
|
||||||
cdev_del(&g->ctxsw.cdev);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (g->sched.node) {
|
|
||||||
device_destroy(class, g->sched.cdev.dev);
|
|
||||||
cdev_del(&g->sched.cdev);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (g->cdev_region)
|
|
||||||
unregister_chrdev_region(g->cdev_region, GK20A_NUM_CDEVS);
|
|
||||||
}
|
|
||||||
|
|
||||||
int gk20a_user_init(struct device *dev, const char *interface_name,
|
|
||||||
struct class *class)
|
|
||||||
{
|
|
||||||
int err;
|
|
||||||
dev_t devno;
|
|
||||||
struct gk20a *g = gk20a_from_dev(dev);
|
|
||||||
|
|
||||||
err = alloc_chrdev_region(&devno, 0, GK20A_NUM_CDEVS, dev_name(dev));
|
|
||||||
if (err) {
|
|
||||||
dev_err(dev, "failed to allocate devno\n");
|
|
||||||
goto fail;
|
|
||||||
}
|
|
||||||
g->cdev_region = devno;
|
|
||||||
|
|
||||||
err = gk20a_create_device(dev, devno++, interface_name, "",
|
|
||||||
&g->channel.cdev, &g->channel.node,
|
|
||||||
&gk20a_channel_ops,
|
|
||||||
class);
|
|
||||||
if (err)
|
|
||||||
goto fail;
|
|
||||||
|
|
||||||
err = gk20a_create_device(dev, devno++, interface_name, "-as",
|
|
||||||
&g->as.cdev, &g->as.node,
|
|
||||||
&gk20a_as_ops,
|
|
||||||
class);
|
|
||||||
if (err)
|
|
||||||
goto fail;
|
|
||||||
|
|
||||||
err = gk20a_create_device(dev, devno++, interface_name, "-ctrl",
|
|
||||||
&g->ctrl.cdev, &g->ctrl.node,
|
|
||||||
&gk20a_ctrl_ops,
|
|
||||||
class);
|
|
||||||
if (err)
|
|
||||||
goto fail;
|
|
||||||
|
|
||||||
err = gk20a_create_device(dev, devno++, interface_name, "-dbg",
|
|
||||||
&g->dbg.cdev, &g->dbg.node,
|
|
||||||
&gk20a_dbg_ops,
|
|
||||||
class);
|
|
||||||
if (err)
|
|
||||||
goto fail;
|
|
||||||
|
|
||||||
err = gk20a_create_device(dev, devno++, interface_name, "-prof",
|
|
||||||
&g->prof.cdev, &g->prof.node,
|
|
||||||
&gk20a_prof_ops,
|
|
||||||
class);
|
|
||||||
if (err)
|
|
||||||
goto fail;
|
|
||||||
|
|
||||||
err = gk20a_create_device(dev, devno++, interface_name, "-tsg",
|
|
||||||
&g->tsg.cdev, &g->tsg.node,
|
|
||||||
&gk20a_tsg_ops,
|
|
||||||
class);
|
|
||||||
if (err)
|
|
||||||
goto fail;
|
|
||||||
|
|
||||||
#ifdef CONFIG_GK20A_CTXSW_TRACE
|
|
||||||
err = gk20a_create_device(dev, devno++, interface_name, "-ctxsw",
|
|
||||||
&g->ctxsw.cdev, &g->ctxsw.node,
|
|
||||||
&gk20a_ctxsw_ops,
|
|
||||||
class);
|
|
||||||
if (err)
|
|
||||||
goto fail;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
err = gk20a_create_device(dev, devno++, interface_name, "-sched",
|
|
||||||
&g->sched.cdev, &g->sched.node,
|
|
||||||
&gk20a_sched_ops,
|
|
||||||
class);
|
|
||||||
if (err)
|
|
||||||
goto fail;
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
fail:
|
|
||||||
gk20a_user_deinit(dev, &nvgpu_class);
|
|
||||||
return err;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int gk20a_pm_railgate(struct device *dev)
|
static int gk20a_pm_railgate(struct device *dev)
|
||||||
{
|
{
|
||||||
struct gk20a_platform *platform = dev_get_drvdata(dev);
|
struct gk20a_platform *platform = dev_get_drvdata(dev);
|
||||||
|
|||||||
Reference in New Issue
Block a user