Module Name:    src
Committed By:   riastradh
Date:           Sun Sep  8 16:16:37 UTC 2013

Modified Files:
        src/sys/external/bsd/drm2/include/linux [riastradh-drm2]: highmem.h
        src/sys/external/bsd/drm2/linux [riastradh-drm2]: linux_kmap.c

Log Message:
Fix kunmap: unlike kunmap_atomic, it takes a page, not a vaddr.

Unmapping the vaddr where the struct vm_page is stored makes for a
rather confusing state of affairs!


To generate a diff of this commit:
cvs rdiff -u -r1.1.2.3 -r1.1.2.4 \
    src/sys/external/bsd/drm2/include/linux/highmem.h
cvs rdiff -u -r1.1.2.2 -r1.1.2.3 src/sys/external/bsd/drm2/linux/linux_kmap.c

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/highmem.h
diff -u src/sys/external/bsd/drm2/include/linux/highmem.h:1.1.2.3 src/sys/external/bsd/drm2/include/linux/highmem.h:1.1.2.4
--- src/sys/external/bsd/drm2/include/linux/highmem.h:1.1.2.3	Wed Jul 24 03:46:22 2013
+++ src/sys/external/bsd/drm2/include/linux/highmem.h	Sun Sep  8 16:16:37 2013
@@ -1,4 +1,4 @@
-/*	$NetBSD: highmem.h,v 1.1.2.3 2013/07/24 03:46:22 riastradh Exp $	*/
+/*	$NetBSD: highmem.h,v 1.1.2.4 2013/09/08 16:16:37 riastradh Exp $	*/
 
 /*-
  * Copyright (c) 2013 The NetBSD Foundation, Inc.
@@ -51,6 +51,6 @@ void *	kmap_atomic(struct page *);
 void	kunmap_atomic(void *);
 
 void *	kmap(struct page *);
-void	kunmap(void *);
+void	kunmap(struct page *);
 
 #endif  /* _LINUX_HIGHMEM_H_ */

Index: src/sys/external/bsd/drm2/linux/linux_kmap.c
diff -u src/sys/external/bsd/drm2/linux/linux_kmap.c:1.1.2.2 src/sys/external/bsd/drm2/linux/linux_kmap.c:1.1.2.3
--- src/sys/external/bsd/drm2/linux/linux_kmap.c:1.1.2.2	Wed Jul 24 03:46:22 2013
+++ src/sys/external/bsd/drm2/linux/linux_kmap.c	Sun Sep  8 16:16:37 2013
@@ -1,4 +1,4 @@
-/*	$NetBSD: linux_kmap.c,v 1.1.2.2 2013/07/24 03:46:22 riastradh Exp $	*/
+/*	$NetBSD: linux_kmap.c,v 1.1.2.3 2013/09/08 16:16:37 riastradh Exp $	*/
 
 /*-
  * Copyright (c) 2013 The NetBSD Foundation, Inc.
@@ -30,10 +30,12 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: linux_kmap.c,v 1.1.2.2 2013/07/24 03:46:22 riastradh Exp $");
+__KERNEL_RCSID(0, "$NetBSD: linux_kmap.c,v 1.1.2.3 2013/09/08 16:16:37 riastradh Exp $");
 
 #include <sys/types.h>
+#include <sys/kmem.h>
 #include <sys/mutex.h>
+#include <sys/rbtree.h>
 
 #include <uvm/uvm_extern.h>
 
@@ -55,6 +57,51 @@ __KERNEL_RCSID(0, "$NetBSD: linux_kmap.c
 static kmutex_t linux_kmap_atomic_lock;
 static vaddr_t linux_kmap_atomic_vaddr;
 
+static kmutex_t linux_kmap_lock;
+static rb_tree_t linux_kmap_entries;
+
+struct linux_kmap_entry {
+	paddr_t		lke_paddr;
+	vaddr_t		lke_vaddr;
+	unsigned int	lke_refcnt;
+	rb_node_t	lke_node;
+};
+
+static int
+lke_compare_nodes(void *ctx __unused, const void *an, const void *bn)
+{
+	const struct linux_kmap_entry *const a = an;
+	const struct linux_kmap_entry *const b = bn;
+
+	if (a->lke_paddr < b->lke_paddr)
+		return -1;
+	else if (a->lke_paddr > b->lke_paddr)
+		return +1;
+	else
+		return 0;
+}
+
+static int
+lke_compare_key(void *ctx __unused, const void *node, const void *key)
+{
+	const struct linux_kmap_entry *const lke = node;
+	const paddr_t *const paddrp = key;
+
+	if (lke->lke_paddr < *paddrp)
+		return -1;
+	else if (lke->lke_paddr > *paddrp)
+		return +1;
+	else
+		return 0;
+}
+
+static const rb_tree_ops_t linux_kmap_entry_ops = {
+	.rbto_compare_nodes = &lke_compare_nodes,
+	.rbto_compare_key = &lke_compare_key,
+	.rbto_node_offset = offsetof(struct linux_kmap_entry, lke_node),
+	.rbto_context = NULL,
+};
+
 int
 linux_kmap_init(void)
 {
@@ -68,6 +115,9 @@ linux_kmap_init(void)
 	KASSERT(linux_kmap_atomic_vaddr != 0);
 	KASSERT(!pmap_extract(pmap_kernel(), linux_kmap_atomic_vaddr, NULL));
 
+	mutex_init(&linux_kmap_lock, MUTEX_DEFAULT, IPL_VM);
+	rb_tree_init(&linux_kmap_entries, &linux_kmap_entry_ops);
+
 	return 0;
 }
 
@@ -75,6 +125,13 @@ void
 linux_kmap_fini(void)
 {
 
+	KASSERT(rb_tree_iterate(&linux_kmap_entries, NULL, RB_DIR_RIGHT) ==
+	    NULL);
+#if 0				/* XXX no rb_tree_destroy*/
+	rb_tree_destroy(&linux_kmap_entries);
+#endif
+	mutex_destroy(&linux_kmap_lock);
+
 	KASSERT(linux_kmap_atomic_vaddr != 0);
 	KASSERT(!pmap_extract(pmap_kernel(), linux_kmap_atomic_vaddr, NULL));
 
