Source-Changes-HG archive
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index][Old Index]
[src/trunk]: src/sys/external/bsd/drm2/include/linux Make Linux io_mapping ac...
details: https://anonhg.NetBSD.org/src/rev/e12d2ea5cb0f
branches: trunk
changeset: 802020:e12d2ea5cb0f
user: riastradh <riastradh%NetBSD.org@localhost>
date: Thu Aug 28 13:45:59 2014 +0000
description:
Make Linux io_mapping actually work.
Can't use bus_space_map/bus_space_unmap in interrupt context, where
Linux uses this io_mapping abstraction. Instead, do uvm_km_alloc up
front and then use bus_space_mmap/pmap_kenter_pa to map it.
XXX Should bus_space_reserve the region (but that's x86-only for now).
XXX Should use direct map if possible.
XXX Should set an MTRR WC too in case of direct map or no PAT.
diffstat:
sys/external/bsd/drm2/include/linux/io-mapping.h | 99 ++++++++++++++++-------
1 files changed, 67 insertions(+), 32 deletions(-)
diffs (161 lines):
diff -r aa0fd4145f91 -r e12d2ea5cb0f sys/external/bsd/drm2/include/linux/io-mapping.h
--- a/sys/external/bsd/drm2/include/linux/io-mapping.h Thu Aug 28 12:23:29 2014 +0000
+++ b/sys/external/bsd/drm2/include/linux/io-mapping.h Thu Aug 28 13:45:59 2014 +0000
@@ -1,4 +1,4 @@
-/* $NetBSD: io-mapping.h,v 1.2 2014/03/18 18:20:43 riastradh Exp $ */
+/* $NetBSD: io-mapping.h,v 1.3 2014/08/28 13:45:59 riastradh Exp $ */
/*-
* Copyright (c) 2013 The NetBSD Foundation, Inc.
@@ -32,40 +32,58 @@
#ifndef _LINUX_IO_MAPPING_H_
#define _LINUX_IO_MAPPING_H_
+#include <sys/param.h>
#include <sys/bus.h>
#include <sys/kmem.h>
#include <sys/systm.h>
+#include <uvm/uvm_extern.h>
+
struct io_mapping {
bus_space_tag_t diom_bst;
bus_addr_t diom_addr;
bus_size_t diom_size;
- int diom_flags;
- bus_space_handle_t diom_bsh;
- void *diom_vaddr;
+ vaddr_t diom_va;
+ bool diom_mapped;
};
static inline struct io_mapping *
bus_space_io_mapping_create_wc(bus_space_tag_t bst, bus_addr_t addr,
bus_size_t size)
{
- struct io_mapping *const mapping = kmem_alloc(sizeof(*mapping),
- KM_SLEEP);
+ struct io_mapping *mapping;
+ bus_size_t offset;
+
+ KASSERT(PAGE_SIZE <= size);
+ KASSERT(0 == (size & (PAGE_SIZE - 1)));
+ KASSERT(__type_fit(off_t, size));
+
+ /*
+ * XXX For x86: Reserve the region (bus_space_reserve) and set
+ * an MTRR to make it write-combining. Doesn't matter if we
+ * have PAT and we use pmap_kenter_pa, but matters if we don't
+ * have PAT or if we later make this use direct map.
+ */
+
+ /* Make sure the region is mappable. */
+ for (offset = 0; offset < size; offset += PAGE_SIZE) {
+ if (bus_space_mmap(bst, addr, offset, PROT_READ|PROT_WRITE,
+ BUS_SPACE_MAP_LINEAR|BUS_SPACE_MAP_PREFETCHABLE)
+ == (paddr_t)-1)
+ return NULL;
+ }
+
+ /* Create a mapping record. */
+ mapping = kmem_alloc(sizeof(*mapping), KM_SLEEP);
mapping->diom_bst = bst;
mapping->diom_addr = addr;
mapping->diom_size = size;
- mapping->diom_flags = 0;
- mapping->diom_flags |= BUS_SPACE_MAP_LINEAR;
- mapping->diom_flags |= BUS_SPACE_MAP_PREFETCHABLE;
- mapping->diom_vaddr = NULL;
+ mapping->diom_mapped = false;
- bus_space_handle_t bsh;
- if (bus_space_map(mapping->diom_bst, addr, PAGE_SIZE,
- mapping->diom_flags, &bsh)) {
- kmem_free(mapping, sizeof(*mapping));
- return NULL;
- }
- bus_space_unmap(mapping->diom_bst, bsh, PAGE_SIZE);
+ /* Allocate kva for one page. */
+ mapping->diom_va = uvm_km_alloc(kernel_map, PAGE_SIZE, PAGE_SIZE,
+ UVM_KMF_VAONLY | UVM_KMF_WAITVA);
+ KASSERT(mapping->diom_va != 0);
return mapping;
}
@@ -74,44 +92,61 @@
io_mapping_free(struct io_mapping *mapping)
{
- KASSERT(mapping->diom_vaddr == NULL);
+ KASSERT(!mapping->diom_mapped);
+
+ uvm_km_free(kernel_map, mapping->diom_va, PAGE_SIZE, UVM_KMF_VAONLY);
kmem_free(mapping, sizeof(*mapping));
}
static inline void *
io_mapping_map_wc(struct io_mapping *mapping, unsigned long offset)
{
+ paddr_t cookie;
- KASSERT(mapping->diom_vaddr == NULL);
- KASSERT(ISSET(mapping->diom_flags, BUS_SPACE_MAP_LINEAR));
- if (bus_space_map(mapping->diom_bst, (mapping->diom_addr + offset),
- PAGE_SIZE, mapping->diom_flags, &mapping->diom_bsh))
- panic("Unable to make I/O mapping!"); /* XXX */
- mapping->diom_vaddr = bus_space_vaddr(mapping->diom_bst,
- mapping->diom_bsh);
+ KASSERT(0 == (offset & (PAGE_SIZE - 1)));
+ KASSERT(PAGE_SIZE <= mapping->diom_size);
+ KASSERT(offset <= (mapping->diom_size - PAGE_SIZE));
+ KASSERT(__type_fit(off_t, offset));
+ KASSERT(!mapping->diom_mapped);
- return mapping->diom_vaddr;
+ cookie = bus_space_mmap(mapping->diom_bst, mapping->diom_addr, offset,
+ PROT_READ|PROT_WRITE,
+ BUS_SPACE_MAP_LINEAR|BUS_SPACE_MAP_PREFETCHABLE);
+ KASSERT(cookie != (paddr_t)-1);
+
+ pmap_kenter_pa(mapping->diom_va, pmap_phys_address(cookie),
+ PROT_READ|PROT_WRITE, pmap_mmap_flags(cookie));
+ pmap_update(pmap_kernel());
+
+ mapping->diom_mapped = true;
+ return (void *)mapping->diom_va;
}
static inline void
-io_mapping_unmap(struct io_mapping *mapping, void *vaddr __unused)
+io_mapping_unmap(struct io_mapping *mapping, void *ptr __diagused)
{
- KASSERT(mapping->diom_vaddr == vaddr);
- bus_space_unmap(mapping->diom_bst, mapping->diom_bsh, PAGE_SIZE);
- mapping->diom_vaddr = NULL;
+ KASSERT(mapping->diom_mapped);
+ KASSERT(mapping->diom_va == (vaddr_t)ptr);
+
+ pmap_kremove(mapping->diom_va, PAGE_SIZE);
+ pmap_update(pmap_kernel());
+
+ mapping->diom_mapped = false;
}
static inline void *
io_mapping_map_atomic_wc(struct io_mapping *mapping, unsigned long offset)
{
+
return io_mapping_map_wc(mapping, offset);
}
static inline void
-io_mapping_unmap_atomic(struct io_mapping *mapping, void *vaddr __unused)
+io_mapping_unmap_atomic(struct io_mapping *mapping, void *ptr)
{
- return io_mapping_unmap(mapping, vaddr);
+
+ return io_mapping_unmap(mapping, ptr);
}
#endif /* _LINUX_IO_MAPPING_H_ */
Home |
Main Index |
Thread Index |
Old Index