Module Name:    src
Committed By:   snj
Date:           Thu Apr 23 07:31:17 UTC 2015

Modified Files:
        src/sys/arch/x86/include [netbsd-7]: pmap.h
        src/sys/arch/x86/x86 [netbsd-7]: pmap.c
        src/sys/dev/pci [netbsd-7]: agp_amd64.c agp_i810.c
        src/sys/external/bsd/drm2/dist/drm/i915 [netbsd-7]: i915_dma.c
            i915_gem.c
        src/sys/external/bsd/drm2/dist/drm/nouveau [netbsd-7]: nouveau_agp.c
            nouveau_ttm.c
        src/sys/external/bsd/drm2/dist/drm/radeon [netbsd-7]: atombios_crtc.c
            radeon_agp.c radeon_display.c radeon_legacy_crtc.c radeon_object.c
            radeon_ttm.c
        src/sys/external/bsd/drm2/dist/drm/ttm [netbsd-7]: ttm_bo.c
            ttm_bo_util.c
        src/sys/external/bsd/drm2/i915drm [netbsd-7]: intelfb.c
        src/sys/external/bsd/drm2/include/drm [netbsd-7]: drm_wait_netbsd.h
        src/sys/external/bsd/drm2/include/linux [netbsd-7]: mm.h pci.h
        src/sys/external/bsd/drm2/nouveau [netbsd-7]: nouveaufb.c
        src/sys/external/bsd/drm2/radeon [netbsd-7]: radeon_pci.c
        src/sys/uvm [netbsd-7]: uvm_init.c

