diff --git a/drivers/gpu/nvgpu/os/linux/fecs_trace_linux.c b/drivers/gpu/nvgpu/os/linux/fecs_trace_linux.c index 58a5df6ca..b00271d27 100644 --- a/drivers/gpu/nvgpu/os/linux/fecs_trace_linux.c +++ b/drivers/gpu/nvgpu/os/linux/fecs_trace_linux.c @@ -310,24 +310,25 @@ static int gk20a_ctxsw_dev_ioctl_poll(struct gk20a_ctxsw_dev *dev) int gk20a_ctxsw_dev_open(struct inode *inode, struct file *filp) { - struct nvgpu_os_linux *l; struct gk20a *g; struct gk20a_ctxsw_trace *trace; struct gk20a_ctxsw_dev *dev; int err; size_t size; u32 n; - /* only one VM for now */ const int vmid = 0; + struct nvgpu_cdev *cdev; - l = container_of(inode->i_cdev, struct nvgpu_os_linux, ctxsw.cdev); - g = nvgpu_get(&l->g); + cdev = container_of(inode->i_cdev, struct nvgpu_cdev, cdev); + g = get_gk20a(cdev->node->parent); + + g = nvgpu_get(g); if (!g) return -ENODEV; if (!nvgpu_is_enabled(g, NVGPU_SUPPORT_FECS_CTXSW_TRACE)) { - nvgpu_put(&l->g); + nvgpu_put(g); return -ENODEV; } diff --git a/drivers/gpu/nvgpu/os/linux/ioctl.c b/drivers/gpu/nvgpu/os/linux/ioctl.c index 22e4ad55c..bb3e8281a 100644 --- a/drivers/gpu/nvgpu/os/linux/ioctl.c +++ b/drivers/gpu/nvgpu/os/linux/ioctl.c @@ -33,8 +33,6 @@ #include "fecs_trace_linux.h" #include "platform_gk20a.h" -#define GK20A_NUM_CDEVS 10 - const struct file_operations gk20a_channel_ops = { .owner = THIS_MODULE, .release = gk20a_channel_release, @@ -67,7 +65,7 @@ static const struct file_operations gk20a_dbg_ops = { #endif }; -static const struct file_operations gk20a_as_ops = { +const struct file_operations gk20a_as_ops = { .owner = THIS_MODULE, .release = gk20a_as_dev_release, .open = gk20a_as_dev_open, @@ -150,6 +148,26 @@ static const struct file_operations gk20a_sched_ops = { .read = gk20a_sched_dev_read, }; +struct nvgpu_dev_node { + char name[20]; + const struct file_operations *fops; +}; + +static const struct nvgpu_dev_node dev_node_list[] = { + {"as", &gk20a_as_ops}, + {"channel", &gk20a_channel_ops}, + {"ctrl", &gk20a_ctrl_ops}, +#if defined(CONFIG_NVGPU_FECS_TRACE) + {"ctxsw", &gk20a_ctxsw_ops}, +#endif + {"dbg", &gk20a_dbg_ops}, + {"prof", &gk20a_prof_ops}, + {"prof-ctx", &gk20a_prof_ctx_ops}, + {"prof-dev", &gk20a_prof_dev_ops}, + {"sched", &gk20a_sched_ops}, + {"tsg", &gk20a_tsg_ops}, +}; + static char *nvgpu_devnode(const char *cdev_name) { /* Special case to maintain legacy names */ @@ -226,66 +244,28 @@ void gk20a_user_deinit(struct device *dev) struct gk20a *g = gk20a_from_dev(dev); struct nvgpu_os_linux *l = nvgpu_os_linux_from_gk20a(g); struct class *class = l->devnode_class; + struct nvgpu_cdev *cdev, *n; if (class == NULL) { return; } - if (l->channel.node) { - device_destroy(class, l->channel.cdev.dev); - cdev_del(&l->channel.cdev); + nvgpu_list_for_each_entry_safe(cdev, n, &l->cdev_list_head, nvgpu_cdev, list_entry) { + nvgpu_list_del(&cdev->list_entry); + + device_destroy(class, cdev->cdev.dev); + cdev_del(&cdev->cdev); + + nvgpu_kfree(g, cdev); } - if (l->as_dev.node) { - device_destroy(class, l->as_dev.cdev.dev); - cdev_del(&l->as_dev.cdev); + if (l->cdev_region) { + unregister_chrdev_region(l->cdev_region, l->num_cdevs); } - if (l->ctrl.node) { - device_destroy(class, l->ctrl.cdev.dev); - cdev_del(&l->ctrl.cdev); - } - - if (l->dbg.node) { - device_destroy(class, l->dbg.cdev.dev); - cdev_del(&l->dbg.cdev); - } - - if (l->prof.node) { - device_destroy(class, l->prof.cdev.dev); - cdev_del(&l->prof.cdev); - } - - if (l->prof_dev.node) { - device_destroy(class, l->prof_dev.cdev.dev); - cdev_del(&l->prof_dev.cdev); - } - - if (l->prof_ctx.node) { - device_destroy(class, l->prof_ctx.cdev.dev); - cdev_del(&l->prof_ctx.cdev); - } - - if (l->tsg.node) { - device_destroy(class, l->tsg.cdev.dev); - cdev_del(&l->tsg.cdev); - } - - if (l->ctxsw.node) { - device_destroy(class, l->ctxsw.cdev.dev); - cdev_del(&l->ctxsw.cdev); - } - - if (l->sched.node) { - device_destroy(class, l->sched.cdev.dev); - cdev_del(&l->sched.cdev); - } - - if (l->cdev_region) - unregister_chrdev_region(l->cdev_region, GK20A_NUM_CDEVS); - class_destroy(class); l->devnode_class = NULL; + l->num_cdevs = 0; } int gk20a_user_init(struct device *dev) @@ -295,6 +275,9 @@ int gk20a_user_init(struct device *dev) struct gk20a *g = gk20a_from_dev(dev); struct nvgpu_os_linux *l = nvgpu_os_linux_from_gk20a(g); struct class *class; + u32 num_cdevs; + struct nvgpu_cdev *cdev; + u32 cdev_index; if (g->pci_class != 0U) { class = class_create(THIS_MODULE, "nvidia-pci-gpu"); @@ -312,86 +295,38 @@ int gk20a_user_init(struct device *dev) class->devnode = NULL; } - err = alloc_chrdev_region(&devno, 0, GK20A_NUM_CDEVS, dev_name(dev)); + num_cdevs = sizeof(dev_node_list) / sizeof(dev_node_list[0]); + err = alloc_chrdev_region(&devno, 0, num_cdevs, dev_name(dev)); if (err) { dev_err(dev, "failed to allocate devno\n"); goto fail; } l->cdev_region = devno; - err = gk20a_create_device(dev, devno++, "channel", - &l->channel.cdev, &l->channel.node, - &gk20a_channel_ops, - class); - if (err) - goto fail; + nvgpu_init_list_node(&l->cdev_list_head); - err = gk20a_create_device(dev, devno++, "as", - &l->as_dev.cdev, &l->as_dev.node, - &gk20a_as_ops, - class); - if (err) - goto fail; + for (cdev_index = 0; cdev_index < num_cdevs; cdev_index++) { + cdev = nvgpu_kzalloc(g, sizeof(*cdev)); + if (cdev == NULL) { + dev_err(dev, "failed to allocate cdev\n"); + goto fail; + } - err = gk20a_create_device(dev, devno++, "ctrl", - &l->ctrl.cdev, &l->ctrl.node, - &gk20a_ctrl_ops, - class); - if (err) - goto fail; + err = gk20a_create_device(dev, devno++, dev_node_list[cdev_index].name, + &cdev->cdev, &cdev->node, + dev_node_list[cdev_index].fops, + class); + if (err) { + goto fail; + } - err = gk20a_create_device(dev, devno++, "dbg", - &l->dbg.cdev, &l->dbg.node, - &gk20a_dbg_ops, - class); - if (err) - goto fail; - - err = gk20a_create_device(dev, devno++, "prof", - &l->prof.cdev, &l->prof.node, - &gk20a_prof_ops, - class); - if (err) - goto fail; - - err = gk20a_create_device(dev, devno++, "prof-dev", - &l->prof_dev.cdev, &l->prof_dev.node, - &gk20a_prof_dev_ops, - class); - if (err) - goto fail; - - err = gk20a_create_device(dev, devno++, "prof-ctx", - &l->prof_ctx.cdev, &l->prof_ctx.node, - &gk20a_prof_ctx_ops, - class); - if (err) - goto fail; - - err = gk20a_create_device(dev, devno++, "tsg", - &l->tsg.cdev, &l->tsg.node, - &gk20a_tsg_ops, - class); - if (err) - goto fail; - -#if defined(CONFIG_NVGPU_FECS_TRACE) - err = gk20a_create_device(dev, devno++, "ctxsw", - &l->ctxsw.cdev, &l->ctxsw.node, - &gk20a_ctxsw_ops, - class); - if (err) - goto fail; -#endif - - err = gk20a_create_device(dev, devno++, "sched", - &l->sched.cdev, &l->sched.node, - &gk20a_sched_ops, - class); - if (err) - goto fail; + nvgpu_init_list_node(&cdev->list_entry); + nvgpu_list_add(&cdev->list_entry, &l->cdev_list_head); + } + l->num_cdevs = num_cdevs; l->devnode_class = class; + return 0; fail: gk20a_user_deinit(dev); diff --git a/drivers/gpu/nvgpu/os/linux/ioctl_as.c b/drivers/gpu/nvgpu/os/linux/ioctl_as.c index 85d634881..212f2b861 100644 --- a/drivers/gpu/nvgpu/os/linux/ioctl_as.c +++ b/drivers/gpu/nvgpu/os/linux/ioctl_as.c @@ -302,13 +302,13 @@ static int nvgpu_as_ioctl_get_sync_ro_map( int gk20a_as_dev_open(struct inode *inode, struct file *filp) { - struct nvgpu_os_linux *l; struct gk20a_as_share *as_share; struct gk20a *g; int err; + struct nvgpu_cdev *cdev; - l = container_of(inode->i_cdev, struct nvgpu_os_linux, as_dev.cdev); - g = &l->g; + cdev = container_of(inode->i_cdev, struct nvgpu_cdev, cdev); + g = get_gk20a(cdev->node->parent); nvgpu_log_fn(g, " "); diff --git a/drivers/gpu/nvgpu/os/linux/ioctl_channel.c b/drivers/gpu/nvgpu/os/linux/ioctl_channel.c index 969607a0d..f931b83bd 100644 --- a/drivers/gpu/nvgpu/os/linux/ioctl_channel.c +++ b/drivers/gpu/nvgpu/os/linux/ioctl_channel.c @@ -529,10 +529,12 @@ free_ref: int gk20a_channel_open(struct inode *inode, struct file *filp) { - struct nvgpu_os_linux *l = container_of(inode->i_cdev, - struct nvgpu_os_linux, channel.cdev); - struct gk20a *g = &l->g; + struct gk20a *g; int ret; + struct nvgpu_cdev *cdev; + + cdev = container_of(inode->i_cdev, struct nvgpu_cdev, cdev); + g = get_gk20a(cdev->node->parent); nvgpu_log_fn(g, "start"); ret = __gk20a_channel_open(g, filp, -1); @@ -549,7 +551,6 @@ int gk20a_channel_open_ioctl(struct gk20a *g, struct file *file; char name[64]; s32 runlist_id = args->in.runlist_id; - struct nvgpu_os_linux *l = nvgpu_os_linux_from_gk20a(g); err = get_unused_fd_flags(O_RDWR); if (err < 0) @@ -559,7 +560,7 @@ int gk20a_channel_open_ioctl(struct gk20a *g, (void) snprintf(name, sizeof(name), "nvhost-%s-fd%d", dev_name(dev_from_gk20a(g)), fd); - file = anon_inode_getfile(name, l->channel.cdev.ops, NULL, O_RDWR); + file = anon_inode_getfile(name, &gk20a_channel_ops, NULL, O_RDWR); if (IS_ERR(file)) { err = PTR_ERR(file); goto clean_up; diff --git a/drivers/gpu/nvgpu/os/linux/ioctl_ctrl.c b/drivers/gpu/nvgpu/os/linux/ioctl_ctrl.c index 9619eff15..1d16afe0e 100644 --- a/drivers/gpu/nvgpu/os/linux/ioctl_ctrl.c +++ b/drivers/gpu/nvgpu/os/linux/ioctl_ctrl.c @@ -72,6 +72,9 @@ (u32) ((a * 0x10C8ULL) >> 32) : (u16) ((u32) a/MHZ)) #define MHZ_TO_HZ(a) ((u64)a * MHZ) +extern const struct file_operations gk20a_as_ops; +extern const struct file_operations gk20a_tsg_ops; + struct gk20a_ctrl_priv { struct device *dev; struct gk20a *g; @@ -110,13 +113,17 @@ int gk20a_ctrl_dev_open(struct inode *inode, struct file *filp) struct gk20a *g; struct gk20a_ctrl_priv *priv; int err = 0; + struct nvgpu_cdev *cdev; - l = container_of(inode->i_cdev, - struct nvgpu_os_linux, ctrl.cdev); - g = nvgpu_get(&l->g); + cdev = container_of(inode->i_cdev, struct nvgpu_cdev, cdev); + g = get_gk20a(cdev->node->parent); + + g = nvgpu_get(g); if (!g) return -ENODEV; + l = nvgpu_os_linux_from_gk20a(g); + nvgpu_log_fn(g, " "); priv = nvgpu_kzalloc(g, sizeof(struct gk20a_ctrl_priv)); @@ -562,7 +569,6 @@ static int gk20a_ctrl_alloc_as( struct gk20a *g, struct nvgpu_alloc_as_args *args) { - struct nvgpu_os_linux *l = nvgpu_os_linux_from_gk20a(g); struct gk20a_as_share *as_share; int err; int fd; @@ -576,7 +582,7 @@ static int gk20a_ctrl_alloc_as( (void) snprintf(name, sizeof(name), "nvhost-%s-fd%d", g->name, fd); - file = anon_inode_getfile(name, l->as_dev.cdev.ops, NULL, O_RDWR); + file = anon_inode_getfile(name, &gk20a_as_ops, NULL, O_RDWR); if (IS_ERR(file)) { err = PTR_ERR(file); goto clean_up; @@ -605,7 +611,6 @@ clean_up: static int gk20a_ctrl_open_tsg(struct gk20a *g, struct nvgpu_gpu_open_tsg_args *args) { - struct nvgpu_os_linux *l = nvgpu_os_linux_from_gk20a(g); int err; int fd; struct file *file; @@ -618,7 +623,7 @@ static int gk20a_ctrl_open_tsg(struct gk20a *g, (void) snprintf(name, sizeof(name), "nvgpu-%s-tsg%d", g->name, fd); - file = anon_inode_getfile(name, l->tsg.cdev.ops, NULL, O_RDWR); + file = anon_inode_getfile(name, &gk20a_tsg_ops, NULL, O_RDWR); if (IS_ERR(file)) { err = PTR_ERR(file); goto clean_up; diff --git a/drivers/gpu/nvgpu/os/linux/ioctl_dbg.c b/drivers/gpu/nvgpu/os/linux/ioctl_dbg.c index dc7d4b0c9..35b55ce68 100644 --- a/drivers/gpu/nvgpu/os/linux/ioctl_dbg.c +++ b/drivers/gpu/nvgpu/os/linux/ioctl_dbg.c @@ -150,7 +150,7 @@ static int nvgpu_profiler_reserve_release(struct dbg_session_gk20a *dbg_s, static int dbg_unbind_all_channels_gk20a(struct dbg_session_gk20a *dbg_s); -static int gk20a_dbg_gpu_do_dev_open(struct inode *inode, +static int gk20a_dbg_gpu_do_dev_open(struct gk20a *g, struct file *filp, bool is_profiler); unsigned int gk20a_dbg_gpu_dev_poll(struct file *filep, poll_table *wait) @@ -230,12 +230,14 @@ int gk20a_dbg_gpu_dev_release(struct inode *inode, struct file *filp) int gk20a_prof_gpu_dev_open(struct inode *inode, struct file *filp) { - struct nvgpu_os_linux *l = container_of(inode->i_cdev, - struct nvgpu_os_linux, prof.cdev); - struct gk20a *g = &l->g; + struct gk20a *g; + struct nvgpu_cdev *cdev; + + cdev = container_of(inode->i_cdev, struct nvgpu_cdev, cdev); + g = get_gk20a(cdev->node->parent); nvgpu_log(g, gpu_dbg_fn | gpu_dbg_gpu_dbg, " "); - return gk20a_dbg_gpu_do_dev_open(inode, filp, true /* is profiler */); + return gk20a_dbg_gpu_do_dev_open(g, filp, true /* is profiler */); } static int nvgpu_dbg_gpu_ioctl_timeout(struct dbg_session_gk20a *dbg_s, @@ -380,25 +382,15 @@ static int nvgpu_dbg_timeout_enable(struct dbg_session_gk20a *dbg_s, return err; } -static int gk20a_dbg_gpu_do_dev_open(struct inode *inode, +static int gk20a_dbg_gpu_do_dev_open(struct gk20a *g, struct file *filp, bool is_profiler) { - struct nvgpu_os_linux *l; struct dbg_session_gk20a_linux *dbg_session_linux; struct dbg_session_gk20a *dbg_s; - struct gk20a *g; - struct device *dev; - int err; - if (!is_profiler) - l = container_of(inode->i_cdev, - struct nvgpu_os_linux, dbg.cdev); - else - l = container_of(inode->i_cdev, - struct nvgpu_os_linux, prof.cdev); - g = nvgpu_get(&l->g); + g = nvgpu_get(g); if (!g) return -ENODEV; @@ -2015,12 +2007,14 @@ static int nvgpu_dbg_gpu_cycle_stats_snapshot(struct dbg_session_gk20a *dbg_s, int gk20a_dbg_gpu_dev_open(struct inode *inode, struct file *filp) { - struct nvgpu_os_linux *l = container_of(inode->i_cdev, - struct nvgpu_os_linux, dbg.cdev); - struct gk20a *g = &l->g; + struct gk20a *g; + struct nvgpu_cdev *cdev; + + cdev = container_of(inode->i_cdev, struct nvgpu_cdev, cdev); + g = get_gk20a(cdev->node->parent); nvgpu_log(g, gpu_dbg_fn | gpu_dbg_gpu_dbg, " "); - return gk20a_dbg_gpu_do_dev_open(inode, filp, false /* not profiler */); + return gk20a_dbg_gpu_do_dev_open(g, filp, false /* not profiler */); } long gk20a_dbg_gpu_dev_ioctl(struct file *filp, unsigned int cmd, diff --git a/drivers/gpu/nvgpu/os/linux/ioctl_prof.c b/drivers/gpu/nvgpu/os/linux/ioctl_prof.c index be7fe3642..0ceea35ae 100644 --- a/drivers/gpu/nvgpu/os/linux/ioctl_prof.c +++ b/drivers/gpu/nvgpu/os/linux/ioctl_prof.c @@ -31,6 +31,7 @@ #include #include +#include "platform_gk20a.h" #include "os_linux.h" #include "ioctl_prof.h" #include "ioctl_dbg.h" @@ -129,12 +130,14 @@ free_priv: int nvgpu_prof_dev_fops_open(struct inode *inode, struct file *filp) { - struct nvgpu_os_linux *l = container_of(inode->i_cdev, - struct nvgpu_os_linux, prof_dev.cdev); struct gk20a *g; int err; + struct nvgpu_cdev *cdev; - g = nvgpu_get(&l->g); + cdev = container_of(inode->i_cdev, struct nvgpu_cdev, cdev); + g = get_gk20a(cdev->node->parent); + + g = nvgpu_get(g); if (!g) { return -ENODEV; } @@ -155,12 +158,14 @@ int nvgpu_prof_dev_fops_open(struct inode *inode, struct file *filp) int nvgpu_prof_ctx_fops_open(struct inode *inode, struct file *filp) { - struct nvgpu_os_linux *l = container_of(inode->i_cdev, - struct nvgpu_os_linux, prof_ctx.cdev); struct gk20a *g; int err; + struct nvgpu_cdev *cdev; - g = nvgpu_get(&l->g); + cdev = container_of(inode->i_cdev, struct nvgpu_cdev, cdev); + g = get_gk20a(cdev->node->parent); + + g = nvgpu_get(g); if (!g) { return -ENODEV; } diff --git a/drivers/gpu/nvgpu/os/linux/ioctl_tsg.c b/drivers/gpu/nvgpu/os/linux/ioctl_tsg.c index 67f3acf16..a1c1d7ac9 100644 --- a/drivers/gpu/nvgpu/os/linux/ioctl_tsg.c +++ b/drivers/gpu/nvgpu/os/linux/ioctl_tsg.c @@ -466,13 +466,12 @@ free_ref: int nvgpu_ioctl_tsg_dev_open(struct inode *inode, struct file *filp) { - struct nvgpu_os_linux *l; struct gk20a *g; int ret; + struct nvgpu_cdev *cdev; - l = container_of(inode->i_cdev, - struct nvgpu_os_linux, tsg.cdev); - g = &l->g; + cdev = container_of(inode->i_cdev, struct nvgpu_cdev, cdev); + g = get_gk20a(cdev->node->parent); nvgpu_log_fn(g, " "); @@ -482,7 +481,7 @@ int nvgpu_ioctl_tsg_dev_open(struct inode *inode, struct file *filp) return ret; } - ret = nvgpu_ioctl_tsg_open(&l->g, filp); + ret = nvgpu_ioctl_tsg_open(g, filp); gk20a_idle(g); nvgpu_log_fn(g, "done"); diff --git a/drivers/gpu/nvgpu/os/linux/os_linux.h b/drivers/gpu/nvgpu/os/linux/os_linux.h index 96de83fc3..a1966ead8 100644 --- a/drivers/gpu/nvgpu/os/linux/os_linux.h +++ b/drivers/gpu/nvgpu/os/linux/os_linux.h @@ -73,6 +73,19 @@ struct dgpu_thermal_alert { u32 event_delay; }; +struct nvgpu_cdev { + struct cdev cdev; + struct device *node; + struct nvgpu_list_node list_entry; +}; + +static inline struct nvgpu_cdev * +nvgpu_cdev_from_list_entry(struct nvgpu_list_node *node) +{ + return (struct nvgpu_cdev *) + ((uintptr_t)node - offsetof(struct nvgpu_cdev, list_entry)); +}; + struct nvgpu_os_linux { struct gk20a g; struct device *dev; @@ -80,55 +93,8 @@ struct nvgpu_os_linux { struct nvgpu_interrupts interrupts; struct class *devnode_class; - struct { - struct cdev cdev; - struct device *node; - } channel; - - struct { - struct cdev cdev; - struct device *node; - } ctrl; - - struct { - struct cdev cdev; - struct device *node; - } as_dev; - - struct { - struct cdev cdev; - struct device *node; - } dbg; - - struct { - struct cdev cdev; - struct device *node; - } prof; - - struct { - struct cdev cdev; - struct device *node; - } prof_dev; - - struct { - struct cdev cdev; - struct device *node; - } prof_ctx; - - struct { - struct cdev cdev; - struct device *node; - } tsg; - - struct { - struct cdev cdev; - struct device *node; - } ctxsw; - - struct { - struct cdev cdev; - struct device *node; - } sched; + struct nvgpu_list_node cdev_list_head; + u32 num_cdevs; dev_t cdev_region; diff --git a/drivers/gpu/nvgpu/os/linux/sched.c b/drivers/gpu/nvgpu/os/linux/sched.c index 225730df6..39a3a11dd 100644 --- a/drivers/gpu/nvgpu/os/linux/sched.c +++ b/drivers/gpu/nvgpu/os/linux/sched.c @@ -28,6 +28,7 @@ #include #include +#include "platform_gk20a.h" #include "sched.h" #include "os_linux.h" #include "ioctl_tsg.h" @@ -387,13 +388,15 @@ static int gk20a_sched_dev_ioctl_put_tsg(struct gk20a *g, int gk20a_sched_dev_open(struct inode *inode, struct file *filp) { - struct nvgpu_os_linux *l = container_of(inode->i_cdev, - struct nvgpu_os_linux, sched.cdev); struct gk20a *g; struct nvgpu_sched_ctrl *sched; int err = 0; + struct nvgpu_cdev *cdev; - g = nvgpu_get(&l->g); + cdev = container_of(inode->i_cdev, struct nvgpu_cdev, cdev); + g = get_gk20a(cdev->node->parent); + + g = nvgpu_get(g); if (!g) return -ENODEV; sched = &g->sched_ctrl;