summaryrefslogtreecommitdiffstats
path: root/sys/arm/arm/devmap.c
diff options
context:
space:
mode:
Diffstat (limited to 'sys/arm/arm/devmap.c')
-rw-r--r--sys/arm/arm/devmap.c174
1 files changed, 174 insertions, 0 deletions
diff --git a/sys/arm/arm/devmap.c b/sys/arm/arm/devmap.c
new file mode 100644
index 0000000..a8819bd
--- /dev/null
+++ b/sys/arm/arm/devmap.c
@@ -0,0 +1,174 @@
+/*-
+ * Copyright (c) 2013 Ian Lepore <ian@freebsd.org>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+/*
+ * Routines for mapping device memory.
+ */
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <vm/vm.h>
+#include <vm/vm_extern.h>
+#include <vm/pmap.h>
+#include <machine/devmap.h>
+
+static const struct arm_devmap_entry *devmap_table;
+
+/*
+ * Register the given table as the one to use in arm_devmap_bootstrap().
+ */
+void
+arm_devmap_register_table(const struct arm_devmap_entry *table)
+{
+
+ devmap_table = table;
+}
+
+/*
+ * Map all of the static regions in the devmap table, and remember the devmap
+ * table so the mapdev, ptov, and vtop functions can do lookups later.
+ *
+ * If a non-NULL table pointer is given it is used unconditionally, otherwise
+ * the previously-registered table is used. This smooths transition from legacy
+ * code that fills in a local table then calls this function passing that table,
+ * and newer code that uses arm_devmap_register_table() in platform-specific
+ * code, then lets the common initarm() call this function with a NULL pointer.
+ */
+void
+arm_devmap_bootstrap(vm_offset_t l1pt, const struct arm_devmap_entry *table)
+{
+ const struct arm_devmap_entry *pd;
+
+ /*
+ * If given a table pointer, use it, else ensure a table was previously
+ * registered. This happens early in boot, and there's a good chance
+ * the panic message won't be seen, but there's not much we can do.
+ */
+ if (table != NULL)
+ devmap_table = table;
+ else if (devmap_table == NULL)
+ panic("arm_devmap_bootstrap: No devmap table registered.");
+
+ for (pd = devmap_table; pd->pd_size != 0; ++pd) {
+ pmap_map_chunk(l1pt, pd->pd_va, pd->pd_pa, pd->pd_size,
+ pd->pd_prot,pd->pd_cache);
+ }
+}
+
+/*
+ * Look up the given physical address in the static mapping data and return the
+ * corresponding virtual address, or NULL if not found.
+ */
+void *
+arm_devmap_ptov(vm_paddr_t pa, vm_size_t size)
+{
+ const struct arm_devmap_entry *pd;
+
+ if (devmap_table == NULL)
+ return (NULL);
+
+ for (pd = devmap_table; pd->pd_size != 0; ++pd) {
+ if (pa >= pd->pd_pa && pa + size <= pd->pd_pa + pd->pd_size)
+ return ((void *)(pd->pd_va + (pa - pd->pd_pa)));
+ }
+
+ return (NULL);
+}
+
+/*
+ * Look up the given virtual address in the static mapping data and return the
+ * corresponding physical address, or DEVMAP_PADDR_NOTFOUND if not found.
+ */
+vm_paddr_t
+arm_devmap_vtop(void * vpva, vm_size_t size)
+{
+ const struct arm_devmap_entry *pd;
+ vm_offset_t va;
+
+ if (devmap_table == NULL)
+ return (DEVMAP_PADDR_NOTFOUND);
+
+ va = (vm_offset_t)vpva;
+ for (pd = devmap_table; pd->pd_size != 0; ++pd) {
+ if (va >= pd->pd_va && va + size <= pd->pd_va + pd->pd_size)
+ return ((vm_paddr_t)(pd->pd_pa + (va - pd->pd_va)));
+ }
+
+ return (DEVMAP_PADDR_NOTFOUND);
+}
+
+/*
+ * Map a set of physical memory pages into the kernel virtual address space.
+ * Return a pointer to where it is mapped. This routine is intended to be used
+ * for mapping device memory, NOT real memory.
+ */
+void *
+pmap_mapdev(vm_offset_t pa, vm_size_t size)
+{
+ vm_offset_t va, tmpva, offset;
+
+ offset = pa & PAGE_MASK;
+ pa = trunc_page(pa);
+ size = round_page(size + offset);
+
+ va = kva_alloc(size);
+ if (!va)
+ panic("pmap_mapdev: Couldn't alloc kernel virtual memory");
+
+ for (tmpva = va; size > 0;) {
+ pmap_kenter_device(tmpva, pa);
+ size -= PAGE_SIZE;
+ tmpva += PAGE_SIZE;
+ pa += PAGE_SIZE;
+ }
+
+ return ((void *)(va + offset));
+}
+
+/*
+ * Unmap device memory and free the kva space.
+ */
+void
+pmap_unmapdev(vm_offset_t va, vm_size_t size)
+{
+ vm_offset_t tmpva, offset;
+
+ offset = va & PAGE_MASK;
+ va = trunc_page(va);
+ size = round_page(size + offset);
+
+ for (tmpva = va; size > 0;) {
+ pmap_kremove(tmpva);
+ size -= PAGE_SIZE;
+ tmpva += PAGE_SIZE;
+ }
+
+ kva_free(va, size);
+}
+
OpenPOWER on IntegriCloud