diff options
Diffstat (limited to 'drivers/gpu')
-rw-r--r-- | drivers/gpu/nvgpu/os/linux/ioctl_ctrl.c | 52 |
1 files changed, 39 insertions, 13 deletions
diff --git a/drivers/gpu/nvgpu/os/linux/ioctl_ctrl.c b/drivers/gpu/nvgpu/os/linux/ioctl_ctrl.c index f71921cb..b6cdffcb 100644 --- a/drivers/gpu/nvgpu/os/linux/ioctl_ctrl.c +++ b/drivers/gpu/nvgpu/os/linux/ioctl_ctrl.c | |||
@@ -2051,7 +2051,7 @@ int gk20a_ctrl_dev_mmap(struct file *filp, struct vm_area_struct *vma) | |||
2051 | return err; | 2051 | return err; |
2052 | } | 2052 | } |
2053 | 2053 | ||
2054 | static void alter_usermode_mapping(struct gk20a *g, | 2054 | static int alter_usermode_mapping(struct gk20a *g, |
2055 | struct gk20a_ctrl_priv *priv, | 2055 | struct gk20a_ctrl_priv *priv, |
2056 | bool poweroff) | 2056 | bool poweroff) |
2057 | { | 2057 | { |
@@ -2059,23 +2059,34 @@ static void alter_usermode_mapping(struct gk20a *g, | |||
2059 | struct vm_area_struct *vma = priv->usermode_vma.vma; | 2059 | struct vm_area_struct *vma = priv->usermode_vma.vma; |
2060 | bool vma_mapped = priv->usermode_vma.vma_mapped; | 2060 | bool vma_mapped = priv->usermode_vma.vma_mapped; |
2061 | u64 addr; | 2061 | u64 addr; |
2062 | int err; | 2062 | int err = 0; |
2063 | 2063 | ||
2064 | if (!vma) { | 2064 | if (!vma) { |
2065 | /* Nothing to do - no mmap called */ | 2065 | /* Nothing to do - no mmap called */ |
2066 | return; | 2066 | return 0; |
2067 | } | 2067 | } |
2068 | 2068 | ||
2069 | addr = l->regs_bus_addr + g->ops.fifo.usermode_base(g); | 2069 | addr = l->regs_bus_addr + g->ops.fifo.usermode_base(g); |
2070 | 2070 | ||
2071 | down_write(&vma->vm_mm->mmap_sem); | ||
2072 | |||
2073 | /* | 2071 | /* |
2074 | * This is a no-op for the below cases | 2072 | * This is a no-op for the below cases |
2075 | * a) poweroff and !vma_mapped - > do nothing as no map exists | 2073 | * a) poweroff and !vma_mapped - > do nothing as no map exists |
2076 | * b) !poweroff and vmap_mapped -> do nothing as already mapped | 2074 | * b) !poweroff and vmap_mapped -> do nothing as already mapped |
2077 | */ | 2075 | */ |
2078 | if (poweroff && vma_mapped) { | 2076 | if (poweroff != vma_mapped) { |
2077 | return 0; | ||
2078 | } | ||
2079 | |||
2080 | /* | ||
2081 | * We use trylock due to lock inversion: we need to acquire | ||
2082 | * mmap_lock while holding ctrl_privs_lock. usermode_vma_close | ||
2083 | * does it in reverse order. Trylock is a way to avoid deadlock. | ||
2084 | */ | ||
2085 | if (!down_write_trylock(&vma->vm_mm->mmap_sem)) { | ||
2086 | return -EBUSY; | ||
2087 | } | ||
2088 | |||
2089 | if (poweroff) { | ||
2079 | err = zap_vma_ptes(vma, vma->vm_start, SZ_4K); | 2090 | err = zap_vma_ptes(vma, vma->vm_start, SZ_4K); |
2080 | if (err == 0) { | 2091 | if (err == 0) { |
2081 | vma->vm_flags = VM_NONE; | 2092 | vma->vm_flags = VM_NONE; |
@@ -2083,7 +2094,7 @@ static void alter_usermode_mapping(struct gk20a *g, | |||
2083 | } else { | 2094 | } else { |
2084 | nvgpu_err(g, "can't remove usermode mapping"); | 2095 | nvgpu_err(g, "can't remove usermode mapping"); |
2085 | } | 2096 | } |
2086 | } else if (!poweroff && !vma_mapped) { | 2097 | } else { |
2087 | vma->vm_flags = priv->usermode_vma.flags; | 2098 | vma->vm_flags = priv->usermode_vma.flags; |
2088 | err = io_remap_pfn_range(vma, vma->vm_start, | 2099 | err = io_remap_pfn_range(vma, vma->vm_start, |
2089 | addr >> PAGE_SHIFT, | 2100 | addr >> PAGE_SHIFT, |
@@ -2097,19 +2108,34 @@ static void alter_usermode_mapping(struct gk20a *g, | |||
2097 | } | 2108 | } |
2098 | 2109 | ||
2099 | up_write(&vma->vm_mm->mmap_sem); | 2110 | up_write(&vma->vm_mm->mmap_sem); |
2111 | |||
2112 | return err; | ||
2100 | } | 2113 | } |
2101 | 2114 | ||
2102 | static void alter_usermode_mappings(struct gk20a *g, bool poweroff) | 2115 | static void alter_usermode_mappings(struct gk20a *g, bool poweroff) |
2103 | { | 2116 | { |
2104 | struct gk20a_ctrl_priv *priv; | 2117 | struct gk20a_ctrl_priv *priv; |
2105 | struct nvgpu_os_linux *l = nvgpu_os_linux_from_gk20a(g); | 2118 | struct nvgpu_os_linux *l = nvgpu_os_linux_from_gk20a(g); |
2119 | int err = 0; | ||
2106 | 2120 | ||
2107 | nvgpu_mutex_acquire(&l->ctrl.privs_lock); | 2121 | do { |
2108 | nvgpu_list_for_each_entry(priv, &l->ctrl.privs, | 2122 | nvgpu_mutex_acquire(&l->ctrl.privs_lock); |
2109 | gk20a_ctrl_priv, list) { | 2123 | nvgpu_list_for_each_entry(priv, &l->ctrl.privs, |
2110 | alter_usermode_mapping(g, priv, poweroff); | 2124 | gk20a_ctrl_priv, list) { |
2111 | } | 2125 | err = alter_usermode_mapping(g, priv, poweroff); |
2112 | nvgpu_mutex_release(&l->ctrl.privs_lock); | 2126 | if (err != 0) { |
2127 | break; | ||
2128 | } | ||
2129 | } | ||
2130 | nvgpu_mutex_release(&l->ctrl.privs_lock); | ||
2131 | |||
2132 | if (err == -EBUSY) { | ||
2133 | nvgpu_log_info(g, "ctrl_privs_lock lock contended. retry altering usermode mappings"); | ||
2134 | nvgpu_udelay(10); | ||
2135 | } else if (err != 0) { | ||
2136 | nvgpu_err(g, "can't alter usermode mapping. err = %d", err); | ||
2137 | } | ||
2138 | } while (err == -EBUSY); | ||
2113 | } | 2139 | } |
2114 | 2140 | ||
2115 | void nvgpu_hide_usermode_for_poweroff(struct gk20a *g) | 2141 | void nvgpu_hide_usermode_for_poweroff(struct gk20a *g) |