From 8ef838e5ff7b3c005d7fbc725e17bcccd0e1e1eb Mon Sep 17 00:00:00 2001 From: Thomas Hellstrom Date: Thu, 28 Feb 2008 13:47:15 +0100 Subject: Add a compat kmap_atomic_prot_pfn to do quick kernel map / unmaps of PCI- or high memory. This is substantially more efficient than drm_bo_kmap, since the mapping only lives on a single processor. Unmapping is done use kunmap_atomic(). Flushes only a single tlb() entry. Add a support utility int drm_bo_pfn_prot() that returns the pfn and desired page protection for a given bo offset. This is all intended for relocations in bound TTMS or vram. Mapping-accessing-unmapping must be atomic, either using preempt_xx() macros or a spinlock. --- linux-core/drm_bo_move.c | 33 +++++++++++++++++++++++++++++++++ linux-core/drm_compat.c | 32 ++++++++++++++++++++++++++++++++ linux-core/drm_compat.h | 5 +++++ linux-core/drm_objects.h | 4 ++++ 4 files changed, 74 insertions(+) (limited to 'linux-core') diff --git a/linux-core/drm_bo_move.c b/linux-core/drm_bo_move.c index b06a09f0..30e0f43f 100644 --- a/linux-core/drm_bo_move.c +++ b/linux-core/drm_bo_move.c @@ -595,3 +595,36 @@ void drm_bo_kunmap(struct drm_bo_kmap_obj *map) map->page = NULL; } EXPORT_SYMBOL(drm_bo_kunmap); + +int drm_bo_pfn_prot(struct drm_buffer_object *bo, + unsigned long dst_offset, + unsigned long *pfn, + pgprot_t *prot) +{ + struct drm_bo_mem_reg *mem = &bo->mem; + struct drm_device *dev = bo->dev; + unsigned long bus_offset; + unsigned long bus_size; + unsigned long bus_base; + struct drm_mem_type_manager *man = &dev->bm.man[mem->mem_type]; + int ret; + + ret = drm_bo_pci_offset(dev, mem, &bus_base, &bus_offset, + &bus_size); + if (ret) + return -EINVAL; + + if (bus_size != 0) + *pfn = (bus_base + bus_offset + dst_offset) >> PAGE_SHIFT; + else if (!bo->ttm) + return -EINVAL; + else + *pfn = page_to_pfn(drm_ttm_get_page(bo->ttm, dst_offset >> PAGE_SHIFT)); + + *prot = (mem->flags & DRM_BO_FLAG_CACHED) ? + PAGE_KERNEL : drm_kernel_io_prot(man->drm_bus_maptype); + + return 0; +} +EXPORT_SYMBOL(drm_bo_pfn_prot); + diff --git a/linux-core/drm_compat.c b/linux-core/drm_compat.c index a745a7d9..32e43a0a 100644 --- a/linux-core/drm_compat.c +++ b/linux-core/drm_compat.c @@ -729,3 +729,35 @@ void *idr_replace(struct idr *idp, void *ptr, int id) } EXPORT_SYMBOL(idr_replace); #endif + +#if defined(CONFIG_X86) + +#define drm_kmap_get_fixmap_pte(vaddr) \ + pte_offset_kernel(pmd_offset(pud_offset(pgd_offset_k(vaddr), vaddr), (vaddr)), (vaddr)) + +void *kmap_atomic_prot_pfn(unsigned long pfn, enum km_type type, + pgprot_t protection) +{ + enum fixed_addresses idx; + unsigned long vaddr; + static pte_t *km_pte; + static int initialized = 0; + + if (unlikely(!initialized)) { + km_pte = drm_kmap_get_fixmap_pte(__fix_to_virt(FIX_KMAP_BEGIN)); + initialized = 1; + } + + pagefault_disable(); + idx = type + KM_TYPE_NR*smp_processor_id(); + vaddr = __fix_to_virt(FIX_KMAP_BEGIN + idx); + set_pte(km_pte-idx, pfn_pte(pfn, protection)); + + return (void*) vaddr; +} + +EXPORT_SYMBOL(kmap_atomic_prot_pfn); + +#endif + + diff --git a/linux-core/drm_compat.h b/linux-core/drm_compat.h index f8933e0c..39027cf4 100644 --- a/linux-core/drm_compat.h +++ b/linux-core/drm_compat.h @@ -328,4 +328,9 @@ void *idr_replace(struct idr *idp, void *ptr, int id); typedef _Bool bool; #endif +#if defined(CONFIG_X86) +#define DRM_KMAP_ATOMIC_PROT_PFN +extern void *kmap_atomic_prot_pfn(unsigned long pfn, enum km_type type, + pgprot_t protection); +#endif #endif diff --git a/linux-core/drm_objects.h b/linux-core/drm_objects.h index e43e8dfd..8055afe1 100644 --- a/linux-core/drm_objects.h +++ b/linux-core/drm_objects.h @@ -738,6 +738,10 @@ static inline void *drm_bmo_virtual(struct drm_bo_kmap_obj *map, int *is_iomem) extern void drm_bo_kunmap(struct drm_bo_kmap_obj *map); extern int drm_bo_kmap(struct drm_buffer_object *bo, unsigned long start_page, unsigned long num_pages, struct drm_bo_kmap_obj *map); +extern int drm_bo_pfn_prot(struct drm_buffer_object *bo, + unsigned long dst_offset, + unsigned long *pfn, + pgprot_t *prot); /* -- cgit v1.2.3 From cdbd616ea5f0ee491ff82cac74b918a14b039917 Mon Sep 17 00:00:00 2001 From: Dave Airlie Date: Fri, 29 Feb 2008 10:16:24 +1000 Subject: agp: export the correct symbol --- linux-core/drm_agpsupport.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'linux-core') diff --git a/linux-core/drm_agpsupport.c b/linux-core/drm_agpsupport.c index 02187017..f58d5516 100644 --- a/linux-core/drm_agpsupport.c +++ b/linux-core/drm_agpsupport.c @@ -666,7 +666,7 @@ void drm_agp_chipset_flush(struct drm_device *dev) { agp_flush_chipset(dev->agp->bridge); } -EXPORT_SYMBOL(drm_agp_flush_chipset); +EXPORT_SYMBOL(drm_agp_chipset_flush); #endif #endif /* __OS_HAS_AGP */ -- cgit v1.2.3 From 1d068973d5f5e6d8d14b4c0c6e28588107aafc6f Mon Sep 17 00:00:00 2001 From: Thomas Hellstrom Date: Fri, 29 Feb 2008 13:31:14 +0100 Subject: Fix compilation breakage on x86-64. --- linux-core/drm_compat.c | 3 +-- linux-core/drm_compat.h | 2 +- 2 files changed, 2 insertions(+), 3 deletions(-) (limited to 'linux-core') diff --git a/linux-core/drm_compat.c b/linux-core/drm_compat.c index 32e43a0a..eb6c5d81 100644 --- a/linux-core/drm_compat.c +++ b/linux-core/drm_compat.c @@ -730,8 +730,7 @@ void *idr_replace(struct idr *idp, void *ptr, int id) EXPORT_SYMBOL(idr_replace); #endif -#if defined(CONFIG_X86) - +#if defined(DRM_KMAP_ATOMIC_PROT_PFN) #define drm_kmap_get_fixmap_pte(vaddr) \ pte_offset_kernel(pmd_offset(pud_offset(pgd_offset_k(vaddr), vaddr), (vaddr)), (vaddr)) diff --git a/linux-core/drm_compat.h b/linux-core/drm_compat.h index 39027cf4..08892e6b 100644 --- a/linux-core/drm_compat.h +++ b/linux-core/drm_compat.h @@ -328,7 +328,7 @@ void *idr_replace(struct idr *idp, void *ptr, int id); typedef _Bool bool; #endif -#if defined(CONFIG_X86) +#if (defined(CONFIG_X86) && defined(CONFIG_X86_32)) #define DRM_KMAP_ATOMIC_PROT_PFN extern void *kmap_atomic_prot_pfn(unsigned long pfn, enum km_type type, pgprot_t protection); -- cgit v1.2.3 From 09999c90ab1bf3f7d8b277895c962c8a7b3afc18 Mon Sep 17 00:00:00 2001 From: Patrice Mandin Date: Fri, 29 Feb 2008 21:57:40 +0100 Subject: FIX_KMAP_BEGIN requires CONFIG_HIMEM (see include/asm-i386.h/fixmap.h) --- linux-core/drm_compat.c | 2 +- linux-core/drm_compat.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) (limited to 'linux-core') diff --git a/linux-core/drm_compat.c b/linux-core/drm_compat.c index eb6c5d81..d4044cbd 100644 --- a/linux-core/drm_compat.c +++ b/linux-core/drm_compat.c @@ -730,7 +730,7 @@ void *idr_replace(struct idr *idp, void *ptr, int id) EXPORT_SYMBOL(idr_replace); #endif -#if defined(DRM_KMAP_ATOMIC_PROT_PFN) +#if defined(DRM_KMAP_ATOMIC_PROT_PFN) && defined(CONFIG_HIMEM) #define drm_kmap_get_fixmap_pte(vaddr) \ pte_offset_kernel(pmd_offset(pud_offset(pgd_offset_k(vaddr), vaddr), (vaddr)), (vaddr)) diff --git a/linux-core/drm_compat.h b/linux-core/drm_compat.h index 08892e6b..136a7296 100644 --- a/linux-core/drm_compat.h +++ b/linux-core/drm_compat.h @@ -328,7 +328,7 @@ void *idr_replace(struct idr *idp, void *ptr, int id); typedef _Bool bool; #endif -#if (defined(CONFIG_X86) && defined(CONFIG_X86_32)) +#if (defined(CONFIG_X86) && defined(CONFIG_X86_32) && defined(CONFIG_HIMEM)) #define DRM_KMAP_ATOMIC_PROT_PFN extern void *kmap_atomic_prot_pfn(unsigned long pfn, enum km_type type, pgprot_t protection); -- cgit v1.2.3 From d41846adb72ba89c94ea1164e366032b1d36bd55 Mon Sep 17 00:00:00 2001 From: Eric Anholt Date: Tue, 4 Mar 2008 13:35:23 -0800 Subject: Clarify through the names what drm_ttm_alloc_pages() and friend actually did. These are all about the page directory (pointers to pages) rather than the actual pages backing the allocation. --- linux-core/drm_objects.h | 2 +- linux-core/drm_ttm.c | 21 +++++++++++---------- 2 files changed, 12 insertions(+), 11 deletions(-) (limited to 'linux-core') diff --git a/linux-core/drm_objects.h b/linux-core/drm_objects.h index 8055afe1..69a5c27f 100644 --- a/linux-core/drm_objects.h +++ b/linux-core/drm_objects.h @@ -384,7 +384,7 @@ extern int drm_ttm_destroy(struct drm_ttm *ttm); * The array of page pointers was allocated with vmalloc * instead of drm_calloc. */ -#define DRM_TTM_PAGE_VMALLOC (1 << 4) +#define DRM_TTM_PAGEDIR_VMALLOC (1 << 4) /* * This ttm is mapped from user space */ diff --git a/linux-core/drm_ttm.c b/linux-core/drm_ttm.c index a9d87338..cc80b132 100644 --- a/linux-core/drm_ttm.c +++ b/linux-core/drm_ttm.c @@ -42,11 +42,12 @@ void drm_ttm_cache_flush(void) } EXPORT_SYMBOL(drm_ttm_cache_flush); -/* - * Use kmalloc if possible. Otherwise fall back to vmalloc. +/** + * Allocates storage for pointers to the pages that back the ttm. + * + * Uses kmalloc if possible. Otherwise falls back to vmalloc. */ - -static void drm_ttm_alloc_pages(struct drm_ttm *ttm) +static void drm_ttm_alloc_page_directory(struct drm_ttm *ttm) { unsigned long size = ttm->num_pages * sizeof(*ttm->pages); ttm->pages = NULL; @@ -60,19 +61,19 @@ static void drm_ttm_alloc_pages(struct drm_ttm *ttm) if (!ttm->pages) { ttm->pages = vmalloc_user(size); if (ttm->pages) - ttm->page_flags |= DRM_TTM_PAGE_VMALLOC; + ttm->page_flags |= DRM_TTM_PAGEDIR_VMALLOC; } if (!ttm->pages) drm_free_memctl(size); } -static void drm_ttm_free_pages(struct drm_ttm *ttm) +static void drm_ttm_free_page_directory(struct drm_ttm *ttm) { unsigned long size = ttm->num_pages * sizeof(*ttm->pages); - if (ttm->page_flags & DRM_TTM_PAGE_VMALLOC) { + if (ttm->page_flags & DRM_TTM_PAGEDIR_VMALLOC) { vfree(ttm->pages); - ttm->page_flags &= ~DRM_TTM_PAGE_VMALLOC; + ttm->page_flags &= ~DRM_TTM_PAGEDIR_VMALLOC; } else { drm_free(ttm->pages, size, DRM_MEM_TTM); } @@ -215,7 +216,7 @@ int drm_ttm_destroy(struct drm_ttm *ttm) else drm_ttm_free_alloced_pages(ttm); - drm_ttm_free_pages(ttm); + drm_ttm_free_page_directory(ttm); } drm_ctl_free(ttm, sizeof(*ttm), DRM_MEM_TTM); @@ -349,7 +350,7 @@ struct drm_ttm *drm_ttm_create(struct drm_device *dev, unsigned long size, * Account also for AGP module memory usage. */ - drm_ttm_alloc_pages(ttm); + drm_ttm_alloc_page_directory(ttm); if (!ttm->pages) { drm_ttm_destroy(ttm); DRM_ERROR("Failed allocating page table\n"); -- cgit v1.2.3