Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(8)

Unified Diff: arch/arm/mach-tegra/nv/nvos/nvos_page.c

Issue 3256004: [ARM] tegra: add nvos/nvrm/nvmap drivers (Closed) Base URL: ssh://git@gitrw.chromium.org/kernel.git
Patch Set: remove ap15 headers Created 10 years, 4 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
« no previous file with comments | « arch/arm/mach-tegra/nv/nvos/nvos_exports.c ('k') | arch/arm/mach-tegra/nv/nvos/nvustring.c » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: arch/arm/mach-tegra/nv/nvos/nvos_page.c
diff --git a/arch/arm/mach-tegra/nv/nvos/nvos_page.c b/arch/arm/mach-tegra/nv/nvos/nvos_page.c
new file mode 100644
index 0000000000000000000000000000000000000000..fe0326f612b1a9581e5166a3e4f23b3f2fce716b
--- /dev/null
+++ b/arch/arm/mach-tegra/nv/nvos/nvos_page.c
@@ -0,0 +1,236 @@
+/*
+ * arch/arm/mach-tegra/nvos/nvos_page.c
+ *
+ * Implementation of NvOsPage* APIs using the Linux page allocator
+ *
+ * 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/vmalloc.h>
+#include <linux/highmem.h>
+#include <asm/cacheflush.h>
+#include <asm/tlbflush.h>
+#include <asm/pgtable.h>
+#include <asm/pgalloc.h>
+#include "nvcommon.h"
+#include "nvos.h"
+#include <linux/slab.h>
+
+#if NVOS_TRACE || NV_DEBUG
+#undef NvOsPageMap
+#undef NvOsPageGetPage
+#undef NvOsPageAddress
+#undef NvOsPageUnmap
+#undef NvOsPageAlloc
+#undef NvOsPageFree
+#undef NvOsPageLock
+#undef NvOsPageMapIntoPtr
+#endif
+
+#define L_PTE_MT_INNER_WB (0x05 << 2) /* 0101 (armv6, armv7) */
+#define pgprot_inner_writeback(prot) \
+ __pgprot((pgprot_val(prot) & ~L_PTE_MT_MASK) | L_PTE_MT_INNER_WB)
+
+#define nv_gfp_pool (GFP_KERNEL | __GFP_HIGHMEM | __GFP_NOWARN)
+
+struct nvos_pagemap {
+ void *addr;
+ unsigned int nr_pages;
+ struct page *pages[1];
+};
+
+static void pagemap_flush_page(struct page *page)
+{
+#ifdef CONFIG_HIGHMEM
+ void *km = NULL;
+
+ if (!page_address(page)) {
+ km = kmap(page);
+ if (!km) {
+ pr_err("unable to map high page\n");
+ return;
+ }
+ }
+#endif
+
+ flush_dcache_page(page_address(page));
+ outer_flush_range(page_to_phys(page), page_to_phys(page)+PAGE_SIZE);
+ dsb();
+
+#ifdef CONFIG_HIGHMEM
+ if (km) kunmap(page);
+#endif
+}
+
+static void nv_free_pages(struct nvos_pagemap *pm)
+{
+ unsigned int i;
+
+ if (pm->addr) vm_unmap_ram(pm->addr, pm->nr_pages);
+
+ for (i=0; i<pm->nr_pages; i++) {
+ ClearPageReserved(pm->pages[i]);
+ __free_page(pm->pages[i]);
+ }
+ kfree(pm);
+}
+
+static struct nvos_pagemap *nv_alloc_pages(unsigned int count,
+ pgprot_t prot, bool contiguous, int create_mapping)
+{
+ struct nvos_pagemap *pm;
+ size_t size;
+ unsigned int i = 0;
+
+ size = sizeof(struct nvos_pagemap) + sizeof(struct page *)*(count-1);
+ pm = kzalloc(size, GFP_KERNEL);
+ if (!pm)
+ return NULL;
+
+ if (count==1) contiguous = true;
+
+ if (contiguous) {
+ size_t order = get_order(count << PAGE_SHIFT);
+ struct page *compound_page;
+ compound_page = alloc_pages(nv_gfp_pool, order);
+ if (!compound_page) goto fail;
+
+ split_page(compound_page, order);
+ for (i=0; i<count; i++)
+ pm->pages[i] = nth_page(compound_page, i);
+
+ for ( ; i < (1<<order); i++)
+ __free_page(nth_page(compound_page, i));
+ i = count;
+ } else {
+ for (i=0; i<count; i++) {
+ pm->pages[i] = alloc_page(nv_gfp_pool);
+ if (!pm->pages[i]) goto fail;
+ }
+ }
+
+ if (create_mapping) {
+ /* since the linear kernel mapping uses sections and super-
+ * sections rather than PTEs, it's not possible to overwrite
+ * it with the correct caching attributes, so use a local
+ * mapping */
+ pm->addr = vm_map_ram(pm->pages, count, -1, prot);
+ if (!pm->addr) {
+ pr_err("nv_alloc_pages fail to vmap contiguous area\n");
+ goto fail;
+ }
+ }
+
+ pm->nr_pages = count;
+ for (i=0; i<count; i++) {
+ SetPageReserved(pm->pages[i]);
+ pagemap_flush_page(pm->pages[i]);
+ }
+
+ return pm;
+
+fail:
+ while (i) __free_page(pm->pages[--i]);
+ if (pm) kfree(pm);
+ return NULL;
+}
+
+NvError NvOsPageMap(NvOsPageAllocHandle desc, size_t offs,
+ size_t size, void **ptr)
+{
+ struct nvos_pagemap *pm = (struct nvos_pagemap *)desc;
+ if (!desc || !ptr || !size)
+ return NvError_BadParameter;
+
+ if (pm->addr) *ptr = (void*)((unsigned long)pm->addr + offs);
+ else *ptr = NULL;
+
+ return (*ptr) ? NvSuccess : NvError_MemoryMapFailed;
+}
+
+struct page *NvOsPageGetPage(NvOsPageAllocHandle desc, size_t offs)
+{
+ struct nvos_pagemap *pm = (struct nvos_pagemap *)desc;
+ if (!pm) return NULL;
+
+ offs >>= PAGE_SHIFT;
+ return (likely(offs<pm->nr_pages)) ? pm->pages[offs] : NULL;
+}
+
+NvOsPhysAddr NvOsPageAddress(NvOsPageAllocHandle desc, size_t offs)
+{
+ struct nvos_pagemap *pm = (struct nvos_pagemap *)desc;
+ size_t index;
+
+ if (unlikely(!pm)) return (NvOsPhysAddr)0;
+
+ index = offs >> PAGE_SHIFT;
+ offs &= (PAGE_SIZE - 1);
+
+ return (NvOsPhysAddr)(page_to_phys(pm->pages[index]) + offs);
+}
+
+
+void NvOsPageUnmap(NvOsPageAllocHandle desc, void *ptr, size_t size)
+{
+ return;
+}
+
+NvError NvOsPageAlloc(size_t size, NvOsMemAttribute attrib,
+ NvOsPageFlags flags, NvU32 protect, NvOsPageAllocHandle *desc)
+{
+ struct nvos_pagemap *pm;
+ pgprot_t prot = pgprot_kernel;
+ size += PAGE_SIZE-1;
+ size >>= PAGE_SHIFT;
+
+ /* writeback is implemented as inner-cacheable only, since these
+ * allocators are only used to allocate buffers for DMA-driven
+ * clients, and the cost of L2 maintenance makes outer cacheability
+ * a net performance loss more often than not */
+ if (attrib == NvOsMemAttribute_WriteBack)
+ prot = pgprot_inner_writeback(prot);
+ else
+ prot = pgprot_writecombine(prot);
+
+ pm = nv_alloc_pages(size, prot, (flags==NvOsPageFlags_Contiguous), 1);
+
+ if (!pm) return NvError_InsufficientMemory;
+
+ *desc = (NvOsPageAllocHandle)pm;
+ return NvSuccess;
+}
+
+void NvOsPageFree(NvOsPageAllocHandle desc)
+{
+ struct nvos_pagemap *pm = (struct nvos_pagemap *)desc;
+
+ if (pm) nv_free_pages(pm);
+}
+
+
+NvError NvOsPageLock(void *ptr, size_t size, NvU32 protect,
+ NvOsPageAllocHandle *descriptor)
+{
+ return NvError_NotImplemented;
+}
+
+NvError NvOsPageMapIntoPtr(NvOsPageAllocHandle desc, void *ptr,
+ size_t offset, size_t size)
+{
+ return NvError_NotImplemented;
+}
« no previous file with comments | « arch/arm/mach-tegra/nv/nvos/nvos_exports.c ('k') | arch/arm/mach-tegra/nv/nvos/nvustring.c » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698