diff --git a/arch/arm/include/asm/attrib_alloc.h b/arch/arm/include/asm/attrib_alloc.h deleted file mode 100644 index bd21761810f5..000000000000 --- a/arch/arm/include/asm/attrib_alloc.h +++ /dev/null @@ -1,47 +0,0 @@ -/* - * arch/arm/include/asm/attrib_alloc.h - * - * Page allocator with custom cache attributes - * - * Copyright (c) 2010, NVIDIA Corporation. - * - * This program 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., - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - */ - -#ifndef __ARCH_ARM_ATTRIB_ALLOC_H -#define __ARCH_ARM_ATTRIB_ALLOC_H - -#include -#include - -struct page *arm_attrib_alloc_pages_exact_node(int nid, gfp_t gfp, - size_t size, pgprot_t prot); - -void arm_attrib_free_pages_exact(struct page *page, size_t size); - -static inline -struct page *arm_attrib_alloc_pages_exact(gfp_t gfp, size_t size, - pgprot_t prot) -{ - return arm_attrib_alloc_pages_exact_node(-1, gfp, size, prot); -} - -#define arm_attrib_alloc_page(gfp, prot) \ - arm_attrib_alloc_pages_exact((gfp), PAGE_SIZE, (prot)) - -#define arm_attrib_free_page(page) \ - arm_attrib_free_pages_exact((page), PAGE_SIZE) - -#endif /* __ARCH_ARM_ATTRIB_ALLOC_H */ diff --git a/arch/arm/mm/Kconfig b/arch/arm/mm/Kconfig index da057fcd0491..cc6f9d6193dd 100644 --- a/arch/arm/mm/Kconfig +++ b/arch/arm/mm/Kconfig @@ -808,29 +808,6 @@ config ARM_L1_CACHE_SHIFT default 6 if ARM_L1_CACHE_SHIFT_6 default 5 -config ARM_ATTRIB_ALLOCATOR - bool "Support custom cache attribute allocations in low memory" - select ARCH_LOWMEM_IN_PTES if (CPU_V7) - depends on MMU && !CPU_CACHE_VIVT - help - Historically, the kernel has only reserved a small region - of physical memory for uncached access, and relied on - explicit cache maintenance for ensuring coherency between - the CPU and DMA. - - However, many recent systems support mapping discontiguous - physical pages into contiguous DMA addresses (so-called - system MMUs). For some DMA clients (notably graphics and - multimedia engines), performing explict cache maintenance - between CPU and DMA mappings can be prohibitively expensive, - and since ARMv7, mapping the same physical page with different - cache attributes is disallowed and has unpredictable behavior. - - Say 'Y' here to include page allocation support with explicit - cache attributes; on ARMv7 systems this will also force the - kernel's page tables to be mapped using page tables rather - than sections. - config ARM_DMA_MEM_BUFFERABLE bool "Use non-cacheable memory for DMA" if CPU_V6 && !CPU_V7 depends on !(MACH_REALVIEW_PB1176 || REALVIEW_EB_ARM11MP || \ diff --git a/arch/arm/mm/Makefile b/arch/arm/mm/Makefile index 16e8164b63bc..d63b6c413758 100644 --- a/arch/arm/mm/Makefile +++ b/arch/arm/mm/Makefile @@ -12,8 +12,6 @@ ifneq ($(CONFIG_MMU),y) obj-y += nommu.o endif -obj-$(CONFIG_ARM_ATTRIB_ALLOCATOR) += attrib_alloc.o - obj-$(CONFIG_MODULES) += proc-syms.o obj-$(CONFIG_ALIGNMENT_TRAP) += alignment.o diff --git a/arch/arm/mm/attrib_alloc.c b/arch/arm/mm/attrib_alloc.c deleted file mode 100644 index 73be2d664669..000000000000 --- a/arch/arm/mm/attrib_alloc.c +++ /dev/null @@ -1,126 +0,0 @@ -/* - * arch/arm/mm/attrib_alloc.c - * - * Page allocator with custom cache attributes - * - * Copyright (c) 2010, NVIDIA Corporation. - * - * This program 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., - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include "mm.h" - -static void update_kmap_pte(struct page *page, pgprot_t prot) -{ -#ifdef CONFIG_HIGHMEM - unsigned long addr; - pte_t *pte; - - addr = (unsigned long)kmap_high_get(page); - BUG_ON(!PageHighMem(page) || addr >= FIXADDR_START); - if (!addr) - return; - - pte = &pkmap_page_table[PKMAP_NR(addr)]; - set_pte_at(&init_mm, addr, pte, mk_pte(page, __pgprot(prot))); - flush_tlb_kernel_range(addr, addr + PAGE_SIZE); - kunmap_high(page); -#endif -} - -static void update_pte(struct page *page, pgprot_t prot) -{ -#ifdef CONFIG_ARCH_LOWMEM_IN_PTES - unsigned long addr = (unsigned long)page_address(page); - pgd_t *pgd = pgd_offset_k(addr); - pmd_t *pmd = pmd_offset(pgd, addr); - pte_t *pte; - - BUG_ON(pmd_none(*pmd)); - pte = pte_offset_kernel(pmd, addr); - set_pte_at(&init_mm, addr, pte, mk_pte(page, __pgprot(prot))); - flush_tlb_kernel_range(addr, addr + PAGE_SIZE); -#endif -} - -void arm_attrib_free_pages_exact(struct page *page, size_t size) -{ - struct page *p, *e; - - size = PAGE_ALIGN(size); - e = page + (size >> PAGE_SHIFT); - - /* reset the page's mappings back to the standard kernel mappings - * before returning it to the page allocator */ - for (p = page; p < e; p++) { - if (PageHighMem(p)) - update_kmap_pte(p, pgprot_kernel); - else - update_pte(p, pgprot_kernel); - - __free_page(p); - } -} - -struct page *arm_attrib_alloc_pages_exact_node(int nid, gfp_t gfp, - size_t size, pgprot_t prot) -{ - struct page *page, *p, *e; - unsigned int order; - unsigned long base; - - size = PAGE_ALIGN(size); - order = get_order(size); - page = alloc_pages_node(nid, gfp, order); - - if (!page) - return NULL; - - split_page(page, order); - - e = page + (1 << order); - for (p = page + (size >> PAGE_SHIFT); p < e; p++) - __free_page(p); - - e = page + (size >> PAGE_SHIFT); - - for (p = page; p < e; p++) { - __flush_dcache_page(page_mapping(p), p); - - /* even though a freshly-allocated highmem page shouldn't - * be mapped, because the kmaps are flushed lazily, it - * is possible that a mapping from an old kmap_high call - * is still present, and its cache attributes need to - * be updated to match the new expectations */ - if (PageHighMem(p)) - update_kmap_pte(p, prot); - else - update_pte(p, prot); - } - base = page_to_phys(page); - outer_flush_range(base, base + size); - return page; -} diff --git a/drivers/video/tegra/Kconfig b/drivers/video/tegra/Kconfig index f9192c6d68b8..2b8160877688 100644 --- a/drivers/video/tegra/Kconfig +++ b/drivers/video/tegra/Kconfig @@ -28,22 +28,38 @@ config FB_TEGRA Framebuffer device support for the Tegra display controller. config TEGRA_NVMAP - bool "Tegra GPU memory management driver" - select ARM_ATTRIB_ALLOCATOR + bool "Tegra GPU memory management driver (nvmap)" default y help Say Y here to include the memory management driver for the Tegra GPU, multimedia and display subsystems config NVMAP_RECLAIM_UNPINNED_VM - bool "Allow /dev/nvmap to reclaim unpinned I/O virtual memory" + bool "Virtualize IOVMM memory in nvmap" depends on TEGRA_NVMAP && TEGRA_IOVMM default y help - Say Y here to enable /dev/nvmap to reclaim I/O virtual memory after - it has been unpinned, and re-use it for other objects. This can + Say Y here to enable nvmap to reclaim I/O virtual memory after + it has been unpinned, and re-use it for other handles. This can allow a larger virtual I/O VM space than would normally be supported by the hardware, at a slight cost in performance. +config NVMAP_ALLOW_SYSMEM + bool "Allow physical system memory to be used by nvmap" + depends on TEGRA_NVMAP + default y + help + Say Y here to allow nvmap to use physical system memory (i.e., + shared with the operating system but not translated through + an IOVMM device) for allocations. + +config NVMAP_HIGHMEM_ONLY + bool "Use only HIGHMEM for nvmap" + depends on TEGRA_NVMAP && (NVMAP_ALLOW_SYSMEM || TEGRA_IOVMM) && HIGHMEM + default n + help + Say Y here to restrict nvmap system memory allocations (both + physical system memory and IOVMM) to just HIGHMEM pages. + endif diff --git a/drivers/video/tegra/nvmap/nvmap.c b/drivers/video/tegra/nvmap/nvmap.c index 506aef8408a9..865681f2e221 100644 --- a/drivers/video/tegra/nvmap/nvmap.c +++ b/drivers/video/tegra/nvmap/nvmap.c @@ -623,10 +623,7 @@ void *nvmap_mmap(struct nvmap_handle_ref *ref) prot = nvmap_pgprot(h, pgprot_kernel); - if (h->heap_pgalloc && h->pgalloc.contig && - !PageHighMem(h->pgalloc.pages[0])) - return page_address(h->pgalloc.pages[0]); - else if (h->heap_pgalloc) + if (h->heap_pgalloc) return vm_map_ram(h->pgalloc.pages, h->size >> PAGE_SHIFT, -1, prot); @@ -687,10 +684,9 @@ void nvmap_munmap(struct nvmap_handle_ref *ref, void *addr) h = ref->handle; - if (h->heap_pgalloc && (!h->pgalloc.contig || - PageHighMem(h->pgalloc.pages[0]))) { + if (h->heap_pgalloc) { vm_unmap_ram(addr, h->size >> PAGE_SHIFT); - } else if (!h->heap_pgalloc) { + } else { struct vm_struct *vm; addr -= (h->carveout->base & ~PAGE_MASK); vm = remove_vm_area(addr); diff --git a/drivers/video/tegra/nvmap/nvmap_handle.c b/drivers/video/tegra/nvmap/nvmap_handle.c index 21cbf9c4d85d..725a132ff6fd 100644 --- a/drivers/video/tegra/nvmap/nvmap_handle.c +++ b/drivers/video/tegra/nvmap/nvmap_handle.c @@ -28,7 +28,8 @@ #include #include -#include +#include +#include #include #include @@ -38,7 +39,11 @@ #include "nvmap_mru.h" #define NVMAP_SECURE_HEAPS (NVMAP_HEAP_CARVEOUT_IRAM | NVMAP_HEAP_IOVMM) +#ifdef CONFIG_NVMAP_HIGHMEM_ONLY #define GFP_NVMAP (__GFP_HIGHMEM | __GFP_NOWARN) +#else +#define GFP_NVMAP (GFP_KERNEL | __GFP_HIGHMEM | __GFP_NOWARN) +#endif /* handles may be arbitrarily large (16+MiB), and any handle allocated from * the kernel (i.e., not a carveout handle) includes its array of pages. to * preserve kmalloc space, if the array of pages exceeds PAGELIST_VMALLOC_MIN, @@ -90,7 +95,7 @@ void _nvmap_handle_free(struct nvmap_handle *h) tegra_iovmm_free_vm(h->pgalloc.area); for (i = 0; i < nr_page; i++) - arm_attrib_free_page(h->pgalloc.pages[i]); + __free_page(h->pgalloc.pages[i]); altfree(h->pgalloc.pages, nr_page * sizeof(struct page *)); @@ -99,6 +104,36 @@ void _nvmap_handle_free(struct nvmap_handle *h) nvmap_client_put(client); } +extern void __flush_dcache_page(struct address_space *, struct page *); + +static struct page *nvmap_alloc_pages_exact(gfp_t gfp, size_t size) +{ + struct page *page, *p, *e; + unsigned int order; + unsigned long base; + + size = PAGE_ALIGN(size); + order = get_order(size); + page = alloc_pages(gfp, order); + + if (!page) + return NULL; + + split_page(page, order); + + e = page + (1 << order); + for (p = page + (size >> PAGE_SHIFT); p < e; p++) + __free_page(p); + + e = page + (size >> PAGE_SHIFT); + for (p = page; p < e; p++) + __flush_dcache_page(page_mapping(p), p); + + base = page_to_phys(page); + outer_flush_range(base, base + size); + return page; +} + static int handle_page_alloc(struct nvmap_client *client, struct nvmap_handle *h, bool contiguous) { @@ -120,14 +155,16 @@ static int handle_page_alloc(struct nvmap_client *client, h->pgalloc.area = NULL; if (contiguous) { struct page *page; - page = arm_attrib_alloc_pages_exact(GFP_NVMAP, size, prot); + page = nvmap_alloc_pages_exact(GFP_NVMAP, size); + if (!page) + goto fail; for (i = 0; i < nr_page; i++) pages[i] = nth_page(page, i); } else { for (i = 0; i < nr_page; i++) { - pages[i] = arm_attrib_alloc_page(GFP_NVMAP, prot); + pages[i] = nvmap_alloc_pages_exact(GFP_NVMAP, PAGE_SIZE); if (!pages[i]) goto fail; } @@ -151,7 +188,7 @@ static int handle_page_alloc(struct nvmap_client *client, fail: while (i--) - arm_attrib_free_page(pages[i]); + __free_page(pages[i]); altfree(pages, nr_page * sizeof(*pages)); return -ENOMEM; } @@ -210,7 +247,9 @@ static void alloc_handle(struct nvmap_client *client, size_t align, * sub-page splinters */ static const unsigned int heap_policy_small[] = { NVMAP_HEAP_CARVEOUT_IRAM, +#ifdef CONFIG_NVMAP_ALLOW_SYSMEM NVMAP_HEAP_SYSMEM, +#endif NVMAP_HEAP_CARVEOUT_MASK, NVMAP_HEAP_IOVMM, 0, @@ -220,7 +259,9 @@ static const unsigned int heap_policy_large[] = { NVMAP_HEAP_CARVEOUT_IRAM, NVMAP_HEAP_IOVMM, NVMAP_HEAP_CARVEOUT_MASK, +#ifdef CONFIG_NVMAP_ALLOW_SYSMEM NVMAP_HEAP_SYSMEM, +#endif 0, };