@@ -121,16 +178,25 @@ kunmap_atomic(void *addr)
 void *
 kmap(struct page *page)
 {
-	int s;
-
+	const paddr_t paddr = VM_PAGE_TO_PHYS(&page->p_vmp);
 	const vaddr_t vaddr = uvm_km_alloc(kernel_map, PAGE_SIZE, 0,
 	    (UVM_KMF_VAONLY | UVM_KMF_WAITVA));
 	KASSERT(vaddr != 0);
 
-	s = splvm();
+	struct linux_kmap_entry *const lke = kmem_alloc(sizeof(*lke),
+	    KM_SLEEP);
+	lke->lke_paddr = paddr;
+	lke->lke_vaddr = vaddr;
+
+	mutex_spin_enter(&linux_kmap_lock);
+	struct linux_kmap_entry *const collision __unused =
+	    rb_tree_insert_node(&linux_kmap_entries, lke);
+	KASSERT(collision == lke);
+	mutex_spin_exit(&linux_kmap_lock);
+
+	const int s = splvm();
 
 	KASSERT(!pmap_extract(pmap_kernel(), vaddr, NULL));
-	const paddr_t paddr = uvm_vm_page_to_phys(&page->p_vmp);
 	const int prot = (VM_PROT_READ | VM_PROT_WRITE);
 	const int flags = 0;
 	pmap_kenter_pa(vaddr, paddr, prot, flags);
@@ -142,12 +208,21 @@ kmap(struct page *page)
 }
 
 void
-kunmap(void *addr)
+kunmap(struct page *page)
 {
-	const vaddr_t vaddr = (vaddr_t)addr;
-	int s;
+	const paddr_t paddr = VM_PAGE_TO_PHYS(&page->p_vmp);
+
+	mutex_spin_enter(&linux_kmap_lock);
+	struct linux_kmap_entry *const lke =
+	    rb_tree_find_node(&linux_kmap_entries, &paddr);
+	KASSERT(lke != NULL);
+	rb_tree_remove_node(&linux_kmap_entries, lke);
+	mutex_spin_exit(&linux_kmap_lock);
+
+	const vaddr_t vaddr = lke->lke_vaddr;
+	kmem_free(lke, sizeof(*lke));
 
-	s = splvm();
+	const int s = splvm();
 
 	KASSERT(pmap_extract(pmap_kernel(), vaddr, NULL));
 

Reply via email to