Module Name:    src
Committed By:   snj
Date:           Sun Sep 21 18:01:28 UTC 2014

Modified Files:
        src/sys/external/bsd/drm2/include/linux [netbsd-7]: io-mapping.h

Log Message:
Pull up following revision(s) (requested by riastradh in ticket #98):
        sys/external/bsd/drm2/include/linux/io-mapping.h: revision 1.3
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.


To generate a diff of this commit:
cvs rdiff -u -r1.2 -r1.2.8.1 \
    src/sys/external/bsd/drm2/include/linux/io-mapping.h

Please note that diffs are not public domain; they are subject to the
copyright notices on the relevant files.

Modified files:

Index: src/sys/external/bsd/drm2/include/linux/io-mapping.h
diff -u src/sys/external/bsd/drm2/include/linux/io-mapping.h:1.2 src/sys/external/bsd/drm2/include/linux/io-mapping.h:1.2.8.1
--- src/sys/external/bsd/drm2/include/linux/io-mapping.h:1.2	Tue Mar 18 18:20:43 2014
+++ src/sys/external/bsd/drm2/include/linux/io-mapping.h	Sun Sep 21 18:01:28 2014
@@ -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.2.8.1 2014/09/21 18:01:28 snj 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;
-
-	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);
+	mapping->diom_mapped = false;
+
+	/* 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 @@ static inline void
 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);
+
+	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());
 
-	return mapping->diom_vaddr;
+	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_ */

Reply via email to