diff options
Diffstat (limited to 'linux-core')
-rw-r--r-- | linux-core/Makefile.kernel | 2 | ||||
-rw-r--r-- | linux-core/drm_compat.c | 140 | ||||
-rw-r--r-- | linux-core/drm_compat.h | 18 |
3 files changed, 159 insertions, 1 deletions
diff --git a/linux-core/Makefile.kernel b/linux-core/Makefile.kernel index 651e30b0..c7c47919 100644 --- a/linux-core/Makefile.kernel +++ b/linux-core/Makefile.kernel @@ -12,7 +12,7 @@ drm-objs := drm_auth.o drm_bufs.o drm_context.o drm_dma.o drm_drawable.o \ drm_lock.o drm_memory.o drm_proc.o drm_stub.o drm_vm.o \ drm_sysfs.o drm_pci.o drm_agpsupport.o drm_scatter.o \ drm_memory_debug.o ati_pcigart.o drm_sman.o \ - drm_hashtab.o drm_mm.o drm_object.o + drm_hashtab.o drm_mm.o drm_object.o drm_compat.o tdfx-objs := tdfx_drv.o r128-objs := r128_drv.o r128_cce.o r128_state.o r128_irq.o mga-objs := mga_drv.o mga_dma.o mga_state.o mga_warp.o mga_irq.o diff --git a/linux-core/drm_compat.c b/linux-core/drm_compat.c new file mode 100644 index 00000000..cdef4b97 --- /dev/null +++ b/linux-core/drm_compat.c @@ -0,0 +1,140 @@ +/************************************************************************** + * + * This kernel module is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * + **************************************************************************/ +/* + * This code provides access to unexported mm kernel features. It is necessary + * to use the new DRM memory manager code with kernels that don't support it + * directly. + * + * Authors: Thomas Hellstrom <thomas-at-tungstengraphics-dot-com> + * Linux kernel mm subsystem authors. + * (Most code taken from there). + */ + +#include "drmP.h" +#include <asm/pgtable.h> +#include <asm/cacheflush.h> +#include <asm/tlbflush.h> + +#ifdef MODULE +void pgd_clear_bad(pgd_t * pgd) +{ + pgd_ERROR(*pgd); + pgd_clear(pgd); +} + +void pud_clear_bad(pud_t * pud) +{ + pud_ERROR(*pud); + pud_clear(pud); +} + +void pmd_clear_bad(pmd_t * pmd) +{ + pmd_ERROR(*pmd); + pmd_clear(pmd); +} +#endif + +static inline void change_pte_range(struct mm_struct *mm, pmd_t * pmd, + unsigned long addr, unsigned long end) +{ + pte_t *pte; + + pte = pte_offset_map(pmd, addr); + do { + if (pte_present(*pte)) { + pte_t ptent; + ptent = *pte; + ptep_get_and_clear(mm, addr, pte); + lazy_mmu_prot_update(ptent); + } + } while (pte++, addr += PAGE_SIZE, addr != end); + pte_unmap(pte - 1); +} + +static inline void change_pmd_range(struct mm_struct *mm, pud_t * pud, + unsigned long addr, unsigned long end) +{ + pmd_t *pmd; + unsigned long next; + + pmd = pmd_offset(pud, addr); + do { + next = pmd_addr_end(addr, end); + if (pmd_none_or_clear_bad(pmd)) + continue; + change_pte_range(mm, pmd, addr, next); + } while (pmd++, addr = next, addr != end); +} + +static inline void change_pud_range(struct mm_struct *mm, pgd_t * pgd, + unsigned long addr, unsigned long end) +{ + pud_t *pud; + unsigned long next; + + pud = pud_offset(pgd, addr); + do { + next = pud_addr_end(addr, end); + if (pud_none_or_clear_bad(pud)) + continue; + change_pmd_range(mm, pud, addr, next); + } while (pud++, addr = next, addr != end); +} + +/* + * This function should be called with all relevant spinlocks held. + */ + +void drm_clear_vma(struct vm_area_struct *vma, + unsigned long addr, unsigned long end) +{ + struct mm_struct *mm = vma->vm_mm; + pgd_t *pgd; + unsigned long next; +#if defined(flush_tlb_mm) || !defined(MODULE) + unsigned long start = addr; +#endif + BUG_ON(addr >= end); + pgd = pgd_offset(mm, addr); + flush_cache_range(vma, addr, end); + do { + next = pgd_addr_end(addr, end); + if (pgd_none_or_clear_bad(pgd)) + continue; + change_pud_range(mm, pgd, addr, next); + } while (pgd++, addr = next, addr != end); +#if defined(flush_tlb_mm) || !defined(MODULE) + flush_tlb_range(vma, addr, end); +#endif +} + +pgprot_t drm_prot_map(uint32_t flags) +{ +#ifdef MODULE + static pgprot_t drm_protection_map[16] = { + __P000, __P001, __P010, __P011, __P100, __P101, __P110, __P111, + __S000, __S001, __S010, __S011, __S100, __S101, __S110, __S111 + }; + + return drm_protection_map[flags & 0x0F]; +#else + extern pgprot_t protection_map[]; + return protection_map[flags & 0x0F]; +#endif +}; diff --git a/linux-core/drm_compat.h b/linux-core/drm_compat.h index 407853d7..80928319 100644 --- a/linux-core/drm_compat.h +++ b/linux-core/drm_compat.h @@ -227,4 +227,22 @@ static inline int remap_pfn_range(struct vm_area_struct *vma, unsigned long from } #endif +#include <linux/mm.h> +#include <asm/page.h> + +/* + * Flush relevant caches and clear a VMA structure so that page references + * will cause a page fault. Don't flush tlbs. + */ + +extern void drm_clear_vma(struct vm_area_struct *vma, + unsigned long addr, unsigned long end); + +/* + * Return the PTE protection map entries for the VMA flags given by + * flags. This is a functional interface to the kernel's protection map. + */ + +extern pgprot_t drm_prot_map(uint32_t flags); + #endif |