mirror of
https://github.com/torvalds/linux.git
synced 2026-06-10 23:53:52 +02:00
Merge branch 'linux-tegra-2.6.36' into android-tegra-2.6.36
This commit is contained in:
commit
d84db764fb
|
|
@ -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 */
|
||||
|
|
@ -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 || \
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
|
@ -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
|
||||
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
};
|
||||
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user