diff options
Diffstat (limited to 'drivers/gpu/nvgpu/gm20b/mm_gm20b.c')
-rw-r--r-- | drivers/gpu/nvgpu/gm20b/mm_gm20b.c | 63 |
1 files changed, 58 insertions, 5 deletions
diff --git a/drivers/gpu/nvgpu/gm20b/mm_gm20b.c b/drivers/gpu/nvgpu/gm20b/mm_gm20b.c index 67d61569..2c211a57 100644 --- a/drivers/gpu/nvgpu/gm20b/mm_gm20b.c +++ b/drivers/gpu/nvgpu/gm20b/mm_gm20b.c | |||
@@ -13,9 +13,11 @@ | |||
13 | * more details. | 13 | * more details. |
14 | */ | 14 | */ |
15 | 15 | ||
16 | #include <linux/pm_runtime.h> | ||
16 | #include "gk20a/gk20a.h" | 17 | #include "gk20a/gk20a.h" |
17 | #include "mm_gm20b.h" | 18 | #include "mm_gm20b.h" |
18 | #include "hw_gmmu_gm20b.h" | 19 | #include "hw_gmmu_gm20b.h" |
20 | #include "hw_fb_gm20b.h" | ||
19 | 21 | ||
20 | static const u32 gmmu_page_sizes[gmmu_nr_page_sizes] = { SZ_4K, SZ_128K }; | 22 | static const u32 gmmu_page_sizes[gmmu_nr_page_sizes] = { SZ_4K, SZ_128K }; |
21 | static const u32 gmmu_page_shifts[gmmu_nr_page_sizes] = { 12, 17 }; | 23 | static const u32 gmmu_page_shifts[gmmu_nr_page_sizes] = { 12, 17 }; |
@@ -24,8 +26,8 @@ static const u64 gmmu_page_offset_masks[gmmu_nr_page_sizes] = { 0xfffLL, | |||
24 | static const u64 gmmu_page_masks[gmmu_nr_page_sizes] = { ~0xfffLL, ~0x1ffffLL }; | 26 | static const u64 gmmu_page_masks[gmmu_nr_page_sizes] = { ~0xfffLL, ~0x1ffffLL }; |
25 | 27 | ||
26 | static int allocate_gmmu_ptes_sparse(struct vm_gk20a *vm, | 28 | static int allocate_gmmu_ptes_sparse(struct vm_gk20a *vm, |
27 | enum gmmu_pgsz_gk20a pgsz_idx, | 29 | enum gmmu_pgsz_gk20a pgsz_idx, |
28 | u64 first_vaddr, u64 last_vaddr) | 30 | u64 first_vaddr, u64 last_vaddr) |
29 | { | 31 | { |
30 | int err; | 32 | int err; |
31 | u32 pte_lo, pte_hi; | 33 | u32 pte_lo, pte_hi; |
@@ -39,10 +41,10 @@ static int allocate_gmmu_ptes_sparse(struct vm_gk20a *vm, | |||
39 | gk20a_dbg_fn(""); | 41 | gk20a_dbg_fn(""); |
40 | 42 | ||
41 | pde_range_from_vaddr_range(vm, first_vaddr, last_vaddr, | 43 | pde_range_from_vaddr_range(vm, first_vaddr, last_vaddr, |
42 | &pde_lo, &pde_hi); | 44 | &pde_lo, &pde_hi); |
43 | 45 | ||
44 | gk20a_dbg(gpu_dbg_pte, "size_idx=%d, pde_lo=%d, pde_hi=%d", | 46 | gk20a_dbg(gpu_dbg_pte, "size_idx=%d, pde_lo=%d, pde_hi=%d", |
45 | pgsz_idx, pde_lo, pde_hi); | 47 | pgsz_idx, pde_lo, pde_hi); |
46 | 48 | ||
47 | /* Expect ptes of the same pde */ | 49 | /* Expect ptes of the same pde */ |
48 | BUG_ON(pde_lo != pde_hi); | 50 | BUG_ON(pde_lo != pde_hi); |
@@ -185,7 +187,8 @@ static int gm20b_vm_put_sparse(struct vm_gk20a *vm, u64 vaddr, | |||
185 | vaddr_pde_start = (u64)i << pde_shift; | 187 | vaddr_pde_start = (u64)i << pde_shift; |
186 | allocate_gmmu_ptes_sparse(vm, pgsz_idx, | 188 | allocate_gmmu_ptes_sparse(vm, pgsz_idx, |
187 | vaddr_pde_start, | 189 | vaddr_pde_start, |
188 | PDE_ADDR_END(vaddr_pde_start, pde_shift)); | 190 | PDE_ADDR_END(vaddr_pde_start, |
191 | pde_shift)); | ||
189 | } else { | 192 | } else { |
190 | /* Check leading and trailing spaces which doesn't fit | 193 | /* Check leading and trailing spaces which doesn't fit |
191 | * into entire pde. */ | 194 | * into entire pde. */ |
@@ -212,6 +215,56 @@ fail: | |||
212 | return err; | 215 | return err; |
213 | } | 216 | } |
214 | 217 | ||
218 | static int gm20b_mm_mmu_vpr_info_fetch_wait(struct gk20a *g, | ||
219 | const unsigned int msec) | ||
220 | { | ||
221 | unsigned long timeout; | ||
222 | |||
223 | if (tegra_platform_is_silicon()) | ||
224 | timeout = jiffies + msecs_to_jiffies(msec); | ||
225 | else | ||
226 | timeout = msecs_to_jiffies(msec); | ||
227 | |||
228 | while (1) { | ||
229 | u32 val; | ||
230 | val = gk20a_readl(g, fb_mmu_vpr_info_r()); | ||
231 | if (fb_mmu_vpr_info_fetch_v(val) == | ||
232 | fb_mmu_vpr_info_fetch_false_v()) | ||
233 | break; | ||
234 | if (tegra_platform_is_silicon()) { | ||
235 | if (WARN_ON(time_after(jiffies, timeout))) | ||
236 | return -ETIME; | ||
237 | } else if (--timeout == 0) | ||
238 | return -ETIME; | ||
239 | } | ||
240 | return 0; | ||
241 | } | ||
242 | |||
243 | int gm20b_mm_mmu_vpr_info_fetch(struct gk20a *g) | ||
244 | { | ||
245 | int ret = 0; | ||
246 | |||
247 | gk20a_busy_noresume(g->dev); | ||
248 | #ifdef CONFIG_PM_RUNTIME | ||
249 | if (!pm_runtime_active(&g->dev->dev)) | ||
250 | goto fail; | ||
251 | #endif | ||
252 | |||
253 | if (gm20b_mm_mmu_vpr_info_fetch_wait(g, VPR_INFO_FETCH_WAIT)) { | ||
254 | ret = -ETIME; | ||
255 | goto fail; | ||
256 | } | ||
257 | |||
258 | gk20a_writel(g, fb_mmu_vpr_info_r(), | ||
259 | fb_mmu_vpr_info_fetch_true_v()); | ||
260 | |||
261 | ret = gm20b_mm_mmu_vpr_info_fetch_wait(g, VPR_INFO_FETCH_WAIT); | ||
262 | |||
263 | fail: | ||
264 | gk20a_idle(g->dev); | ||
265 | return ret; | ||
266 | } | ||
267 | |||
215 | void gm20b_init_mm(struct gpu_ops *gops) | 268 | void gm20b_init_mm(struct gpu_ops *gops) |
216 | { | 269 | { |
217 | gops->mm.set_sparse = gm20b_vm_put_sparse; | 270 | gops->mm.set_sparse = gm20b_vm_put_sparse; |