Log Message:
Pull up following revision(s) (requested by mrg in ticket #718):
        sys/arch/x86/include/pmap.h: revision 1.56
        sys/arch/x86/x86/pmap.c: revision 1.188
        sys/dev/pci/agp_amd64.c: revision 1.8
        sys/dev/pci/agp_i810.c: revision 1.118
        sys/external/bsd/drm2/dist/drm/i915/i915_dma.c: revision 1.16
        sys/external/bsd/drm2/dist/drm/i915/i915_gem.c: revision 1.29
        sys/external/bsd/drm2/dist/drm/nouveau/nouveau_agp.c: revision 1.3
        sys/external/bsd/drm2/dist/drm/nouveau/nouveau_ttm.c: revision 1.4
        sys/external/bsd/drm2/dist/drm/radeon/atombios_crtc.c: revision 1.3
        sys/external/bsd/drm2/dist/drm/radeon/radeon_agp.c: revision 1.3
        sys/external/bsd/drm2/dist/drm/radeon/radeon_display.c: revision 1.3
        sys/external/bsd/drm2/dist/drm/radeon/radeon_legacy_crtc.c: revision 1.2
        sys/external/bsd/drm2/dist/drm/radeon/radeon_object.c: revision 1.3
        sys/external/bsd/drm2/dist/drm/radeon/radeon_ttm.c: revision 1.7
        sys/external/bsd/drm2/dist/drm/ttm/ttm_bo.c: revisions 1.7-1.10
        sys/external/bsd/drm2/dist/drm/ttm/ttm_bo_util.c: revision 1.5
        sys/external/bsd/drm2/i915drm/intelfb.c: revision 1.13
        sys/external/bsd/drm2/include/drm/drm_wait_netbsd.h: revisions 1.12, 
1.13
        sys/external/bsd/drm2/include/linux/mm.h: revision 1.5
        sys/external/bsd/drm2/include/linux/pci.h: revisions 1.16, 1.17
        sys/external/bsd/drm2/nouveau/nouveaufb.c: revision 1.2
        sys/external/bsd/drm2/radeon/radeon_pci.c: revisions 1.8, 1.9
        sys/uvm/uvm_init.c: revision 1.46
Hack against the blank console problem:
Leave the CLUT alone on ancient cards. At least this leaves us with a
semi working console (red and blue are flipped). Leave an example of what
seems to be happening but disable it because colors are better than 444 bit
greyscale.
--
Initialize P->V tracking for unmanaged device pages in uvm_init.

Conditional on __HAVE_PMAP_PV_TRACK until we add it to all pmaps.

MI part of pmap_pv(9) change proposed on tech-kern:

https://mail-index.netbsd.org/tech-kern/2015/03/26/msg018561.html
--
Implement pmap_pv(9) for x86 for P->V tracking of unmanaged pages.

Proposed on tech-kern with no objections:

https://mail-index.netbsd.org/tech-kern/2015/03/26/msg018561.html
--
Use pmap_pv(9) to remove mappings of Intel graphics aperture pages.

Proposed on tech-kern with no objections:

https://mail-index.netbsd.org/tech-kern/2015/03/26/msg018561.html

Further background at:

https://mail-index.netbsd.org/tech-kern/2014/07/23/msg017392.html
--
Use pmap_pv(9) to remove mappings of device pages in TTM.

Adapt nouveau and radeon to do pmap_pv_track for their device pages.

Proposed on tech-kern with no objections:

https://mail-index.netbsd.org/tech-kern/2015/03/26/msg018561.html

Further background at:

https://mail-index.netbsd.org/tech-kern/2014/07/23/msg017392.html
--
Fix error branches in agp_amd64.c.

- agp_generic_detach always.
- Free asc if it was allocated.  (Found by Brainy, noted by maxv@.)
- Free the GATT if it was allocated.
--
pmf_device_register returns false on failure, not true
--
In DRM_SPIN_WAIT_ON, don't stop after waiting only one tick.

Continue the loop to recheck the condition and count the whole
duration.
--
Don't use the video BIOS memory as an i915 flush page!
--
Don't let anyone else allocate the video BIOS either.
--
Missed a zero: it's 0x100000, not 0x10000.
--
Don't reserve if atomic -- caller must have pre-pinned the buffer.
--
Don't reserve if atomic -- caller must have pre-pinned the buffer.
--
almost add radeondrmkms suspend/resume support.  it unfortunately doesn't work.
--
Need the page's uvm object lock to do pmap_page_protect.
--
Use KASSERTMSG to show bad base/offset.
--
KASSERT about page-alignment on initialization too.
--
Don't break when hardclock_ticks wraps around.

Since we now only count time spent in wait, rather than determining
the end time and checking whether we've passed it, timeouts might be
marginally longer in effect.  Unlikely to be an issue.
--
Remove broken drm2 vm_mmap stub.  Can't possibly have ever worked.
--
apply some of the additional changes from Arto Huusko in PR#49645:
- call pmf_device_deregister on detach.

i've kept the "resume = true" for radeon_resume_kms() call as it
seems to work for me (indeed, code inspection shows it is unused
on netbsd :-)

my old nforce4 box that can resume old drm (or could, last i tried
several years ago) while X and GL apps were running, can at least
survive a resume if X hasn't started.  my one attempt so far with
X exited, but having run, did not work.
--
First attempt to make ttm_buffer_object_transfer less bogus.
--
Make sure mem.bus.is_iomem is initialized.  PR 49833


To generate a diff of this commit:
cvs rdiff -u -r1.55 -r1.55.4.1 src/sys/arch/x86/include/pmap.h
cvs rdiff -u -r1.183.2.1 -r1.183.2.2 src/sys/arch/x86/x86/pmap.c
cvs rdiff -u -r1.7 -r1.7.14.1 src/sys/dev/pci/agp_amd64.c
cvs rdiff -u -r1.112.2.2 -r1.112.2.3 src/sys/dev/pci/agp_i810.c
cvs rdiff -u -r1.10.2.3 -r1.10.2.4 \
    src/sys/external/bsd/drm2/dist/drm/i915/i915_dma.c
cvs rdiff -u -r1.14.2.7 -r1.14.2.8 \
    src/sys/external/bsd/drm2/dist/drm/i915/i915_gem.c
cvs rdiff -u -r1.2 -r1.2.4.1 \
    src/sys/external/bsd/drm2/dist/drm/nouveau/nouveau_agp.c
cvs rdiff -u -r1.2.4.1 -r1.2.4.2 \
    src/sys/external/bsd/drm2/dist/drm/nouveau/nouveau_ttm.c
cvs rdiff -u -r1.2 -r1.2.4.1 \
    src/sys/external/bsd/drm2/dist/drm/radeon/atombios_crtc.c \
    src/sys/external/bsd/drm2/dist/drm/radeon/radeon_agp.c \
    src/sys/external/bsd/drm2/dist/drm/radeon/radeon_display.c \
    src/sys/external/bsd/drm2/dist/drm/radeon/radeon_object.c
cvs rdiff -u -r1.1.1.1 -r1.1.1.1.4.1 \
    src/sys/external/bsd/drm2/dist/drm/radeon/radeon_legacy_crtc.c
cvs rdiff -u -r1.5.4.1 -r1.5.4.2 \
    src/sys/external/bsd/drm2/dist/drm/radeon/radeon_ttm.c
cvs rdiff -u -r1.4.2.1 -r1.4.2.2 \
    src/sys/external/bsd/drm2/dist/drm/ttm/ttm_bo.c
cvs rdiff -u -r1.4 -r1.4.2.1 \
    src/sys/external/bsd/drm2/dist/drm/ttm/ttm_bo_util.c
cvs rdiff -u -r1.9.4.2 -r1.9.4.3 src/sys/external/bsd/drm2/i915drm/intelfb.c
cvs rdiff -u -r1.4.2.3 -r1.4.2.4 \
    src/sys/external/bsd/drm2/include/drm/drm_wait_netbsd.h
cvs rdiff -u -r1.3.2.1 -r1.3.2.2 src/sys/external/bsd/drm2/include/linux/mm.h
cvs rdiff -u -r1.7.2.5 -r1.7.2.6 \
    src/sys/external/bsd/drm2/include/linux/pci.h
cvs rdiff -u -r1.1.2.2 -r1.1.2.3 \
    src/sys/external/bsd/drm2/nouveau/nouveaufb.c
cvs rdiff -u -r1.4.4.1 -r1.4.4.2 \
    src/sys/external/bsd/drm2/radeon/radeon_pci.c
cvs rdiff -u -r1.45 -r1.45.12.1 src/sys/uvm/uvm_init.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/arch/x86/include/pmap.h
diff -u src/sys/arch/x86/include/pmap.h:1.55 src/sys/arch/x86/include/pmap.h:1.55.4.1
--- src/sys/arch/x86/include/pmap.h:1.55	Thu Oct 17 20:59:16 2013
+++ src/sys/arch/x86/include/pmap.h	Thu Apr 23 07:31:16 2015
@@ -1,4 +1,4 @@
-/*	$NetBSD: pmap.h,v 1.55 2013/10/17 20:59:16 christos Exp $	*/
+/*	$NetBSD: pmap.h,v 1.55.4.1 2015/04/23 07:31:16 snj Exp $	*/
 
 /*
  * Copyright (c) 1997 Charles D. Cranor and Washington University.
@@ -243,8 +243,10 @@ extern long nkptp[PTP_LEVELS];
 void		pmap_activate(struct lwp *);
 void		pmap_bootstrap(vaddr_t);
 bool		pmap_clear_attrs(struct vm_page *, unsigned);
+bool		pmap_pv_clear_attrs(paddr_t, unsigned);
 void		pmap_deactivate(struct lwp *);
-void		pmap_page_remove (struct vm_page *);
+void		pmap_page_remove(struct vm_page *);
+void		pmap_pv_remove(paddr_t);
 void		pmap_remove(struct pmap *, vaddr_t, vaddr_t);
 bool		pmap_test_attrs(struct vm_page *, unsigned);
 void		pmap_write_protect(struct pmap *, vaddr_t, vaddr_t, vm_prot_t);
@@ -258,6 +260,11 @@ void		pmap_emap_enter(vaddr_t, paddr_t, 
 void		pmap_emap_remove(vaddr_t, vsize_t);
 void		pmap_emap_sync(bool);
 
+#define	__HAVE_PMAP_PV_TRACK	1
+void		pmap_pv_init(void);
+void		pmap_pv_track(paddr_t, psize_t);
+void		pmap_pv_untrack(paddr_t, psize_t);
+
 void		pmap_map_ptes(struct pmap *, struct pmap **, pd_entry_t **,
 		    pd_entry_t * const **);
 void		pmap_unmap_ptes(struct pmap *, struct pmap *);
@@ -359,6 +366,23 @@ pmap_page_protect(struct vm_page *pg, vm
 }
 
 /*
+ * pmap_pv_protect: change the protection of all recorded mappings
+ *	of an unmanaged page
+ */
+
+__inline static void __unused
+pmap_pv_protect(paddr_t pa, vm_prot_t prot)
+{
+	if ((prot & VM_PROT_WRITE) == 0) {
+		if (prot & (VM_PROT_READ|VM_PROT_EXECUTE)) {
+			(void) pmap_pv_clear_attrs(pa, PG_RW);
+		} else {
+			pmap_pv_remove(pa);
+		}
+	}
+}
+
+/*
  * pmap_protect: change the protection of pages in a pmap
  *
  * => this function is a frontend for pmap_remove/pmap_write_protect

Index: src/sys/arch/x86/x86/pmap.c
diff -u src/sys/arch/x86/x86/pmap.c:1.183.2.1 src/sys/arch/x86/x86/pmap.c:1.183.2.2
--- src/sys/arch/x86/x86/pmap.c:1.183.2.1	Tue Oct 14 07:37:37 2014
+++ src/sys/arch/x86/x86/pmap.c	Thu Apr 23 07:31:16 2015
@@ -1,4 +1,4 @@
-/*	$NetBSD: pmap.c,v 1.183.2.1 2014/10/14 07:37:37 martin Exp $	*/
+/*	$NetBSD: pmap.c,v 1.183.2.2 2015/04/23 07:31:16 snj Exp $	*/
 
 /*-
  * Copyright (c) 2008, 2010 The NetBSD Foundation, Inc.
@@ -171,7 +171,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: pmap.c,v 1.183.2.1 2014/10/14 07:37:37 martin Exp $");
+__KERNEL_RCSID(0, "$NetBSD: pmap.c,v 1.183.2.2 2015/04/23 07:31:16 snj Exp $");
 
 #include "opt_user_ldt.h"
 #include "opt_lockdebug.h"
@@ -191,6 +191,8 @@ __KERNEL_RCSID(0, "$NetBSD: pmap.c,v 1.1
 #include <sys/intr.h>
 #include <sys/xcall.h>
 #include <sys/kcore.h>
+#include <sys/kmem.h>
+#include <sys/pserialize.h>
 
 #include <uvm/uvm.h>
 
@@ -248,8 +250,10 @@ __KERNEL_RCSID(0, "$NetBSD: pmap.c,v 1.1
  * data structures we use include:
  *
  *  - struct pmap: describes the address space of one thread
+ *  - struct pmap_page: describes one pv-tracked page, without
+ *	necessarily a corresponding vm_page
  *  - struct pv_entry: describes one <PMAP,VA> mapping of a PA
- *  - struct pv_head: there is one pv_head per managed page of
+ *  - struct pv_head: there is one pv_head per pv-tracked page of
  *	physical memory.   the pv_head points to a list of pv_entry
  *	structures which describe all the <PMAP,VA> pairs that this
  *      page is mapped in.    this is critical for page based operations
@@ -303,7 +307,7 @@ __KERNEL_RCSID(0, "$NetBSD: pmap.c,v 1.1
  *
  * - pvh_lock (per pv_head)
  *   this lock protects the pv_entry list which is chained off the
- *   pv_head structure for a specific managed PA.   it is locked
+ *   pv_head structure for a specific pv-tracked PA.   it is locked
  *   when traversing the list (e.g. adding/removing mappings,
  *   syncing R/M bits, etc.)
  *
@@ -459,6 +463,120 @@ pvhash_remove(struct pv_hash_head *hh, s
 }
 
 /*
+ * unmanaged pv-tracked ranges
+ *
+ * This is a linear list for now because the only user are the DRM
+ * graphics drivers, with a single tracked range per device, for the
+ * graphics aperture, so there are expected to be few of them.
+ *
+ * This is used only after the VM system is initialized well enough
+ * that we can use kmem_alloc.
+ */
+
+struct pv_track {
+	paddr_t			pvt_start;
+	psize_t			pvt_size;
+	struct pv_track		*pvt_next;
+	struct pmap_page	pvt_pages[];
+};
+
+static struct {
+	kmutex_t	lock;
+	pserialize_t	psz;
+	struct pv_track	*list;
+} pv_unmanaged __cacheline_aligned;
+
+void
+pmap_pv_init(void)
+{
+
+	mutex_init(&pv_unmanaged.lock, MUTEX_DEFAULT, IPL_VM);
+	pv_unmanaged.psz = pserialize_create();
+	pv_unmanaged.list = NULL;
+}
+
+void
+pmap_pv_track(paddr_t start, psize_t size)
+{
+	struct pv_track *pvt;
+	size_t npages;
+
+	KASSERT(start == trunc_page(start));
+	KASSERT(size == trunc_page(size));
+
+	npages = size >> PAGE_SHIFT;
+	pvt = kmem_zalloc(offsetof(struct pv_track, pvt_pages[npages]),
+	    KM_SLEEP);
+	pvt->pvt_start = start;
+	pvt->pvt_size = size;
+
+	mutex_enter(&pv_unmanaged.lock);
+	pvt->pvt_next = pv_unmanaged.list;
+	membar_producer();
+	pv_unmanaged.list = pvt;
+	mutex_exit(&pv_unmanaged.lock);
+}
+
+void
+pmap_pv_untrack(paddr_t start, psize_t size)
+{
+	struct pv_track **pvtp, *pvt;
+	size_t npages;
+
+	KASSERT(start == trunc_page(start));
+	KASSERT(size == trunc_page(size));
+
+	mutex_enter(&pv_unmanaged.lock);
+	for (pvtp = &pv_unmanaged.list;
+	     (pvt = *pvtp) != NULL;
+	     pvtp = &pvt->pvt_next) {
+		if (pvt->pvt_start != start)
+			continue;
+		if (pvt->pvt_size != size)
+			panic("pmap_pv_untrack: pv-tracking at 0x%"PRIxPADDR
+			    ": 0x%"PRIxPSIZE" bytes, not 0x%"PRIxPSIZE" bytes",
+			    pvt->pvt_start, pvt->pvt_size, size);
+		*pvtp = pvt->pvt_next;
+		pserialize_perform(pv_unmanaged.psz);
+		pvt->pvt_next = NULL;
+		goto out;
+	}
+	panic("pmap_pv_untrack: pages not pv-tracked at 0x%"PRIxPADDR
+	    " (0x%"PRIxPSIZE" bytes)",
+	    start, size);
+out:	mutex_exit(&pv_unmanaged.lock);
+
+	npages = size >> PAGE_SHIFT;
+	kmem_free(pvt, offsetof(struct pv_track, pvt_pages[npages]));
+}
+
+static struct pmap_page *
+pmap_pv_tracked(paddr_t pa)
+{
+	struct pv_track *pvt;
+	size_t pgno;
+	int s;
+
+	KASSERT(pa == trunc_page(pa));
+
+	s = pserialize_read_enter();
+	for (pvt = pv_unmanaged.list; pvt != NULL; pvt = pvt->pvt_next) {
+		membar_datadep_consumer();
+		if ((pvt->pvt_start <= pa) &&
+		    ((pa - pvt->pvt_start) < pvt->pvt_size))
+			break;
+	}
+	pserialize_read_exit(s);
+
+	if (pvt == NULL)
+		return NULL;
+	KASSERT(pvt->pvt_start <= pa);
+	KASSERT((pa - pvt->pvt_start) < pvt->pvt_size);
+	pgno = (pa - pvt->pvt_start) >> PAGE_SHIFT;
+	return &pvt->pvt_pages[pgno];
+}
+
+/*
  * other data structures
  */
 
@@ -3300,27 +3418,30 @@ pmap_remove_pte(struct pmap *pmap, struc
 	 */
 	if ((opte & PG_PVLIST) == 0) {
 #if defined(DIAGNOSTIC) && !defined(DOM0OPS)
-		if (PHYS_TO_VM_PAGE(pmap_pte2pa(opte)) != NULL)
-			panic("pmap_remove_pte: managed page without "
-			      "PG_PVLIST for %#" PRIxVADDR, va);
+		if (PHYS_TO_VM_PAGE(pmap_pte2pa(opte)) != NULL ||
+		    pmap_pv_tracked(pmap_pte2pa(opte)) != NULL)
+			panic("pmap_remove_pte: managed or pv-tracked page"
+			    " without PG_PVLIST for %#"PRIxVADDR, va);
 #endif
 		return true;
 	}
 
-	pg = PHYS_TO_VM_PAGE(pmap_pte2pa(opte));
-
-	KASSERTMSG(pg != NULL, "pmap_remove_pte: unmanaged page marked "
-	    "PG_PVLIST, va = %#" PRIxVADDR ", pa = %#" PRIxPADDR,
-	    va, (paddr_t)pmap_pte2pa(opte));
-
-	KASSERT(uvm_page_locked_p(pg));
+	if ((pg = PHYS_TO_VM_PAGE(pmap_pte2pa(opte))) != NULL) {
+		KASSERT(uvm_page_locked_p(pg));
+		pp = VM_PAGE_TO_PP(pg);
+	} else if ((pp = pmap_pv_tracked(pmap_pte2pa(opte))) == NULL) {
+		paddr_t pa = pmap_pte2pa(opte);
+		panic("pmap_remove_pte: PG_PVLIST with pv-untracked page"
+		    " va = 0x%"PRIxVADDR
+		    " pa = 0x%"PRIxPADDR" (0x%"PRIxPADDR")",
+		    va, pa, atop(pa));
+	}
 
 	/* Sync R/M bits. */
-	pp = VM_PAGE_TO_PP(pg);
 	pp->pp_attrs |= opte;
 	pve = pmap_remove_pv(pp, ptp, va);
 
-	if (pve) { 
+	if (pve) {
 		pve->pve_next = *pv_tofree;
 		*pv_tofree = pve;
 	}
@@ -3545,26 +3666,16 @@ pmap_sync_pv(struct pv_pte *pvpte, pt_en
 	return 0;
 }
 
-/*
- * pmap_page_remove: remove a managed vm_page from all pmaps that map it
- *
- * => R/M bits are sync'd back to attrs
- */
-
-void
-pmap_page_remove(struct vm_page *pg)
+static void
+pmap_pp_remove(struct pmap_page *pp, paddr_t pa)
 {
-	struct pmap_page *pp;
 	struct pv_pte *pvpte;
 	struct pv_entry *killlist = NULL;
 	struct vm_page *ptp;
 	pt_entry_t expect;
 	int count;
 
-	KASSERT(uvm_page_locked_p(pg));
-
-	pp = VM_PAGE_TO_PP(pg);
-	expect = pmap_pa2pte(VM_PAGE_TO_PHYS(pg)) | PG_V;
+	expect = pmap_pa2pte(pa) | PG_V;
 	count = SPINLOCK_BACKOFF_MIN;
 	kpreempt_disable();
 startover:
@@ -3637,6 +3748,42 @@ startover:
 }
 
 /*
+ * pmap_page_remove: remove a managed vm_page from all pmaps that map it
+ *
+ * => R/M bits are sync'd back to attrs
+ */
+
+void
+pmap_page_remove(struct vm_page *pg)
+{
+	struct pmap_page *pp;
+	paddr_t pa;
+
+	KASSERT(uvm_page_locked_p(pg));
+
+	pp = VM_PAGE_TO_PP(pg);
+	pa = VM_PAGE_TO_PHYS(pg);
+	pmap_pp_remove(pp, pa);
+}
+
+/*
+ * pmap_pv_remove: remove an unmanaged pv-tracked page from all pmaps
+ *	that map it
+ */
+
+void
+pmap_pv_remove(paddr_t pa)
+{
+	struct pmap_page *pp;
+
+	pp = pmap_pv_tracked(pa);
+	if (pp == NULL)
+		panic("pmap_pv_protect: page not pv-tracked: 0x%"PRIxPADDR,
+		    pa);
+	pmap_pp_remove(pp, pa);
+}
+
+/*
  * p m a p   a t t r i b u t e  f u n c t i o n s
  * functions that test/change managed page's attributes
  * since a page can be mapped multiple times we must check each PTE that
@@ -3686,25 +3833,15 @@ pmap_test_attrs(struct vm_page *pg, unsi
 	return result != 0;
 }
 
-/*
- * pmap_clear_attrs: clear the specified attribute for a page.
- *
- * => we return true if we cleared one of the bits we were asked to
- */
-
-bool
-pmap_clear_attrs(struct vm_page *pg, unsigned clearbits)
+static bool
+pmap_pp_clear_attrs(struct pmap_page *pp, paddr_t pa, unsigned clearbits)
 {
-	struct pmap_page *pp;
 	struct pv_pte *pvpte;
 	u_int result;
 	pt_entry_t expect;
 	int count;
 
-	KASSERT(uvm_page_locked_p(pg));
-
-	pp = VM_PAGE_TO_PP(pg);
-	expect = pmap_pa2pte(VM_PAGE_TO_PHYS(pg)) | PG_V;
+	expect = pmap_pa2pte(pa) | PG_V;
 	count = SPINLOCK_BACKOFF_MIN;
 	kpreempt_disable();
 startover:
@@ -3729,6 +3866,43 @@ startover:
 	return result != 0;
 }
 
+/*
+ * pmap_clear_attrs: clear the specified attribute for a page.
+ *
+ * => we return true if we cleared one of the bits we were asked to
+ */
+
+bool
+pmap_clear_attrs(struct vm_page *pg, unsigned clearbits)
+{
+	struct pmap_page *pp;
+	paddr_t pa;
+
+	KASSERT(uvm_page_locked_p(pg));
+
+	pp = VM_PAGE_TO_PP(pg);
+	pa = VM_PAGE_TO_PHYS(pg);
+
+	return pmap_pp_clear_attrs(pp, pa, clearbits);
+}
+
+/*
+ * pmap_pv_clear_attrs: clear the specified attributes for an unmanaged
+ *	pv-tracked page.
+ */
+
+bool
+pmap_pv_clear_attrs(paddr_t pa, unsigned clearbits)
+{
+	struct pmap_page *pp;
+
+	pp = pmap_pv_tracked(pa);
+	if (pp == NULL)
+		panic("pmap_pv_protect: page not pv-tracked: 0x%"PRIxPADDR,
+		    pa);
+
+	return pmap_pp_clear_attrs(pp, pa, clearbits);
+}
 
 /*
  * p m a p   p r o t e c t i o n   f u n c t i o n s
@@ -3744,6 +3918,15 @@ startover:
 /* see pmap.h */
 
 /*
+ * pmap_pv_protect: change the protection of all recorded mappings
+ *	of an unmanaged pv-tracked page
+ *
+ * => NOTE: this is an inline function in pmap.h
+ */
+
+/* see pmap.h */
+
+/*
  * pmap_protect: set the protection in of the pages in a pmap
  *
  * => NOTE: this is an inline function in pmap.h
@@ -3900,9 +4083,9 @@ pmap_enter_ma(struct pmap *pmap, vaddr_t
 	pt_entry_t *ptes, opte, npte;
 	pt_entry_t *ptep;
 	pd_entry_t * const *pdes;
-	struct vm_page *ptp, *pg;
-	struct pmap_page *new_pp;
-	struct pmap_page *old_pp;
+	struct vm_page *ptp;
+	struct vm_page *new_pg, *old_pg;
+	struct pmap_page *new_pp, *old_pp;
 	struct pv_entry *old_pve = NULL;
 	struct pv_entry *new_pve;
 	struct pv_entry *new_pve2;
@@ -3945,14 +4128,17 @@ pmap_enter_ma(struct pmap *pmap, vaddr_t
 
 #ifdef XEN
 	if (domid != DOMID_SELF)
-		pg = NULL;
+		new_pg = NULL;
 	else
 #endif
-		pg = PHYS_TO_VM_PAGE(pa);
-	if (pg != NULL) {
+		new_pg = PHYS_TO_VM_PAGE(pa);
+	if (new_pg != NULL) {
 		/* This is a managed page */
 		npte |= PG_PVLIST;
-		new_pp = VM_PAGE_TO_PP(pg);
+		new_pp = VM_PAGE_TO_PP(new_pg);
+	} else if ((new_pp = pmap_pv_tracked(pa)) != NULL) {
+		/* This is an unmanaged pv-tracked page */
+		npte |= PG_PVLIST;
 	} else {
 		new_pp = NULL;
 	}
@@ -4041,25 +4227,28 @@ pmap_enter_ma(struct pmap *pmap, vaddr_t
 	}
 
 	/*
-	 * if old page is managed, remove pv_entry from its list.
+	 * if old page is pv-tracked, remove pv_entry from its list.
 	 */
 
 	if ((~opte & (PG_V | PG_PVLIST)) == 0) {
-		pg = PHYS_TO_VM_PAGE(pmap_pte2pa(opte));
-
-		KASSERTMSG(pg != NULL, "pmap_enter: PG_PVLIST mapping with "
-		    "unmanaged page pa = 0x%" PRIx64 " (0x%" PRIx64 ")",
-		    (int64_t)pa, (int64_t)atop(pa));
-
-		KASSERT(uvm_page_locked_p(pg));
+		if ((old_pg = PHYS_TO_VM_PAGE(pmap_pte2pa(opte))) != NULL) {
+			KASSERT(uvm_page_locked_p(old_pg));
+			old_pp = VM_PAGE_TO_PP(old_pg);
+		} else if ((old_pp = pmap_pv_tracked(pmap_pte2pa(opte)))
+		    == NULL) {
+			pa = pmap_pte2pa(opte);
+			panic("pmap_enter: PG_PVLIST with pv-untracked page"
+			    " va = 0x%"PRIxVADDR
+			    " pa = 0x%" PRIxPADDR " (0x%" PRIxPADDR ")",
+			    va, pa, atop(pa));
+		}
 
-		old_pp = VM_PAGE_TO_PP(pg);
 		old_pve = pmap_remove_pv(old_pp, ptp, va);
 		old_pp->pp_attrs |= opte;
 	}
 
 	/*
-	 * if new page is managed, insert pv_entry into its list.
+	 * if new page is pv-tracked, insert pv_entry into its list.
 	 */
 
 	if (new_pp) {

Index: src/sys/dev/pci/agp_amd64.c
diff -u src/sys/dev/pci/agp_amd64.c:1.7 src/sys/dev/pci/agp_amd64.c:1.7.14.1
--- src/sys/dev/pci/agp_amd64.c:1.7	Sat Feb 25 21:21:09 2012
+++ src/sys/dev/pci/agp_amd64.c	Thu Apr 23 07:31:16 2015
@@ -25,7 +25,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: agp_amd64.c,v 1.7 2012/02/25 21:21:09 tsutsui Exp $");
+__KERNEL_RCSID(0, "$NetBSD: agp_amd64.c,v 1.7.14.1 2015/04/23 07:31:16 snj Exp $");
 
 #include <sys/param.h>
 #include <sys/systm.h>
@@ -206,17 +206,19 @@ agp_amd64_attach(device_t parent, device
 	pcitag_t tag;
 	pcireg_t id, attbase, apctrl;
 	int maxdevs, i, n;
+	int error;
 
 	asc = malloc(sizeof(struct agp_amd64_softc), M_AGP, M_NOWAIT | M_ZERO);
 	if (asc == NULL) {
 		aprint_error(": can't allocate softc\n");
-		return ENOMEM;
+		error = ENOMEM;
+		goto fail0;
 	}
 
 	if (agp_map_aperture(pa, sc, AGP_APBASE) != 0) {
 		aprint_error(": can't map aperture\n");
-		free(asc, M_AGP);
-		return ENXIO;
+		error = ENXIO;
+		goto fail1;
 	}
 
 	maxdevs = pci_bus_maxdevs(pa->pa_pc, 0);
@@ -232,7 +234,8 @@ agp_amd64_attach(device_t parent, device
 	}
 	if (n == 0) {
 		aprint_error(": No Miscellaneous Control unit found.\n");
-		return ENXIO;
+		error = ENXIO;
+		goto fail1;
 	}
 	asc->n_mctrl = n;
 
@@ -256,8 +259,8 @@ agp_amd64_attach(device_t parent, device
 		 * aperture so that the gatt size reduces.
 		 */
 		if (AGP_SET_APERTURE(sc, AGP_GET_APERTURE(sc) / 2)) {
-			agp_generic_detach(sc);
-			return ENOMEM;
+			error = ENOMEM;
+			goto fail1;
 		}
 	}
 	asc->gatt = gatt;
@@ -265,15 +268,21 @@ agp_amd64_attach(device_t parent, device
 	switch (PCI_VENDOR(sc->as_id)) {
 	case PCI_VENDOR_ALI:
 		agp_amd64_uli_init(sc);
-		if (agp_amd64_uli_set_aperture(sc, asc->initial_aperture))
-			return ENXIO;
+		if (agp_amd64_uli_set_aperture(sc, asc->initial_aperture)) {
+			/* XXX Back out agp_amd64_uli_init?  */
+			error = ENXIO;
+			goto fail2;
+		}
 		break;
 
 	case PCI_VENDOR_NVIDIA:
 		asc->ctrl_tag = AGP_AMD64_NVIDIA_PCITAG(pa->pa_pc);
 		agp_amd64_nvidia_init(sc);
-		if (agp_amd64_nvidia_set_aperture(sc, asc->initial_aperture))
-			return ENXIO;
+		if (agp_amd64_nvidia_set_aperture(sc, asc->initial_aperture)) {
+			/* XXX Back out agp_amd64_nvidia_init?  */
+			error = ENXIO;
+			goto fail2;
+		}
 		break;
 
 	case PCI_VENDOR_VIATECH:
@@ -282,8 +291,11 @@ agp_amd64_attach(device_t parent, device
 			asc->ctrl_tag = AGP_AMD64_VIA_PCITAG(pa->pa_pc);
 			agp_amd64_via_init(sc);
 			if (agp_amd64_via_set_aperture(sc,
-			    asc->initial_aperture))
-				return ENXIO;
+			    asc->initial_aperture)) {
+				/* XXX Back out agp_amd64_via_init?  */
+				error = ENXIO;
+				goto fail2;
+			}
 		}
 		break;
 	}
@@ -304,7 +316,14 @@ agp_amd64_attach(device_t parent, device
 
 	agp_flush_cache();
 
+	/* Success!  */
 	return 0;
+
+fail2:	agp_free_gatt(sc, gatt);
+fail1:	free(asc, M_AGP);
+fail0:	agp_generic_detach(sc);
+	KASSERT(error);
+	return error;
 }
 
 

Index: src/sys/dev/pci/agp_i810.c
diff -u src/sys/dev/pci/agp_i810.c:1.112.2.2 src/sys/dev/pci/agp_i810.c:1.112.2.3
--- src/sys/dev/pci/agp_i810.c:1.112.2.2	Tue Mar 17 17:52:49 2015
+++ src/sys/dev/pci/agp_i810.c	Thu Apr 23 07:31:16 2015
@@ -1,4 +1,4 @@
-/*	$NetBSD: agp_i810.c,v 1.112.2.2 2015/03/17 17:52:49 riz Exp $	*/
+/*	$NetBSD: agp_i810.c,v 1.112.2.3 2015/04/23 07:31:16 snj Exp $	*/
 
 /*-
  * Copyright (c) 2000 Doug Rabson
@@ -30,7 +30,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: agp_i810.c,v 1.112.2.2 2015/03/17 17:52:49 riz Exp $");
+__KERNEL_RCSID(0, "$NetBSD: agp_i810.c,v 1.112.2.3 2015/04/23 07:31:16 snj Exp $");
 
 #include <sys/param.h>
 #include <sys/systm.h>
@@ -602,6 +602,16 @@ fail0:	agp_generic_detach(sc);
 	return error;
 }
 
+/*
+ * Skip pages reserved by the BIOS.  Notably, skip 0xa0000-0xfffff,
+ * which includes the video BIOS at 0xc0000-0xdffff which the display
+ * drivers need for video mode detection.
+ *
+ * XXX Is there an MI name for this, or a conventional x86 name?  Or
+ * should we really use bus_dma instead?
+ */
+#define	PCIBIOS_MIN_MEM		0x100000
+
 static int
 agp_i810_setup_chipset_flush_page(struct agp_softc *sc)
 {
@@ -621,7 +631,7 @@ agp_i810_setup_chipset_flush_page(struct
 	/* Read the PCI config register: 4-byte on gen3, 8-byte on gen>=4.  */
 	if (isc->chiptype == CHIP_I915) {
 		addr = pci_conf_read(pc, tag, AGP_I915_IFPADDR);
-		minaddr = PAGE_SIZE;	/* XXX PCIBIOS_MIN_MEM?  */
+		minaddr = PCIBIOS_MIN_MEM;
 		maxaddr = UINT32_MAX;
 	} else {
 		hi = pci_conf_read(pc, tag, AGP_I965_IFPADDR+4);
@@ -643,7 +653,7 @@ agp_i810_setup_chipset_flush_page(struct
 			return EIO;
 #endif
 		}
-		minaddr = PAGE_SIZE;	/* XXX PCIBIOS_MIN_MEM?  */
+		minaddr = PCIBIOS_MIN_MEM;
 		maxaddr = MIN(UINT64_MAX, ~(bus_addr_t)0);
 	}
 
@@ -695,8 +705,7 @@ agp_i810_teardown_chipset_flush_page(str
 			    AGP_I965_IFPADDR + 4, 0);
 		}
 		isc->flush_addr = 0;
-		bus_space_free(isc->flush_bst, isc->flush_bsh,
-		    PAGE_SIZE);
+		bus_space_free(isc->flush_bst, isc->flush_bsh, PAGE_SIZE);
 	} else {
 		/* Otherwise, just unmap the pre-allocated page.  */
 		bus_space_unmap(isc->flush_bst, isc->flush_bsh, PAGE_SIZE);

Index: src/sys/external/bsd/drm2/dist/drm/i915/i915_dma.c
diff -u src/sys/external/bsd/drm2/dist/drm/i915/i915_dma.c:1.10.2.3 src/sys/external/bsd/drm2/dist/drm/i915/i915_dma.c:1.10.2.4
--- src/sys/external/bsd/drm2/dist/drm/i915/i915_dma.c:1.10.2.3	Fri Mar  6 21:39:08 2015
+++ src/sys/external/bsd/drm2/dist/drm/i915/i915_dma.c	Thu Apr 23 07:31:17 2015
@@ -1734,6 +1734,8 @@ int i915_driver_load(struct drm_device *
 	dev_priv->gtt.mappable =
 	    drm_io_mapping_create_wc(dev, dev_priv->gtt.mappable_base,
 		aperture_size);
+	/* Note: mappable_end is the size, not end paddr, of the aperture.  */
+	pmap_pv_track(dev_priv->gtt.mappable_base, dev_priv->gtt.mappable_end);
 #else
 	dev_priv->gtt.mappable =
 		io_mapping_create_wc(dev_priv->gtt.mappable_base,
@@ -1851,6 +1853,11 @@ out_gem_unload:
 	destroy_workqueue(dev_priv->wq);
 out_mtrrfree:
 	arch_phys_wc_del(dev_priv->gtt.mtrr);
+#ifdef __NetBSD__
+	/* Note: mappable_end is the size, not end paddr, of the aperture.  */
+	pmap_pv_untrack(dev_priv->gtt.mappable_base,
+	    dev_priv->gtt.mappable_end);
+#endif
 	io_mapping_free(dev_priv->gtt.mappable);
 out_gtt:
 	list_del(&dev_priv->gtt.base.global_link);

Index: src/sys/external/bsd/drm2/dist/drm/i915/i915_gem.c
diff -u src/sys/external/bsd/drm2/dist/drm/i915/i915_gem.c:1.14.2.7 src/sys/external/bsd/drm2/dist/drm/i915/i915_gem.c:1.14.2.8
--- src/sys/external/bsd/drm2/dist/drm/i915/i915_gem.c:1.14.2.7	Tue Mar 17 17:52:49 2015
+++ src/sys/external/bsd/drm2/dist/drm/i915/i915_gem.c	Thu Apr 23 07:31:17 2015
@@ -2121,32 +2121,19 @@ i915_gem_release_mmap(struct drm_i915_ge
 
 #ifdef __NetBSD__		/* XXX gem gtt fault */
 	{
-		struct vm_page *page;
+		struct drm_device *const dev = obj->base.dev;
+		struct drm_i915_private *const dev_priv = dev->dev_private;
+		const paddr_t start = dev_priv->gtt.mappable_base +
+		    i915_gem_obj_ggtt_offset(obj);
+		const size_t size = obj->base.size;
+		const paddr_t end = start + size;
+		paddr_t pa;
 
-		mutex_enter(obj->base.gemo_shm_uao->vmobjlock);
-		KASSERT(obj->pages != NULL);
-		/* Force a fresh fault for each page.  */
-		/*
-		 * XXX OOPS!  This doesn't actually do what we want.
-		 * This causes a fresh fault for access to the backing
-		 * pages -- but nothing accesses the backing pages
-		 * directly!  What is actually entered into CPU page
-		 * table entries is aperture addresses which have been
-		 * programmed by the GTT to refer to those backing
-		 * pages.
-		 *
-		 * We need to clear those page table entries, but
-		 * there's no good way to do that at the moment: nobody
-		 * records for us a map from either uvm objects or
-		 * physical device addresses to a list of all virtual
-		 * pages where they have been mapped.  pmap(9) records
-		 * a map only from physical RAM addresses to virtual
-		 * pages; it does nothing for physical device
-		 * addresses.
-		 */
-		TAILQ_FOREACH(page, &obj->igo_pageq, pageq.queue)
-			pmap_page_protect(page, VM_PROT_NONE);
-		mutex_exit(obj->base.gemo_shm_uao->vmobjlock);
+		KASSERT((start & (PAGE_SIZE - 1)) == 0);
+		KASSERT((size & (PAGE_SIZE - 1)) == 0);
+
+		for (pa = start; pa < end; pa += PAGE_SIZE)
+			pmap_pv_protect(pa, VM_PROT_NONE);
 	}
 #else
 	drm_vma_node_unmap(&obj->base.vma_node,

Index: src/sys/external/bsd/drm2/dist/drm/nouveau/nouveau_agp.c
diff -u src/sys/external/bsd/drm2/dist/drm/nouveau/nouveau_agp.c:1.2 src/sys/external/bsd/drm2/dist/drm/nouveau/nouveau_agp.c:1.2.4.1
--- src/sys/external/bsd/drm2/dist/drm/nouveau/nouveau_agp.c:1.2	Wed Aug  6 13:35:13 2014
+++ src/sys/external/bsd/drm2/dist/drm/nouveau/nouveau_agp.c	Thu Apr 23 07:31:17 2015
@@ -1,7 +1,7 @@
-/*	$NetBSD: nouveau_agp.c,v 1.2 2014/08/06 13:35:13 riastradh Exp $	*/
+/*	$NetBSD: nouveau_agp.c,v 1.2.4.1 2015/04/23 07:31:17 snj Exp $	*/
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: nouveau_agp.c,v 1.2 2014/08/06 13:35:13 riastradh Exp $");
+__KERNEL_RCSID(0, "$NetBSD: nouveau_agp.c,v 1.2.4.1 2015/04/23 07:31:17 snj Exp $");
 
 #include <linux/module.h>
 #include <linux/moduleparam.h>
@@ -190,6 +190,9 @@ nouveau_agp_init(struct nouveau_drm *drm
 	drm->agp.stat = ENABLED;
 	drm->agp.base = info.aperture_base;
 	drm->agp.size = info.aperture_size;
+#ifdef __NetBSD__
+	pmap_pv_track(drm->agp.base, drm->agp.size);
+#endif
 #endif
 }
 
@@ -198,7 +201,11 @@ nouveau_agp_fini(struct nouveau_drm *drm
 {
 #if __OS_HAS_AGP
 	struct drm_device *dev = drm->dev;
-	if (dev->agp && dev->agp->acquired)
+	if (dev->agp && dev->agp->acquired) {
+#ifdef __NetBSD__
+		pmap_pv_untrack(drm->agp.base, drm->agp.size);
+#endif
 		drm_agp_release(dev);
+	}
 #endif
 }

Index: src/sys/external/bsd/drm2/dist/drm/nouveau/nouveau_ttm.c
diff -u src/sys/external/bsd/drm2/dist/drm/nouveau/nouveau_ttm.c:1.2.4.1 src/sys/external/bsd/drm2/dist/drm/nouveau/nouveau_ttm.c:1.2.4.2
--- src/sys/external/bsd/drm2/dist/drm/nouveau/nouveau_ttm.c:1.2.4.1	Fri Mar  6 21:39:08 2015
+++ src/sys/external/bsd/drm2/dist/drm/nouveau/nouveau_ttm.c	Thu Apr 23 07:31:17 2015
@@ -1,4 +1,4 @@
-/*	$NetBSD: nouveau_ttm.c,v 1.2.4.1 2015/03/06 21:39:08 snj Exp $	*/
+/*	$NetBSD: nouveau_ttm.c,v 1.2.4.2 2015/04/23 07:31:17 snj Exp $	*/
 
 /*
  * Copyright (c) 2007-2008 Tungsten Graphics, Inc., Cedar Park, TX., USA,
@@ -27,7 +27,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: nouveau_ttm.c,v 1.2.4.1 2015/03/06 21:39:08 snj Exp $");
+__KERNEL_RCSID(0, "$NetBSD: nouveau_ttm.c,v 1.2.4.2 2015/04/23 07:31:17 snj Exp $");
 
 #include <subdev/fb.h>
 #include <subdev/vm.h>
@@ -443,6 +443,11 @@ nouveau_ttm_init(struct nouveau_drm *drm
 	drm->ttm.mtrr = arch_phys_wc_add(nv_device_resource_start(device, 1),
 					 nv_device_resource_len(device, 1));
 
+#ifdef __NetBSD__
+	pmap_pv_track(nv_device_resource_start(device, 1),
+	    nv_device_resource_len(device, 1));
+#endif
+
 	/* GART init */
 	if (drm->agp.stat != ENABLED) {
 		drm->gem.gart_available = nouveau_vmmgr(drm->device)->limit;
@@ -476,4 +481,9 @@ nouveau_ttm_fini(struct nouveau_drm *drm
 
 	arch_phys_wc_del(drm->ttm.mtrr);
 	drm->ttm.mtrr = 0;
+
+#ifdef __NetBSD__
+	pmap_pv_untrack(nv_device_resource_start(nv_device(drm->device), 1),
+	    nv_device_resource_len(nv_device(drm->device), 1));
+#endif
 }

Index: src/sys/external/bsd/drm2/dist/drm/radeon/atombios_crtc.c
diff -u src/sys/external/bsd/drm2/dist/drm/radeon/atombios_crtc.c:1.2 src/sys/external/bsd/drm2/dist/drm/radeon/atombios_crtc.c:1.2.4.1
--- src/sys/external/bsd/drm2/dist/drm/radeon/atombios_crtc.c:1.2	Wed Jul 16 20:59:57 2014
+++ src/sys/external/bsd/drm2/dist/drm/radeon/atombios_crtc.c	Thu Apr 23 07:31:17 2015
@@ -1124,23 +1124,24 @@ static int dce4_crtc_do_set_base(struct 
 	 */
 	obj = radeon_fb->obj;
 	rbo = gem_to_radeon_bo(obj);
-	r = radeon_bo_reserve(rbo, false);
-	if (unlikely(r != 0))
-		return r;
 
-	if (atomic)
+	if (atomic) {
+		BUG_ON(rbo->pin_count == 0);
 		fb_location = radeon_bo_gpu_offset(rbo);
-	else {
+		tiling_flags = 0;
+	} else {
+		r = radeon_bo_reserve(rbo, false);
+		if (unlikely(r != 0))
+			return r;
 		r = radeon_bo_pin(rbo, RADEON_GEM_DOMAIN_VRAM, &fb_location);
 		if (unlikely(r != 0)) {
 			radeon_bo_unreserve(rbo);
 			return -EINVAL;
 		}
+		radeon_bo_get_tiling_flags(rbo, &tiling_flags, NULL);
+		radeon_bo_unreserve(rbo);
 	}
 
-	radeon_bo_get_tiling_flags(rbo, &tiling_flags, NULL);
-	radeon_bo_unreserve(rbo);
-
 	switch (target_fb->bits_per_pixel) {
 	case 8:
 		fb_format = (EVERGREEN_GRPH_DEPTH(EVERGREEN_GRPH_DEPTH_8BPP) |
Index: src/sys/external/bsd/drm2/dist/drm/radeon/radeon_agp.c
diff -u src/sys/external/bsd/drm2/dist/drm/radeon/radeon_agp.c:1.2 src/sys/external/bsd/drm2/dist/drm/radeon/radeon_agp.c:1.2.4.1
--- src/sys/external/bsd/drm2/dist/drm/radeon/radeon_agp.c:1.2	Wed Jul 16 20:59:57 2014
+++ src/sys/external/bsd/drm2/dist/drm/radeon/radeon_agp.c	Thu Apr 23 07:31:17 2015
@@ -248,6 +248,10 @@ int radeon_agp_init(struct radeon_device
 	dev_info(rdev->dev, "GTT: %"PRIu64"M 0x%08"PRIX64" - 0x%08"PRIX64"\n",
 		rdev->mc.gtt_size >> 20, rdev->mc.gtt_start, rdev->mc.gtt_end);
 
+#ifdef __NetBSD__
+	pmap_pv_track(rdev->mc.agp_base, rdev->mc.gtt_size);
+#endif
+
 	/* workaround some hw issues */
 	if (rdev->family < CHIP_R200) {
 		WREG32(RADEON_AGP_CNTL, RREG32(RADEON_AGP_CNTL) | 0x000e0000);
@@ -274,6 +278,9 @@ void radeon_agp_fini(struct radeon_devic
 {
 #if __OS_HAS_AGP
 	if (rdev->ddev->agp && rdev->ddev->agp->acquired) {
+#ifdef __NetBSD__
+		pmap_pv_untrack(rdev->mc.agp_base, rdev->mc.gtt_size);
+#endif
 		drm_agp_release(rdev->ddev);
 	}
 #endif
Index: src/sys/external/bsd/drm2/dist/drm/radeon/radeon_display.c
diff -u src/sys/external/bsd/drm2/dist/drm/radeon/radeon_display.c:1.2 src/sys/external/bsd/drm2/dist/drm/radeon/radeon_display.c:1.2.4.1
--- src/sys/external/bsd/drm2/dist/drm/radeon/radeon_display.c:1.2	Wed Jul 16 20:59:57 2014
+++ src/sys/external/bsd/drm2/dist/drm/radeon/radeon_display.c	Thu Apr 23 07:31:17 2015
@@ -181,12 +181,36 @@ static void legacy_crtc_load_lut(struct 
 		dac2_cntl |= RADEON_DAC2_PALETTE_ACC_CTL;
 	WREG32(RADEON_DAC_CNTL2, dac2_cntl);
 
-	WREG8(RADEON_PALETTE_INDEX, 0);
-	for (i = 0; i < 256; i++) {
-		WREG32(RADEON_PALETTE_30_DATA,
-			     (radeon_crtc->lut_r[i] << 20) |
-			     (radeon_crtc->lut_g[i] << 10) |
-			     (radeon_crtc->lut_b[i] << 0));
+	/*
+	 * At least the RV100 [vendor 1002 product 515e (rev. 0x02)]
+	 * has an old style palette
+	 */
+	if (ASIC_IS_RV100(rdev)) {
+#ifdef notyet
+		/*
+		 * Leave CLUT alone for now. The code below gives us a
+		 * nice 444 grayscale, but we are not in true color mode
+		 * anymore and I don't have any docs how to do this right.
+		 */
+		WREG8(RADEON_PALETTE_INDEX, 0);
+		for (i = 0; i < 256; i++) {
+#define R(x) (radeon_crtc->lut_r[i] >> 2)
+#define G(x) (radeon_crtc->lut_g[i] >> 2)
+#define B(x) (radeon_crtc->lut_b[i] >> 2)
+			WREG32(RADEON_PALETTE_DATA, ((R(i) << 16)
+				| (G(i) << 8) | B(i)) << 4);
+		}
+#else
+		printf("%s: unknown DAC, can't set lookup table\n", __func__);
+#endif
+	} else {
+		WREG8(RADEON_PALETTE_INDEX, 0);
+		for (i = 0; i < 256; i++) {
+			WREG32(RADEON_PALETTE_30_DATA,
+				     (radeon_crtc->lut_r[i] << 20) |
+				     (radeon_crtc->lut_g[i] << 10) |
+				     (radeon_crtc->lut_b[i] << 0));
+		}
 	}
 }
 
Index: src/sys/external/bsd/drm2/dist/drm/radeon/radeon_object.c
diff -u src/sys/external/bsd/drm2/dist/drm/radeon/radeon_object.c:1.2 src/sys/external/bsd/drm2/dist/drm/radeon/radeon_object.c:1.2.4.1
--- src/sys/external/bsd/drm2/dist/drm/radeon/radeon_object.c:1.2	Wed Jul 16 20:59:57 2014
+++ src/sys/external/bsd/drm2/dist/drm/radeon/radeon_object.c	Thu Apr 23 07:31:17 2015
@@ -366,6 +366,10 @@ int radeon_bo_init(struct radeon_device 
 		rdev->mc.vram_mtrr = arch_phys_wc_add(rdev->mc.aper_base,
 						      rdev->mc.aper_size);
 	}
+#ifdef __NetBSD__
+	if (rdev->mc.aper_base)
+		pmap_pv_track(rdev->mc.aper_base, rdev->mc.aper_size);
+#endif
 	DRM_INFO("Detected VRAM RAM=%"PRIx64"M, BAR=%lluM\n",
 		rdev->mc.mc_vram_size >> 20,
 		(unsigned long long)rdev->mc.aper_size >> 20);
@@ -377,6 +381,10 @@ int radeon_bo_init(struct radeon_device 
 void radeon_bo_fini(struct radeon_device *rdev)
 {
 	radeon_ttm_fini(rdev);
+#ifdef __NetBSD__
+	if (rdev->mc.aper_base)
+		pmap_pv_untrack(rdev->mc.aper_base, rdev->mc.aper_size);
+#endif
 	arch_phys_wc_del(rdev->mc.vram_mtrr);
 }
 

Index: src/sys/external/bsd/drm2/dist/drm/radeon/radeon_legacy_crtc.c
diff -u src/sys/external/bsd/drm2/dist/drm/radeon/radeon_legacy_crtc.c:1.1.1.1 src/sys/external/bsd/drm2/dist/drm/radeon/radeon_legacy_crtc.c:1.1.1.1.4.1
--- src/sys/external/bsd/drm2/dist/drm/radeon/radeon_legacy_crtc.c:1.1.1.1	Wed Jul 16 19:35:28 2014
+++ src/sys/external/bsd/drm2/dist/drm/radeon/radeon_legacy_crtc.c	Thu Apr 23 07:31:17 2015
@@ -422,6 +422,16 @@ int radeon_crtc_do_set_base(struct drm_c
 	/* Pin framebuffer & get tilling informations */
 	obj = radeon_fb->obj;
 	rbo = gem_to_radeon_bo(obj);
+	if (atomic) {
+		/*
+		 * If you want to do this in atomic, better have it
+		 * pinned ahead of time.
+		 */
+		BUG_ON(rbo->pin_count == 0);
+		base = radeon_bo_gpu_offset(rbo);
+		tiling_flags = 0;
+		goto pinned;
+	}
 retry:
 	r = radeon_bo_reserve(rbo, false);
 	if (unlikely(r != 0))
@@ -444,7 +454,7 @@ retry:
 		 * We don't shutdown the display controller because new buffer
 		 * will end up in same spot.
 		 */
-		if (!atomic && fb && fb != crtc->primary->fb) {
+		if (fb && fb != crtc->primary->fb) {
 			struct radeon_bo *old_rbo;
 			unsigned long nsize, osize;
 
@@ -462,6 +472,7 @@ retry:
 	}
 	radeon_bo_get_tiling_flags(rbo, &tiling_flags, NULL);
 	radeon_bo_unreserve(rbo);
+pinned:
 	if (tiling_flags & RADEON_TILING_MICRO)
 		DRM_ERROR("trying to scanout microtiled buffer\n");
 

Index: src/sys/external/bsd/drm2/dist/drm/radeon/radeon_ttm.c
diff -u src/sys/external/bsd/drm2/dist/drm/radeon/radeon_ttm.c:1.5.4.1 src/sys/external/bsd/drm2/dist/drm/radeon/radeon_ttm.c:1.5.4.2
--- src/sys/external/bsd/drm2/dist/drm/radeon/radeon_ttm.c:1.5.4.1	Sun Jan 11 06:29:15 2015
+++ src/sys/external/bsd/drm2/dist/drm/radeon/radeon_ttm.c	Thu Apr 23 07:31:17 2015
@@ -450,6 +450,10 @@ static int radeon_ttm_io_mem_reserve(str
 			mem->bus.offset = mem->start << PAGE_SHIFT;
 			mem->bus.base = rdev->mc.agp_base;
 			mem->bus.is_iomem = !rdev->ddev->agp->cant_use_aperture;
+			KASSERTMSG((mem->bus.base & (PAGE_SIZE - 1)) == 0,
+			    "agp aperture is not page-aligned: %lx",
+			    mem->bus.base);
+			KASSERT((mem->bus.offset & (PAGE_SIZE - 1)) == 0);
 		}
 #endif
 		break;
@@ -483,6 +487,10 @@ static int radeon_ttm_io_mem_reserve(str
 		mem->bus.base = (mem->bus.base & 0x0ffffffffUL) +
 			rdev->ddev->hose->dense_mem_base;
 #endif
+		KASSERTMSG((mem->bus.base & (PAGE_SIZE - 1)) == 0,
+		    "mc aperture is not page-aligned: %lx",
+		    mem->bus.base);
+		KASSERT((mem->bus.offset & (PAGE_SIZE - 1)) == 0);
 		break;
 	default:
 		return -EINVAL;

Index: src/sys/external/bsd/drm2/dist/drm/ttm/ttm_bo.c
diff -u src/sys/external/bsd/drm2/dist/drm/ttm/ttm_bo.c:1.4.2.1 src/sys/external/bsd/drm2/dist/drm/ttm/ttm_bo.c:1.4.2.2
--- src/sys/external/bsd/drm2/dist/drm/ttm/ttm_bo.c:1.4.2.1	Mon Aug 18 07:49:10 2014
+++ src/sys/external/bsd/drm2/dist/drm/ttm/ttm_bo.c	Thu Apr 23 07:31:17 2015
@@ -1021,6 +1021,7 @@ static int ttm_bo_move_buffer(struct ttm
 	mem.num_pages = bo->num_pages;
 	mem.size = mem.num_pages << PAGE_SHIFT;
 	mem.page_alignment = bo->mem.page_alignment;
+	mem.bus.is_iomem = false;
 	mem.bus.io_reserved_vm = false;
 	mem.bus.io_reserved_count = 0;
 	/*
@@ -1611,17 +1612,28 @@ void ttm_bo_unmap_virtual_locked(struct 
 
 #ifdef __NetBSD__
 	if (bo->mem.bus.is_iomem) {
-		/*
-		 * XXX OOPS!  NetBSD doesn't have a way to enumerate
-		 * and remove the virtual mappings for device addresses
-		 * or of a uvm object.
-		 */
+		paddr_t start, end, pa;
+
+		KASSERTMSG((bo->mem.bus.base & (PAGE_SIZE - 1)) == 0,
+		    "bo bus base addr not page-aligned: %lx",
+		    bo->mem.bus.base);
+		KASSERTMSG((bo->mem.bus.offset & (PAGE_SIZE - 1)) == 0,
+		    "bo bus offset not page-aligned: %lx",
+		    bo->mem.bus.offset);
+		start = bo->mem.bus.base + bo->mem.bus.offset;
+		KASSERT((bo->mem.bus.size & (PAGE_SIZE - 1)) == 0);
+		end = start + bo->mem.bus.size;
+
+		for (pa = start; pa < end; pa += PAGE_SIZE)
+			pmap_pv_protect(pa, VM_PROT_NONE);
 	} else if (bo->ttm != NULL) {
 		unsigned i;
 
+		mutex_enter(bo->uvmobj.vmobjlock);
 		for (i = 0; i < bo->ttm->num_pages; i++)
 			pmap_page_protect(&bo->ttm->pages[i]->p_vmp,
 			    VM_PROT_NONE);
+		mutex_exit(bo->uvmobj.vmobjlock);
 	}
 #else
 	drm_vma_node_unmap(&bo->vma_node, bdev->dev_mapping);

Index: src/sys/external/bsd/drm2/dist/drm/ttm/ttm_bo_util.c
diff -u src/sys/external/bsd/drm2/dist/drm/ttm/ttm_bo_util.c:1.4 src/sys/external/bsd/drm2/dist/drm/ttm/ttm_bo_util.c:1.4.2.1
--- src/sys/external/bsd/drm2/dist/drm/ttm/ttm_bo_util.c:1.4	Fri Jul 18 03:11:55 2014
+++ src/sys/external/bsd/drm2/dist/drm/ttm/ttm_bo_util.c	Thu Apr 23 07:31:17 2015
@@ -524,8 +524,13 @@ static int ttm_buffer_object_transfer(st
 	INIT_LIST_HEAD(&fbo->swap);
 	INIT_LIST_HEAD(&fbo->io_reserve_lru);
 #ifdef __NetBSD__
+	linux_mutex_init(&fbo->wu_mutex);
 	drm_vma_node_init(&fbo->vma_node);
+	uvm_obj_init(&fbo->uvmobj, bdev->driver->ttm_uvm_ops, true, 1);
+	mutex_obj_hold(bo->uvmobj.vmobjlock);
+	uvm_obj_setlock(&fbo->uvmobj, bo->uvmobj.vmobjlock);
 #else
+	mutex_init(&fbo->wu_mutex);
 	drm_vma_node_reset(&fbo->vma_node);
 #endif
 	atomic_set(&fbo->cpu_writers, 0);

Index: src/sys/external/bsd/drm2/i915drm/intelfb.c
diff -u src/sys/external/bsd/drm2/i915drm/intelfb.c:1.9.4.2 src/sys/external/bsd/drm2/i915drm/intelfb.c:1.9.4.3
--- src/sys/external/bsd/drm2/i915drm/intelfb.c:1.9.4.2	Fri Mar  6 21:39:10 2015
+++ src/sys/external/bsd/drm2/i915drm/intelfb.c	Thu Apr 23 07:31:17 2015
@@ -1,4 +1,4 @@
-/*	$NetBSD: intelfb.c,v 1.9.4.2 2015/03/06 21:39:10 snj Exp $	*/
+/*	$NetBSD: intelfb.c,v 1.9.4.3 2015/04/23 07:31:17 snj Exp $	*/
 
 /*-
  * Copyright (c) 2014 The NetBSD Foundation, Inc.
@@ -30,7 +30,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: intelfb.c,v 1.9.4.2 2015/03/06 21:39:10 snj Exp $");
+__KERNEL_RCSID(0, "$NetBSD: intelfb.c,v 1.9.4.3 2015/04/23 07:31:17 snj Exp $");
 
 #include <sys/types.h>
 #include <sys/bus.h>
@@ -180,7 +180,7 @@ intelfb_attach_task(struct i915drmkms_ta
 		return;
 	}
 
-	if (pmf_device_register1(sc->sc_dev, NULL, NULL, &intelfb_shutdown))
+	if (!pmf_device_register1(sc->sc_dev, NULL, NULL, &intelfb_shutdown))
 		aprint_error_dev(sc->sc_dev,
 		    "failed to register shutdown handler\n");
 

Index: src/sys/external/bsd/drm2/include/drm/drm_wait_netbsd.h
diff -u src/sys/external/bsd/drm2/include/drm/drm_wait_netbsd.h:1.4.2.3 src/sys/external/bsd/drm2/include/drm/drm_wait_netbsd.h:1.4.2.4
--- src/sys/external/bsd/drm2/include/drm/drm_wait_netbsd.h:1.4.2.3	Fri Mar  6 21:39:10 2015
+++ src/sys/external/bsd/drm2/include/drm/drm_wait_netbsd.h	Thu Apr 23 07:31:17 2015
@@ -1,4 +1,4 @@
-/*	$NetBSD: drm_wait_netbsd.h,v 1.4.2.3 2015/03/06 21:39:10 snj Exp $	*/
+/*	$NetBSD: drm_wait_netbsd.h,v 1.4.2.4 2015/04/23 07:31:17 snj Exp $	*/
 
 /*-
  * Copyright (c) 2013 The NetBSD Foundation, Inc.
@@ -124,9 +124,8 @@ DRM_SPIN_WAKEUP_ALL(drm_waitqueue_t *q, 
 
 #define	DRM_SPIN_WAIT_ON(RET, Q, INTERLOCK, TICKS, CONDITION)	do	      \
 {									      \
-	extern int hardclock_ticks;					      \
-	const int _dswo_start = hardclock_ticks;			      \
-	const int _dswo_end = _dswo_start + (TICKS);			      \
+	unsigned _dswo_ticks = (TICKS);					      \
+	unsigned _dswo_start, _dswo_end;				      \
 									      \
 	KASSERT(spin_is_locked((INTERLOCK)));				      \
 	KASSERT(!cpu_intr_p());						      \
@@ -138,16 +137,22 @@ DRM_SPIN_WAKEUP_ALL(drm_waitqueue_t *q, 
 			(RET) = 0;					      \
 			break;						      \
 		}							      \
-		const int _dswo_now = hardclock_ticks;			      \
-		if (_dswo_end < _dswo_now) {				      \
+		if (_dswo_ticks == 0) {					      \
 			(RET) = -EBUSY;		/* Match Linux...  */	      \
 			break;						      \
 		}							      \
+		_dswo_start = hardclock_ticks;				      \
 		/* XXX errno NetBSD->Linux */				      \
 		(RET) = -cv_timedwait_sig((Q), &(INTERLOCK)->sl_lock, 1);     \
+		_dswo_end = hardclock_ticks;				      \
+		if (_dswo_end - _dswo_start < _dswo_ticks)		      \
+			_dswo_ticks -= _dswo_end - _dswo_start;		      \
+		else							      \
+			_dswo_ticks = 0;				      \
 		if (RET) {						      \
 			if ((RET) == -EWOULDBLOCK)			      \
-				(RET) = (CONDITION) ? 0 : -EBUSY;	      \
+				/* Waited only one tick.  */		      \
+				continue;				      \
 			break;						      \
 		}							      \
 	}								      \
@@ -211,33 +216,36 @@ DRM_SPIN_WAKEUP_ALL(drm_waitqueue_t *q, 
 
 #define	_DRM_TIMED_WAIT_UNTIL(RET, WAIT, Q, INTERLOCK, TICKS, CONDITION) do \
 {									\
-	extern int hardclock_ticks;					\
-	const int _dtwu_start = hardclock_ticks;			\
-	int _dtwu_ticks = (TICKS);					\
+	unsigned _dtwu_ticks = (TICKS);					\
+	unsigned _dtwu_start, _dtwu_end;				\
+									\
 	KASSERT(mutex_is_locked((INTERLOCK)));				\
 	ASSERT_SLEEPABLE();						\
 	KASSERT(!cold);							\
+									\
 	for (;;) {							\
 		if (CONDITION) {					\
-			(RET) = _dtwu_ticks;				\
+			(RET) = MAX(_dtwu_ticks, 1);			\
 			break;						\
 		}							\
+		if (_dtwu_ticks == 0) {					\
+			(RET) = 0;					\
+			break;						\
+		}							\
+		_dtwu_start = hardclock_ticks;				\
 		/* XXX errno NetBSD->Linux */				\
 		(RET) = -WAIT((Q), &(INTERLOCK)->mtx_lock,		\
-		    _dtwu_ticks);					\
+		    MIN(_dtwu_ticks, INT_MAX/2));			\
+		_dtwu_end = hardclock_ticks;				\
+		if ((_dtwu_end - _dtwu_start) < _dtwu_ticks)		\
+			_dtwu_ticks -= _dtwu_end - _dtwu_start;		\
+		else							\
+			_dtwu_ticks = 0;				\
 		if (RET) {						\
 			if ((RET) == -EWOULDBLOCK)			\
 				(RET) = (CONDITION) ? 1 : 0;		\
 			break;						\
 		}							\
-		const int _dtwu_now = hardclock_ticks;			\
-		KASSERT(_dtwu_start <= _dtwu_now);			\
-		if ((_dtwu_now - _dtwu_start) < _dtwu_ticks) {		\
-			_dtwu_ticks -= (_dtwu_now - _dtwu_start);	\
-		} else {						\
-			(RET) = (CONDITION) ? 1 : 0;			\
-			break;						\
-		}							\
 	}								\
 } while (0)
 
@@ -278,34 +286,37 @@ DRM_SPIN_WAKEUP_ALL(drm_waitqueue_t *q, 
 #define	_DRM_SPIN_TIMED_WAIT_UNTIL(RET, WAIT, Q, INTERLOCK, TICKS, CONDITION) \
 	do								\
 {									\
-	extern int hardclock_ticks;					\
-	const int _dstwu_start = hardclock_ticks;			\
-	int _dstwu_ticks = (TICKS);					\
+	unsigned _dstwu_ticks = (TICKS);				\
+	unsigned _dstwu_start, _dstwu_end;				\
+									\
 	KASSERT(spin_is_locked((INTERLOCK)));				\
 	KASSERT(!cpu_intr_p());						\
 	KASSERT(!cpu_softintr_p());					\
 	KASSERT(!cold);							\
+									\
 	for (;;) {							\
 		if (CONDITION) {					\
-			(RET) = _dstwu_ticks;				\
+			(RET) = MAX(_dstwu_ticks, 1);			\
 			break;						\
 		}							\
+		if (_dstwu_ticks == 0) {				\
+			(RET) = 0;					\
+			break;						\
+		}							\
+		_dstwu_start = hardclock_ticks;				\
 		/* XXX errno NetBSD->Linux */				\
 		(RET) = -WAIT((Q), &(INTERLOCK)->sl_lock,		\
-		    _dstwu_ticks);					\
+		    MIN(_dstwu_ticks, INT_MAX/2));			\
+		_dstwu_end = hardclock_ticks;				\
+		if ((_dstwu_end - _dstwu_start) < _dstwu_ticks)		\
+			_dstwu_ticks -= _dstwu_end - _dstwu_start;	\
+		else							\
+			_dstwu_ticks = 0;				\
 		if (RET) {						\
 			if ((RET) == -EWOULDBLOCK)			\
 				(RET) = (CONDITION) ? 1 : 0;		\
 			break;						\
 		}							\
-		const int _dstwu_now = hardclock_ticks;			\
-		KASSERT(_dstwu_start <= _dstwu_now);			\
-		if ((_dstwu_now - _dstwu_start) < _dstwu_ticks) {	\
-			_dstwu_ticks -= (_dstwu_now - _dstwu_start);	\
-		} else {						\
-			(RET) = (CONDITION) ? 1 : 0;			\
-			break;						\
-		}							\
 	}								\
 } while (0)
 

Index: src/sys/external/bsd/drm2/include/linux/mm.h
diff -u src/sys/external/bsd/drm2/include/linux/mm.h:1.3.2.1 src/sys/external/bsd/drm2/include/linux/mm.h:1.3.2.2
--- src/sys/external/bsd/drm2/include/linux/mm.h:1.3.2.1	Wed Dec 31 06:44:00 2014
+++ src/sys/external/bsd/drm2/include/linux/mm.h	Thu Apr 23 07:31:17 2015
@@ -1,4 +1,4 @@
-/*	$NetBSD: mm.h,v 1.3.2.1 2014/12/31 06:44:00 snj Exp $	*/
+/*	$NetBSD: mm.h,v 1.3.2.2 2015/04/23 07:31:17 snj Exp $	*/
 
 /*-
  * Copyright (c) 2013 The NetBSD Foundation, Inc.
@@ -32,18 +32,12 @@
 #ifndef _LINUX_MM_H_
 #define _LINUX_MM_H_
 
-#include <sys/kauth.h>
-#include <sys/file.h>
-#include <sys/mman.h>
-#include <sys/proc.h>
-#include <sys/vnode.h>
-
-#include <miscfs/specfs/specdev.h>
-
 #include <uvm/uvm_extern.h>
 
 #include <asm/page.h>
 
+struct file;
+
 /* XXX Ugh bletch!  Whattakludge!  Linux's sense is reversed...  */
 #undef	PAGE_MASK
 #define	PAGE_MASK	(~(PAGE_SIZE-1))
@@ -67,52 +61,13 @@ si_meminfo(struct sysinfo *si)
 	/* XXX Fill in more as needed.  */
 }
 
-/*
- * ###################################################################
- * ############### XXX THIS NEEDS SERIOUS SCRUTINY XXX ###############
- * ###################################################################
- */
-
-/*
- * XXX unsigned long is a loser but will probably work accidentally.
- * XXX struct file might not map quite right between Linux and NetBSD.
- * XXX This is large enough it should take its own file.
- */
-
 static inline unsigned long
-vm_mmap(struct file *file, unsigned long base, unsigned long size,
-    unsigned long prot, unsigned long flags, unsigned long token)
+vm_mmap(struct file *file __unused, unsigned long base __unused,
+    unsigned long size __unused, unsigned long prot __unused,
+    unsigned long flags __unused, unsigned long token __unused)
 {
-	struct vnode *vp;
-	void *addr;
-	int error;
-
-	/*
-	 * Cargo-culted from sys_mmap.  Various conditions kasserted
-	 * rather than checked for expedience and safey.
-	 */
-
-	KASSERT(base == 0);
-	KASSERT(prot == (PROT_READ | PROT_WRITE));
-	KASSERT(flags == MAP_SHARED);
-
-	KASSERT(file->f_type == DTYPE_VNODE);
-	vp = file->f_data;
-
-	KASSERT(vp->v_type == VCHR);
-	KASSERT((file->f_flag & (FREAD | FWRITE)) == (FREAD | FWRITE));
-
-	/* XXX pax_mprotect?  pax_aslr?  */
-
-	addr = NULL;
-	error = uvm_mmap_dev(curproc, &addr, size, vp->v_rdev, (off_t)base);
-	if (error)
-		goto out;
-
-	KASSERT((uintptr_t)addr <= -1024UL); /* XXX Kludgerosity!  */
 
-out:	/* XXX errno NetBSD->Linux (kludgerific) */
-	return (error? (-error) : (unsigned long)addr);
+	return -ENODEV;
 }
 
 #endif  /* _LINUX_MM_H_ */

Index: src/sys/external/bsd/drm2/include/linux/pci.h
diff -u src/sys/external/bsd/drm2/include/linux/pci.h:1.7.2.5 src/sys/external/bsd/drm2/include/linux/pci.h:1.7.2.6
--- src/sys/external/bsd/drm2/include/linux/pci.h:1.7.2.5	Fri Mar  6 21:39:10 2015
+++ src/sys/external/bsd/drm2/include/linux/pci.h	Thu Apr 23 07:31:17 2015
@@ -1,4 +1,4 @@
-/*	$NetBSD: pci.h,v 1.7.2.5 2015/03/06 21:39:10 snj Exp $	*/
+/*	$NetBSD: pci.h,v 1.7.2.6 2015/04/23 07:31:17 snj Exp $	*/
 
 /*-
  * Copyright (c) 2013 The NetBSD Foundation, Inc.
@@ -331,7 +331,7 @@ pci_clear_master(struct pci_dev *pdev)
 	    PCI_COMMAND_STATUS_REG, csr);
 }
 
-#define	PCIBIOS_MIN_MEM	0	/* XXX bogus x86 kludge bollocks */
+#define	PCIBIOS_MIN_MEM	0x100000	/* XXX bogus x86 kludge bollocks */
 
 static inline bus_addr_t
 pcibios_align_resource(void *p, const struct resource *resource,

Index: src/sys/external/bsd/drm2/nouveau/nouveaufb.c
diff -u src/sys/external/bsd/drm2/nouveau/nouveaufb.c:1.1.2.2 src/sys/external/bsd/drm2/nouveau/nouveaufb.c:1.1.2.3
--- src/sys/external/bsd/drm2/nouveau/nouveaufb.c:1.1.2.2	Fri Mar  6 21:39:11 2015
+++ src/sys/external/bsd/drm2/nouveau/nouveaufb.c	Thu Apr 23 07:31:17 2015
@@ -1,4 +1,4 @@
-/*	$NetBSD: nouveaufb.c,v 1.1.2.2 2015/03/06 21:39:11 snj Exp $	*/
+/*	$NetBSD: nouveaufb.c,v 1.1.2.3 2015/04/23 07:31:17 snj Exp $	*/
 
 /*-
  * Copyright (c) 2015 The NetBSD Foundation, Inc.
@@ -30,7 +30,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: nouveaufb.c,v 1.1.2.2 2015/03/06 21:39:11 snj Exp $");
+__KERNEL_RCSID(0, "$NetBSD: nouveaufb.c,v 1.1.2.3 2015/04/23 07:31:17 snj Exp $");
 
 #include <sys/types.h>
 #include <sys/bus.h>
@@ -158,7 +158,7 @@ nouveaufb_attach_task(struct nouveau_tas
 		return;
 	}
 
-	if (pmf_device_register1(sc->sc_dev, NULL, NULL, &nouveaufb_shutdown))
+	if (!pmf_device_register1(sc->sc_dev, NULL, NULL, &nouveaufb_shutdown))
 		aprint_error_dev(sc->sc_dev,
 		    "failed to register shutdown handler\n");
 

Index: src/sys/external/bsd/drm2/radeon/radeon_pci.c
diff -u src/sys/external/bsd/drm2/radeon/radeon_pci.c:1.4.4.1 src/sys/external/bsd/drm2/radeon/radeon_pci.c:1.4.4.2
--- src/sys/external/bsd/drm2/radeon/radeon_pci.c:1.4.4.1	Fri Mar  6 21:39:11 2015
+++ src/sys/external/bsd/drm2/radeon/radeon_pci.c	Thu Apr 23 07:31:17 2015
@@ -1,4 +1,4 @@
-/*	$NetBSD: radeon_pci.c,v 1.4.4.1 2015/03/06 21:39:11 snj Exp $	*/
+/*	$NetBSD: radeon_pci.c,v 1.4.4.2 2015/04/23 07:31:17 snj Exp $	*/
 
 /*-
  * Copyright (c) 2014 The NetBSD Foundation, Inc.
@@ -30,7 +30,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: radeon_pci.c,v 1.4.4.1 2015/03/06 21:39:11 snj Exp $");
+__KERNEL_RCSID(0, "$NetBSD: radeon_pci.c,v 1.4.4.2 2015/04/23 07:31:17 snj Exp $");
 
 #ifdef _KERNEL_OPT
 #include "vga.h"
@@ -105,6 +105,8 @@ static int	radeon_match(device_t, cfdata
 static void	radeon_attach(device_t, device_t, void *);
 static void	radeon_attach_real(device_t);
 static int	radeon_detach(device_t, int);
+static bool	radeon_do_suspend(device_t, const pmf_qual_t *);
+static bool	radeon_do_resume(device_t, const pmf_qual_t *);
 
 static void	radeon_task_work(struct work *, void *);
 
@@ -163,6 +165,9 @@ radeon_attach(device_t parent, device_t 
 
 	pci_aprint_devinfo(pa, NULL);
 
+	if (!pmf_device_register(self, &radeon_do_suspend, &radeon_do_resume))
+		aprint_error_dev(self, "unable to establish power handler\n");
+
 	/*
 	 * Trivial initialization first; the rest will come after we
 	 * have mounted the root file system and can load firmware
@@ -259,14 +264,14 @@ radeon_detach(device_t self, int flags)
 		return error;
 
 	if (sc->sc_task_state == RADEON_TASK_ATTACH)
-		return 0;
+		goto out;
 	if (sc->sc_task_u.workqueue != NULL) {
 		workqueue_destroy(sc->sc_task_u.workqueue);
 		sc->sc_task_u.workqueue = NULL;
 	}
 
 	if (sc->sc_drm_dev == NULL)
-		return 0;
+		goto out;
 	/* XXX errno Linux->NetBSD */
 	error = -drm_pci_detach(sc->sc_drm_dev, flags);
 	if (error)
@@ -274,9 +279,47 @@ radeon_detach(device_t self, int flags)
 		return error;
 	sc->sc_drm_dev = NULL;
 
+out:	pmf_device_deregister(self);
+
 	return 0;
 }
 
+static bool
+radeon_do_suspend(device_t self, const pmf_qual_t *qual)
+{
+	struct radeon_softc *const sc = device_private(self);
+	struct drm_device *const dev = sc->sc_drm_dev;
+	int ret;
+	bool is_console = true; /* XXX */
+
+	if (dev == NULL)
+		return true;
+
+	ret = radeon_suspend_kms(dev, true, is_console);
+	if (ret)
+		return false;
+
+	return true;
+}
+
+static bool
+radeon_do_resume(device_t self, const pmf_qual_t *qual)
+{
+	struct radeon_softc *const sc = device_private(self);
+	struct drm_device *const dev = sc->sc_drm_dev;
+	int ret;
+	bool is_console = true; /* XXX */
+
+	if (dev == NULL)
+		return true;
+
+	ret = radeon_resume_kms(dev, true, is_console);
+	if (ret)
+		return false;
+
+	return true;
+}
+
 static void
 radeon_task_work(struct work *work, void *cookie __unused)
 {

Index: src/sys/uvm/uvm_init.c
diff -u src/sys/uvm/uvm_init.c:1.45 src/sys/uvm/uvm_init.c:1.45.12.1
--- src/sys/uvm/uvm_init.c:1.45	Tue Jan 29 21:37:04 2013
+++ src/sys/uvm/uvm_init.c	Thu Apr 23 07:31:17 2015
@@ -1,4 +1,4 @@
-/*	$NetBSD: uvm_init.c,v 1.45 2013/01/29 21:37:04 para Exp $	*/
+/*	$NetBSD: uvm_init.c,v 1.45.12.1 2015/04/23 07:31:17 snj Exp $	*/
 
 /*
  * Copyright (c) 1997 Charles D. Cranor and Washington University.
@@ -32,7 +32,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: uvm_init.c,v 1.45 2013/01/29 21:37:04 para Exp $");
+__KERNEL_RCSID(0, "$NetBSD: uvm_init.c,v 1.45.12.1 2015/04/23 07:31:17 snj Exp $");
 
 #include <sys/param.h>
 #include <sys/systm.h>
@@ -133,6 +133,9 @@ uvm_init(void)
 	 */
 
 	uvm_km_init();
+#ifdef __HAVE_PMAP_PV_TRACK
+	pmap_pv_init();
+#endif
 
 #ifdef DEBUG
 	debug_init();

Reply via email to