summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorKonsta Holtta <kholtta@nvidia.com>2018-09-11 07:46:09 -0400
committermobile promotions <svcmobile_promotions@nvidia.com>2019-08-15 03:58:34 -0400
commit44c23acfa4453d7f5773a8adc288358bc3f3b425 (patch)
treec53e2535418d4bd8b10c7dca9a45efe3578756d1
parent7e96b143909b8ab7ba18f28b51cb796d8544aabb (diff)
gpu: nvgpu: provide usermode region via mmap
Add a mmap callback on the control device node for mapping the usermode register region to userspace. Each such mapping is removed when the GPU railgates, and brought back again on unrailgate. The mapping offset must be 0 and its size must be 4 KB. Bug 200145225 Bug 200541476 Change-Id: Ie8d3758da745b958376292691d7d1d02a24e7815 Signed-off-by: Konsta Holtta <kholtta@nvidia.com> Reviewed-on: https://git-master.nvidia.com/r/1795819 Signed-off-by: Debarshi Dutta <ddutta@nvidia.com> (cherry picked from commit f33935f426c46b70b7aee33a1e52d5fdae5ca376 in dev-main) Reviewed-on: https://git-master.nvidia.com/r/2170035 GVS: Gerrit_Virtual_Submit Reviewed-by: Bibek Basu <bbasu@nvidia.com> Reviewed-by: mobile promotions <svcmobile_promotions@nvidia.com> Tested-by: mobile promotions <svcmobile_promotions@nvidia.com>
-rw-r--r--drivers/gpu/nvgpu/os/linux/ioctl.c1
-rw-r--r--drivers/gpu/nvgpu/os/linux/ioctl_ctrl.c131
-rw-r--r--drivers/gpu/nvgpu/os/linux/ioctl_ctrl.h4
-rw-r--r--drivers/gpu/nvgpu/os/linux/module.c4
4 files changed, 140 insertions, 0 deletions
diff --git a/drivers/gpu/nvgpu/os/linux/ioctl.c b/drivers/gpu/nvgpu/os/linux/ioctl.c
index 562500a6..a40df2ad 100644
--- a/drivers/gpu/nvgpu/os/linux/ioctl.c
+++ b/drivers/gpu/nvgpu/os/linux/ioctl.c
@@ -54,6 +54,7 @@ static const struct file_operations gk20a_ctrl_ops = {
54#ifdef CONFIG_COMPAT 54#ifdef CONFIG_COMPAT
55 .compat_ioctl = gk20a_ctrl_dev_ioctl, 55 .compat_ioctl = gk20a_ctrl_dev_ioctl,
56#endif 56#endif
57 .mmap = gk20a_ctrl_dev_mmap,
57}; 58};
58 59
59static const struct file_operations gk20a_dbg_ops = { 60static const struct file_operations gk20a_dbg_ops = {
diff --git a/drivers/gpu/nvgpu/os/linux/ioctl_ctrl.c b/drivers/gpu/nvgpu/os/linux/ioctl_ctrl.c
index e85cec9c..73c9d084 100644
--- a/drivers/gpu/nvgpu/os/linux/ioctl_ctrl.c
+++ b/drivers/gpu/nvgpu/os/linux/ioctl_ctrl.c
@@ -57,6 +57,10 @@ struct gk20a_ctrl_priv {
57 struct nvgpu_clk_session *clk_session; 57 struct nvgpu_clk_session *clk_session;
58 58
59 struct nvgpu_list_node list; 59 struct nvgpu_list_node list;
60 struct {
61 struct vm_area_struct *vma;
62 unsigned long flags;
63 } usermode_vma;
60}; 64};
61 65
62static inline struct gk20a_ctrl_priv * 66static inline struct gk20a_ctrl_priv *
@@ -1919,3 +1923,130 @@ long gk20a_ctrl_dev_ioctl(struct file *filp, unsigned int cmd, unsigned long arg
1919 1923
1920 return err; 1924 return err;
1921} 1925}
1926
1927static void usermode_vma_close(struct vm_area_struct *vma)
1928{
1929 struct gk20a_ctrl_priv *priv = vma->vm_private_data;
1930 struct gk20a *g = priv->g;
1931 struct nvgpu_os_linux *l = nvgpu_os_linux_from_gk20a(g);
1932
1933 nvgpu_mutex_acquire(&l->ctrl.privs_lock);
1934 priv->usermode_vma.vma = NULL;
1935 nvgpu_mutex_release(&l->ctrl.privs_lock);
1936}
1937
1938struct vm_operations_struct usermode_vma_ops = {
1939 /* no .open - we use VM_DONTCOPY and don't support fork */
1940 .close = usermode_vma_close,
1941};
1942
1943int gk20a_ctrl_dev_mmap(struct file *filp, struct vm_area_struct *vma)
1944{
1945 struct gk20a_ctrl_priv *priv = filp->private_data;
1946 struct gk20a *g = priv->g;
1947 struct nvgpu_os_linux *l = nvgpu_os_linux_from_gk20a(g);
1948 u64 addr;
1949 int err;
1950
1951 if (g->ops.fifo.usermode_base == NULL)
1952 return -ENOSYS;
1953
1954 if (priv->usermode_vma.vma != NULL)
1955 return -EBUSY;
1956
1957 if (vma->vm_end - vma->vm_start != SZ_4K)
1958 return -EINVAL;
1959
1960 if (vma->vm_pgoff != 0UL)
1961 return -EINVAL;
1962
1963 addr = l->regs_bus_addr + g->ops.fifo.usermode_base(g);
1964
1965 /* Sync with poweron/poweroff, and require valid regs */
1966 err = gk20a_busy(g);
1967 if (err) {
1968 return err;
1969 }
1970
1971 nvgpu_mutex_acquire(&l->ctrl.privs_lock);
1972
1973 vma->vm_flags |= VM_IO | VM_DONTCOPY | VM_DONTEXPAND | VM_NORESERVE |
1974 VM_DONTDUMP | VM_PFNMAP;
1975 vma->vm_ops = &usermode_vma_ops;
1976 vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot);
1977
1978 err = io_remap_pfn_range(vma, vma->vm_start, addr >> PAGE_SHIFT,
1979 vma->vm_end - vma->vm_start, vma->vm_page_prot);
1980 if (!err) {
1981 priv->usermode_vma.vma = vma;
1982 priv->usermode_vma.flags = vma->vm_flags;
1983 vma->vm_private_data = priv;
1984 }
1985 nvgpu_mutex_release(&l->ctrl.privs_lock);
1986
1987 gk20a_idle(g);
1988
1989 return err;
1990}
1991
1992static void alter_usermode_mapping(struct gk20a *g,
1993 struct gk20a_ctrl_priv *priv,
1994 bool poweroff)
1995{
1996 struct nvgpu_os_linux *l = nvgpu_os_linux_from_gk20a(g);
1997 struct vm_area_struct *vma = priv->usermode_vma.vma;
1998 u64 addr;
1999 int err;
2000
2001 if (!vma) {
2002 /* Nothing to do - no mmap called */
2003 return;
2004 }
2005
2006 addr = l->regs_bus_addr + g->ops.fifo.usermode_base(g);
2007
2008 down_write(&vma->vm_mm->mmap_sem);
2009
2010 if (poweroff) {
2011 err = zap_vma_ptes(vma, vma->vm_start, SZ_4K);
2012 if (err == 0) {
2013 vma->vm_flags = VM_NONE;
2014 } else {
2015 nvgpu_err(g, "can't remove usermode mapping");
2016 }
2017 } else {
2018 vma->vm_flags = priv->usermode_vma.flags;
2019 err = io_remap_pfn_range(vma, vma->vm_start,
2020 addr >> PAGE_SHIFT,
2021 SZ_4K, vma->vm_page_prot);
2022 if (err != 0) {
2023 nvgpu_err(g, "can't restore usermode mapping");
2024 vma->vm_flags = VM_NONE;
2025 }
2026 }
2027
2028 up_write(&vma->vm_mm->mmap_sem);
2029}
2030
2031static void alter_usermode_mappings(struct gk20a *g, bool poweroff)
2032{
2033 struct gk20a_ctrl_priv *priv;
2034 struct nvgpu_os_linux *l = nvgpu_os_linux_from_gk20a(g);
2035
2036 nvgpu_mutex_acquire(&l->ctrl.privs_lock);
2037 nvgpu_list_for_each_entry(priv, &l->ctrl.privs,
2038 gk20a_ctrl_priv, list) {
2039 alter_usermode_mapping(g, priv, poweroff);
2040 }
2041 nvgpu_mutex_release(&l->ctrl.privs_lock);
2042}
2043
2044void nvgpu_hide_usermode_for_poweroff(struct gk20a *g)
2045{
2046 alter_usermode_mappings(g, true);
2047}
2048
2049void nvgpu_restore_usermode_for_poweron(struct gk20a *g)
2050{
2051 alter_usermode_mappings(g, false);
2052}
diff --git a/drivers/gpu/nvgpu/os/linux/ioctl_ctrl.h b/drivers/gpu/nvgpu/os/linux/ioctl_ctrl.h
index 8b4a5e59..3e1f798b 100644
--- a/drivers/gpu/nvgpu/os/linux/ioctl_ctrl.h
+++ b/drivers/gpu/nvgpu/os/linux/ioctl_ctrl.h
@@ -19,5 +19,9 @@
19int gk20a_ctrl_dev_open(struct inode *inode, struct file *filp); 19int gk20a_ctrl_dev_open(struct inode *inode, struct file *filp);
20int gk20a_ctrl_dev_release(struct inode *inode, struct file *filp); 20int gk20a_ctrl_dev_release(struct inode *inode, struct file *filp);
21long gk20a_ctrl_dev_ioctl(struct file *filp, unsigned int cmd, unsigned long arg); 21long gk20a_ctrl_dev_ioctl(struct file *filp, unsigned int cmd, unsigned long arg);
22int gk20a_ctrl_dev_mmap(struct file *filp, struct vm_area_struct *vma);
23
24void nvgpu_hide_usermode_for_poweroff(struct gk20a *g);
25void nvgpu_restore_usermode_for_poweron(struct gk20a *g);
22 26
23#endif 27#endif
diff --git a/drivers/gpu/nvgpu/os/linux/module.c b/drivers/gpu/nvgpu/os/linux/module.c
index ebe2e650..d580d064 100644
--- a/drivers/gpu/nvgpu/os/linux/module.c
+++ b/drivers/gpu/nvgpu/os/linux/module.c
@@ -59,6 +59,7 @@
59#include "module_usermode.h" 59#include "module_usermode.h"
60#include "intr.h" 60#include "intr.h"
61#include "ioctl.h" 61#include "ioctl.h"
62#include "ioctl_ctrl.h"
62 63
63#include "os_linux.h" 64#include "os_linux.h"
64#include "os_ops.h" 65#include "os_ops.h"
@@ -292,6 +293,8 @@ int gk20a_pm_finalize_poweron(struct device *dev)
292 if (err) 293 if (err)
293 goto done; 294 goto done;
294 295
296 nvgpu_restore_usermode_for_poweron(g);
297
295 /* Enable interrupt workqueue */ 298 /* Enable interrupt workqueue */
296 if (!l->nonstall_work_queue) { 299 if (!l->nonstall_work_queue) {
297 l->nonstall_work_queue = alloc_workqueue("%s", 300 l->nonstall_work_queue = alloc_workqueue("%s",
@@ -424,6 +427,7 @@ static int gk20a_pm_prepare_poweroff(struct device *dev)
424 /* Stop CPU from accessing the GPU registers. */ 427 /* Stop CPU from accessing the GPU registers. */
425 gk20a_lockout_registers(g); 428 gk20a_lockout_registers(g);
426 429
430 nvgpu_hide_usermode_for_poweroff(g);
427 nvgpu_mutex_release(&g->power_lock); 431 nvgpu_mutex_release(&g->power_lock);
428 return 0; 432 return 0;
429 433