aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@linux-foundation.org>2016-10-28 12:36:07 -0400
committerLinus Torvalds <torvalds@linux-foundation.org>2016-10-28 12:36:07 -0400
commitbdb520845b5700284f34437fadb920000c306466 (patch)
tree352847387131dd3fed32b8b83b96fb00a99bf548
parente0f3e6a7ccc002be056b6a21768fceee0d44941e (diff)
parent7cf321d118a825c1541b43ca45294126fd474efa (diff)
Merge tag 'drm-x86-pat-regression-fix' of git://people.freedesktop.org/~airlied/linux
Pull drm x86/pat regression fixes from Dave Airlie: "This is a standalone pull request for the fix for a regression introduced in -rc1 by a change to vm_insert_mixed to start using the PAT range tracking to validate page protections. With this fix in place, all the VRAM mappings for GPU drivers ended up at UC instead of WC. There are probably better ways to fix this long term, but nothing I'd considered for -fixes that wouldn't need more settling in time. So I've just created a new arch API that the drivers can reserve all their VRAM aperture ranges as WC" * tag 'drm-x86-pat-regression-fix' of git://people.freedesktop.org/~airlied/linux: drm/drivers: add support for using the arch wc mapping API. x86/io: add interface to reserve io memtype for a resource range. (v1.1)
-rw-r--r--arch/x86/include/asm/io.h6
-rw-r--r--arch/x86/mm/pat.c14
-rw-r--r--drivers/gpu/drm/amd/amdgpu/amdgpu_object.c5
-rw-r--r--drivers/gpu/drm/ast/ast_ttm.c6
-rw-r--r--drivers/gpu/drm/cirrus/cirrus_ttm.c7
-rw-r--r--drivers/gpu/drm/mgag200/mgag200_ttm.c7
-rw-r--r--drivers/gpu/drm/nouveau/nouveau_ttm.c8
-rw-r--r--drivers/gpu/drm/radeon/radeon_object.c5
-rw-r--r--include/linux/io.h22
9 files changed, 80 insertions, 0 deletions
diff --git a/arch/x86/include/asm/io.h b/arch/x86/include/asm/io.h
index de25aad07853..d34bd370074b 100644
--- a/arch/x86/include/asm/io.h
+++ b/arch/x86/include/asm/io.h
@@ -351,4 +351,10 @@ extern void arch_phys_wc_del(int handle);
351#define arch_phys_wc_add arch_phys_wc_add 351#define arch_phys_wc_add arch_phys_wc_add
352#endif 352#endif
353 353
354#ifdef CONFIG_X86_PAT
355extern int arch_io_reserve_memtype_wc(resource_size_t start, resource_size_t size);
356extern void arch_io_free_memtype_wc(resource_size_t start, resource_size_t size);
357#define arch_io_reserve_memtype_wc arch_io_reserve_memtype_wc
358#endif
359
354#endif /* _ASM_X86_IO_H */ 360#endif /* _ASM_X86_IO_H */
diff --git a/arch/x86/mm/pat.c b/arch/x86/mm/pat.c
index 170cc4ff057b..83e701f160a9 100644
--- a/arch/x86/mm/pat.c
+++ b/arch/x86/mm/pat.c
@@ -730,6 +730,20 @@ void io_free_memtype(resource_size_t start, resource_size_t end)
730 free_memtype(start, end); 730 free_memtype(start, end);
731} 731}
732 732
733int arch_io_reserve_memtype_wc(resource_size_t start, resource_size_t size)
734{
735 enum page_cache_mode type = _PAGE_CACHE_MODE_WC;
736
737 return io_reserve_memtype(start, start + size, &type);
738}
739EXPORT_SYMBOL(arch_io_reserve_memtype_wc);
740
741void arch_io_free_memtype_wc(resource_size_t start, resource_size_t size)
742{
743 io_free_memtype(start, start + size);
744}
745EXPORT_SYMBOL(arch_io_free_memtype_wc);
746
733pgprot_t phys_mem_access_prot(struct file *file, unsigned long pfn, 747pgprot_t phys_mem_access_prot(struct file *file, unsigned long pfn,
734 unsigned long size, pgprot_t vma_prot) 748 unsigned long size, pgprot_t vma_prot)
735{ 749{
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_object.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_object.c
index aa074fac0c7f..f3efb1c5dae9 100644
--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_object.c
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_object.c
@@ -754,6 +754,10 @@ static const char *amdgpu_vram_names[] = {
754 754
755int amdgpu_bo_init(struct amdgpu_device *adev) 755int amdgpu_bo_init(struct amdgpu_device *adev)
756{ 756{
757 /* reserve PAT memory space to WC for VRAM */
758 arch_io_reserve_memtype_wc(adev->mc.aper_base,
759 adev->mc.aper_size);
760
757 /* Add an MTRR for the VRAM */ 761 /* Add an MTRR for the VRAM */
758 adev->mc.vram_mtrr = arch_phys_wc_add(adev->mc.aper_base, 762 adev->mc.vram_mtrr = arch_phys_wc_add(adev->mc.aper_base,
759 adev->mc.aper_size); 763 adev->mc.aper_size);
@@ -769,6 +773,7 @@ void amdgpu_bo_fini(struct amdgpu_device *adev)
769{ 773{
770 amdgpu_ttm_fini(adev); 774 amdgpu_ttm_fini(adev);
771 arch_phys_wc_del(adev->mc.vram_mtrr); 775 arch_phys_wc_del(adev->mc.vram_mtrr);
776 arch_io_free_memtype_wc(adev->mc.aper_base, adev->mc.aper_size);
772} 777}
773 778
774int amdgpu_bo_fbdev_mmap(struct amdgpu_bo *bo, 779int amdgpu_bo_fbdev_mmap(struct amdgpu_bo *bo,
diff --git a/drivers/gpu/drm/ast/ast_ttm.c b/drivers/gpu/drm/ast/ast_ttm.c
index 608df4c90520..0743e65cb240 100644
--- a/drivers/gpu/drm/ast/ast_ttm.c
+++ b/drivers/gpu/drm/ast/ast_ttm.c
@@ -267,6 +267,8 @@ int ast_mm_init(struct ast_private *ast)
267 return ret; 267 return ret;
268 } 268 }
269 269
270 arch_io_reserve_memtype_wc(pci_resource_start(dev->pdev, 0),
271 pci_resource_len(dev->pdev, 0));
270 ast->fb_mtrr = arch_phys_wc_add(pci_resource_start(dev->pdev, 0), 272 ast->fb_mtrr = arch_phys_wc_add(pci_resource_start(dev->pdev, 0),
271 pci_resource_len(dev->pdev, 0)); 273 pci_resource_len(dev->pdev, 0));
272 274
@@ -275,11 +277,15 @@ int ast_mm_init(struct ast_private *ast)
275 277
276void ast_mm_fini(struct ast_private *ast) 278void ast_mm_fini(struct ast_private *ast)
277{ 279{
280 struct drm_device *dev = ast->dev;
281
278 ttm_bo_device_release(&ast->ttm.bdev); 282 ttm_bo_device_release(&ast->ttm.bdev);
279 283
280 ast_ttm_global_release(ast); 284 ast_ttm_global_release(ast);
281 285
282 arch_phys_wc_del(ast->fb_mtrr); 286 arch_phys_wc_del(ast->fb_mtrr);
287 arch_io_free_memtype_wc(pci_resource_start(dev->pdev, 0),
288 pci_resource_len(dev->pdev, 0));
283} 289}
284 290
285void ast_ttm_placement(struct ast_bo *bo, int domain) 291void ast_ttm_placement(struct ast_bo *bo, int domain)
diff --git a/drivers/gpu/drm/cirrus/cirrus_ttm.c b/drivers/gpu/drm/cirrus/cirrus_ttm.c
index bb2438dd8733..5e7e63ce7bce 100644
--- a/drivers/gpu/drm/cirrus/cirrus_ttm.c
+++ b/drivers/gpu/drm/cirrus/cirrus_ttm.c
@@ -267,6 +267,9 @@ int cirrus_mm_init(struct cirrus_device *cirrus)
267 return ret; 267 return ret;
268 } 268 }
269 269
270 arch_io_reserve_memtype_wc(pci_resource_start(dev->pdev, 0),
271 pci_resource_len(dev->pdev, 0));
272
270 cirrus->fb_mtrr = arch_phys_wc_add(pci_resource_start(dev->pdev, 0), 273 cirrus->fb_mtrr = arch_phys_wc_add(pci_resource_start(dev->pdev, 0),
271 pci_resource_len(dev->pdev, 0)); 274 pci_resource_len(dev->pdev, 0));
272 275
@@ -276,6 +279,8 @@ int cirrus_mm_init(struct cirrus_device *cirrus)
276 279
277void cirrus_mm_fini(struct cirrus_device *cirrus) 280void cirrus_mm_fini(struct cirrus_device *cirrus)
278{ 281{
282 struct drm_device *dev = cirrus->dev;
283
279 if (!cirrus->mm_inited) 284 if (!cirrus->mm_inited)
280 return; 285 return;
281 286
@@ -285,6 +290,8 @@ void cirrus_mm_fini(struct cirrus_device *cirrus)
285 290
286 arch_phys_wc_del(cirrus->fb_mtrr); 291 arch_phys_wc_del(cirrus->fb_mtrr);
287 cirrus->fb_mtrr = 0; 292 cirrus->fb_mtrr = 0;
293 arch_io_free_memtype_wc(pci_resource_start(dev->pdev, 0),
294 pci_resource_len(dev->pdev, 0));
288} 295}
289 296
290void cirrus_ttm_placement(struct cirrus_bo *bo, int domain) 297void cirrus_ttm_placement(struct cirrus_bo *bo, int domain)
diff --git a/drivers/gpu/drm/mgag200/mgag200_ttm.c b/drivers/gpu/drm/mgag200/mgag200_ttm.c
index 919b35f2ad24..dcf7d11ac380 100644
--- a/drivers/gpu/drm/mgag200/mgag200_ttm.c
+++ b/drivers/gpu/drm/mgag200/mgag200_ttm.c
@@ -266,6 +266,9 @@ int mgag200_mm_init(struct mga_device *mdev)
266 return ret; 266 return ret;
267 } 267 }
268 268
269 arch_io_reserve_memtype_wc(pci_resource_start(dev->pdev, 0),
270 pci_resource_len(dev->pdev, 0));
271
269 mdev->fb_mtrr = arch_phys_wc_add(pci_resource_start(dev->pdev, 0), 272 mdev->fb_mtrr = arch_phys_wc_add(pci_resource_start(dev->pdev, 0),
270 pci_resource_len(dev->pdev, 0)); 273 pci_resource_len(dev->pdev, 0));
271 274
@@ -274,10 +277,14 @@ int mgag200_mm_init(struct mga_device *mdev)
274 277
275void mgag200_mm_fini(struct mga_device *mdev) 278void mgag200_mm_fini(struct mga_device *mdev)
276{ 279{
280 struct drm_device *dev = mdev->dev;
281
277 ttm_bo_device_release(&mdev->ttm.bdev); 282 ttm_bo_device_release(&mdev->ttm.bdev);
278 283
279 mgag200_ttm_global_release(mdev); 284 mgag200_ttm_global_release(mdev);
280 285
286 arch_io_free_memtype_wc(pci_resource_start(dev->pdev, 0),
287 pci_resource_len(dev->pdev, 0));
281 arch_phys_wc_del(mdev->fb_mtrr); 288 arch_phys_wc_del(mdev->fb_mtrr);
282 mdev->fb_mtrr = 0; 289 mdev->fb_mtrr = 0;
283} 290}
diff --git a/drivers/gpu/drm/nouveau/nouveau_ttm.c b/drivers/gpu/drm/nouveau/nouveau_ttm.c
index 1825dbc33192..a6dbe8258040 100644
--- a/drivers/gpu/drm/nouveau/nouveau_ttm.c
+++ b/drivers/gpu/drm/nouveau/nouveau_ttm.c
@@ -398,6 +398,9 @@ nouveau_ttm_init(struct nouveau_drm *drm)
398 /* VRAM init */ 398 /* VRAM init */
399 drm->gem.vram_available = drm->device.info.ram_user; 399 drm->gem.vram_available = drm->device.info.ram_user;
400 400
401 arch_io_reserve_memtype_wc(device->func->resource_addr(device, 1),
402 device->func->resource_size(device, 1));
403
401 ret = ttm_bo_init_mm(&drm->ttm.bdev, TTM_PL_VRAM, 404 ret = ttm_bo_init_mm(&drm->ttm.bdev, TTM_PL_VRAM,
402 drm->gem.vram_available >> PAGE_SHIFT); 405 drm->gem.vram_available >> PAGE_SHIFT);
403 if (ret) { 406 if (ret) {
@@ -430,6 +433,8 @@ nouveau_ttm_init(struct nouveau_drm *drm)
430void 433void
431nouveau_ttm_fini(struct nouveau_drm *drm) 434nouveau_ttm_fini(struct nouveau_drm *drm)
432{ 435{
436 struct nvkm_device *device = nvxx_device(&drm->device);
437
433 ttm_bo_clean_mm(&drm->ttm.bdev, TTM_PL_VRAM); 438 ttm_bo_clean_mm(&drm->ttm.bdev, TTM_PL_VRAM);
434 ttm_bo_clean_mm(&drm->ttm.bdev, TTM_PL_TT); 439 ttm_bo_clean_mm(&drm->ttm.bdev, TTM_PL_TT);
435 440
@@ -439,4 +444,7 @@ nouveau_ttm_fini(struct nouveau_drm *drm)
439 444
440 arch_phys_wc_del(drm->ttm.mtrr); 445 arch_phys_wc_del(drm->ttm.mtrr);
441 drm->ttm.mtrr = 0; 446 drm->ttm.mtrr = 0;
447 arch_io_free_memtype_wc(device->func->resource_addr(device, 1),
448 device->func->resource_size(device, 1));
449
442} 450}
diff --git a/drivers/gpu/drm/radeon/radeon_object.c b/drivers/gpu/drm/radeon/radeon_object.c
index be30861afae9..41b72ce6613f 100644
--- a/drivers/gpu/drm/radeon/radeon_object.c
+++ b/drivers/gpu/drm/radeon/radeon_object.c
@@ -446,6 +446,10 @@ void radeon_bo_force_delete(struct radeon_device *rdev)
446 446
447int radeon_bo_init(struct radeon_device *rdev) 447int radeon_bo_init(struct radeon_device *rdev)
448{ 448{
449 /* reserve PAT memory space to WC for VRAM */
450 arch_io_reserve_memtype_wc(rdev->mc.aper_base,
451 rdev->mc.aper_size);
452
449 /* Add an MTRR for the VRAM */ 453 /* Add an MTRR for the VRAM */
450 if (!rdev->fastfb_working) { 454 if (!rdev->fastfb_working) {
451 rdev->mc.vram_mtrr = arch_phys_wc_add(rdev->mc.aper_base, 455 rdev->mc.vram_mtrr = arch_phys_wc_add(rdev->mc.aper_base,
@@ -463,6 +467,7 @@ void radeon_bo_fini(struct radeon_device *rdev)
463{ 467{
464 radeon_ttm_fini(rdev); 468 radeon_ttm_fini(rdev);
465 arch_phys_wc_del(rdev->mc.vram_mtrr); 469 arch_phys_wc_del(rdev->mc.vram_mtrr);
470 arch_io_free_memtype_wc(rdev->mc.aper_base, rdev->mc.aper_size);
466} 471}
467 472
468/* Returns how many bytes TTM can move per IB. 473/* Returns how many bytes TTM can move per IB.
diff --git a/include/linux/io.h b/include/linux/io.h
index e2c8419278c1..82ef36eac8a1 100644
--- a/include/linux/io.h
+++ b/include/linux/io.h
@@ -141,4 +141,26 @@ enum {
141void *memremap(resource_size_t offset, size_t size, unsigned long flags); 141void *memremap(resource_size_t offset, size_t size, unsigned long flags);
142void memunmap(void *addr); 142void memunmap(void *addr);
143 143
144/*
145 * On x86 PAT systems we have memory tracking that keeps track of
146 * the allowed mappings on memory ranges. This tracking works for
147 * all the in-kernel mapping APIs (ioremap*), but where the user
148 * wishes to map a range from a physical device into user memory
149 * the tracking won't be updated. This API is to be used by
150 * drivers which remap physical device pages into userspace,
151 * and wants to make sure they are mapped WC and not UC.
152 */
153#ifndef arch_io_reserve_memtype_wc
154static inline int arch_io_reserve_memtype_wc(resource_size_t base,
155 resource_size_t size)
156{
157 return 0;
158}
159
160static inline void arch_io_free_memtype_wc(resource_size_t base,
161 resource_size_t size)
162{
163}
164#endif
165
144#endif /* _LINUX_IO_H */ 166#endif /* _LINUX_IO_H */