summaryrefslogtreecommitdiffstats
path: root/drivers/gpu/nvgpu/os/linux/ioctl_ctrl.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/gpu/nvgpu/os/linux/ioctl_ctrl.c')
-rw-r--r--drivers/gpu/nvgpu/os/linux/ioctl_ctrl.c131
1 files changed, 131 insertions, 0 deletions
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}