Merge branch 'linux-tegra-2.6.36' into android-tegra-2.6.36

This commit is contained in:
Rebecca Schultz Zavin 2010-10-19 12:48:52 -07:00
commit d84db764fb
7 changed files with 70 additions and 215 deletions

View File

@ -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 <linux/types.h>
#include <asm/page.h>
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 */

View File

@ -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 || \

View File

@ -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

View File

@ -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 <linux/kernel.h>
#include <linux/highmem.h>
#include <linux/gfp.h>
#include <linux/page-flags.h>
#include <asm/tlbflush.h>
#include <asm/cacheflush.h>
#include <asm/pgtable.h>
#include <asm/pgalloc.h>
#include <asm/fixmap.h>
#include <asm/outercache.h>
#include <asm/attrib_alloc.h>
#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;
}

View File

@ -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

View File

@ -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);

View File

@ -28,7 +28,8 @@
#include <linux/slab.h>
#include <linux/vmalloc.h>
#include <asm/attrib_alloc.h>
#include <asm/cacheflush.h>
#include <asm/outercache.h>
#include <asm/pgtable.h>
#include <mach/iovmm.h>
@ -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,
};