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/e81548a087d0
branches:  trunk
changeset: 331878:e81548a087d0
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 f60669589d7d -r e81548a087d0 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