Module Name: src
Committed By: riastradh
Date: Sun Apr 24 04:26:12 UTC 2016
Modified Files:
src/sys/external/bsd/drm2/dist/drm/nouveau: nouveau_bo.c
src/sys/external/bsd/drm2/dist/drm/radeon: radeon_ttm.c
src/sys/external/bsd/drm2/dist/drm/ttm: ttm_tt.c
src/sys/external/bsd/drm2/dist/include/drm/ttm: ttm_bo_driver.h
src/sys/external/bsd/drm2/include/drm/ttm: ttm_page_alloc.h
src/sys/external/bsd/drm2/ttm: ttm_bus_dma.c
Log Message:
Rework ttm tt swapin/swapout logic.
Rather than handling `swapping in/out' here, per se, we let uvm do
that, we interpret `swap out' as `deactivate pages', and we add
generic ttm operations to wire and unwire pages, for the ttm_tt
driver to use.
This fixes certain graphics buffer eviction logic, which enables
nouveau to suspend/resume on one of my machines. (The machine
doesn't resume overall for other reasons, but the nouveau device
suspends and resumes in isolation.)
XXX pullup to netbsd-7 after a couple weeks
To generate a diff of this commit:
cvs rdiff -u -r1.6 -r1.7 \
src/sys/external/bsd/drm2/dist/drm/nouveau/nouveau_bo.c
cvs rdiff -u -r1.7 -r1.8 \
src/sys/external/bsd/drm2/dist/drm/radeon/radeon_ttm.c
cvs rdiff -u -r1.6 -r1.7 src/sys/external/bsd/drm2/dist/drm/ttm/ttm_tt.c
cvs rdiff -u -r1.2 -r1.3 \
src/sys/external/bsd/drm2/dist/include/drm/ttm/ttm_bo_driver.h
cvs rdiff -u -r1.1 -r1.2 \
src/sys/external/bsd/drm2/include/drm/ttm/ttm_page_alloc.h
cvs rdiff -u -r1.1 -r1.2 src/sys/external/bsd/drm2/ttm/ttm_bus_dma.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/dist/drm/nouveau/nouveau_bo.c
diff -u src/sys/external/bsd/drm2/dist/drm/nouveau/nouveau_bo.c:1.6 src/sys/external/bsd/drm2/dist/drm/nouveau/nouveau_bo.c:1.7
--- src/sys/external/bsd/drm2/dist/drm/nouveau/nouveau_bo.c:1.6 Thu Oct 29 08:08:52 2015
+++ src/sys/external/bsd/drm2/dist/drm/nouveau/nouveau_bo.c Sun Apr 24 04:26:12 2016
@@ -1,4 +1,4 @@
-/* $NetBSD: nouveau_bo.c,v 1.6 2015/10/29 08:08:52 mrg Exp $ */
+/* $NetBSD: nouveau_bo.c,v 1.7 2016/04/24 04:26:12 riastradh Exp $ */
/*
* Copyright 2007 Dave Airlied
@@ -30,7 +30,7 @@
*/
#include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: nouveau_bo.c,v 1.6 2015/10/29 08:08:52 mrg Exp $");
+__KERNEL_RCSID(0, "$NetBSD: nouveau_bo.c,v 1.7 2016/04/24 04:26:12 riastradh Exp $");
#include <core/engine.h>
#include <linux/swiotlb.h>
@@ -1524,6 +1524,16 @@ nouveau_ttm_tt_unpopulate(struct ttm_tt
#endif
}
+#ifdef __NetBSD__
+static void
+nouveau_ttm_tt_swapout(struct ttm_tt *ttm)
+{
+ struct ttm_dma_tt *ttm_dma = container_of(ttm, struct ttm_dma_tt, ttm);
+
+ ttm_bus_dma_swapout(ttm_dma);
+}
+#endif
+
void
nouveau_bo_fence(struct nouveau_bo *nvbo, struct nouveau_fence *fence)
{
@@ -1581,6 +1591,7 @@ struct ttm_bo_driver nouveau_bo_driver =
.ttm_tt_populate = &nouveau_ttm_tt_populate,
.ttm_tt_unpopulate = &nouveau_ttm_tt_unpopulate,
#ifdef __NetBSD__
+ .ttm_tt_swapout = &nouveau_ttm_tt_swapout,
.ttm_uvm_ops = &nouveau_uvm_ops,
#endif
.invalidate_caches = nouveau_bo_invalidate_caches,
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.7 src/sys/external/bsd/drm2/dist/drm/radeon/radeon_ttm.c:1.8
--- src/sys/external/bsd/drm2/dist/drm/radeon/radeon_ttm.c:1.7 Fri Apr 10 17:44:35 2015
+++ src/sys/external/bsd/drm2/dist/drm/radeon/radeon_ttm.c Sun Apr 24 04:26:12 2016
@@ -716,6 +716,15 @@ static void radeon_ttm_tt_unpopulate(str
}
#ifdef __NetBSD__
+static void radeon_ttm_tt_swapout(struct ttm_tt *ttm)
+{
+ struct radeon_ttm_tt *gtt = container_of(ttm, struct radeon_ttm_tt,
+ ttm.ttm);
+ struct ttm_dma_tt *ttm_dma = >t->ttm;
+
+ ttm_bus_dma_swapout(ttm_dma);
+}
+
static int radeon_ttm_fault(struct uvm_faultinfo *, vaddr_t,
struct vm_page **, int, int, vm_prot_t, int);
@@ -731,6 +740,7 @@ static struct ttm_bo_driver radeon_bo_dr
.ttm_tt_populate = &radeon_ttm_tt_populate,
.ttm_tt_unpopulate = &radeon_ttm_tt_unpopulate,
#ifdef __NetBSD__
+ .ttm_tt_swapout = &radeon_ttm_tt_swapout,
.ttm_uvm_ops = &radeon_uvm_ops,
#endif
.invalidate_caches = &radeon_invalidate_caches,
Index: src/sys/external/bsd/drm2/dist/drm/ttm/ttm_tt.c
diff -u src/sys/external/bsd/drm2/dist/drm/ttm/ttm_tt.c:1.6 src/sys/external/bsd/drm2/dist/drm/ttm/ttm_tt.c:1.7
--- src/sys/external/bsd/drm2/dist/drm/ttm/ttm_tt.c:1.6 Sun Jul 27 00:40:39 2014
+++ src/sys/external/bsd/drm2/dist/drm/ttm/ttm_tt.c Sun Apr 24 04:26:12 2016
@@ -349,15 +349,30 @@ int ttm_tt_bind(struct ttm_tt *ttm, stru
}
EXPORT_SYMBOL(ttm_tt_bind);
-int ttm_tt_swapin(struct ttm_tt *ttm)
-{
#ifdef __NetBSD__
+/*
+ * ttm_tt_wire(ttm)
+ *
+ * Wire the uvm pages of ttm and fill the ttm page array. ttm
+ * must be unpopulated or unbound, and must be marked swapped.
+ * This does not change either state -- the caller is expected to
+ * include it among other operations for such a state transition.
+ */
+int
+ttm_tt_wire(struct ttm_tt *ttm)
+{
struct uvm_object *uobj = ttm->swap_storage;
struct vm_page *page;
unsigned i;
int error;
+ KASSERTMSG((ttm->state == tt_unpopulated || ttm->state == tt_unbound),
+ "ttm_tt %p must be unpopulated or unbound for wiring,"
+ " but state=%d",
+ ttm, (int)ttm->state);
+ KASSERT(ISSET(ttm->page_flags, TTM_PAGE_FLAG_SWAPPED));
KASSERT(uobj != NULL);
+
error = uvm_obj_wirepages(uobj, 0, (ttm->num_pages << PAGE_SHIFT),
&ttm->pglist);
if (error)
@@ -375,7 +390,37 @@ int ttm_tt_swapin(struct ttm_tt *ttm)
/* Success! */
return 0;
-#else
+}
+
+/*
+ * ttm_tt_unwire(ttm)
+ *
+ * Nullify the ttm page array and unwire the uvm pages of ttm.
+ * ttm must be unbound and must be marked swapped. This does not
+ * change either state -- the caller is expected to include it
+ * among other operations for such a state transition.
+ */
+void
+ttm_tt_unwire(struct ttm_tt *ttm)
+{
+ struct uvm_object *uobj = ttm->swap_storage;
+ unsigned i;
+
+ KASSERTMSG((ttm->state == tt_unbound),
+ "ttm_tt %p must be unbound for unwiring, but state=%d",
+ ttm, (int)ttm->state);
+ KASSERT(!ISSET(ttm->page_flags, TTM_PAGE_FLAG_SWAPPED));
+ KASSERT(uobj != NULL);
+
+ uvm_obj_unwirepages(uobj, 0, (ttm->num_pages << PAGE_SHIFT));
+ for (i = 0; i < ttm->num_pages; i++)
+ ttm->pages[i] = NULL;
+}
+#endif
+
+#ifndef __NetBSD__
+int ttm_tt_swapin(struct ttm_tt *ttm)
+{
struct address_space *swap_space;
struct file *swap_storage;
struct page *from_page;
@@ -410,35 +455,25 @@ int ttm_tt_swapin(struct ttm_tt *ttm)
return 0;
out_err:
return ret;
-#endif
}
+#endif
-#ifdef __NetBSD__
int ttm_tt_swapout(struct ttm_tt *ttm, struct file *persistent_swap_storage)
{
- struct uvm_object *uobj = ttm->swap_storage;
- unsigned i;
-
- KASSERT((ttm->state == tt_unbound) || (ttm->state == tt_unpopulated));
- KASSERT(ttm->caching_state == tt_cached);
- KASSERT(uobj != NULL);
+#ifdef __NetBSD__
- /*
- * XXX Dunno what this persistent swap storage business is all
- * about, but I see nothing using it and it doesn't make sense.
- */
+ KASSERTMSG((ttm->state == tt_unpopulated || ttm->state == tt_unbound),
+ "ttm_tt %p must be unpopulated or unbound for swapout,"
+ " but state=%d",
+ ttm, (int)ttm->state);
+ KASSERTMSG((ttm->caching_state == tt_cached),
+ "ttm_tt %p must be cached for swapout, but caching_state=%d",
+ ttm, (int)ttm->caching_state);
KASSERT(persistent_swap_storage == NULL);
- uvm_obj_unwirepages(uobj, 0, (ttm->num_pages << PAGE_SHIFT));
- for (i = 0; i < ttm->num_pages; i++)
- ttm->pages[i] = NULL;
-
- /* Success! */
+ ttm->bdev->driver->ttm_tt_swapout(ttm);
return 0;
-}
#else
-int ttm_tt_swapout(struct ttm_tt *ttm, struct file *persistent_swap_storage)
-{
struct address_space *swap_space;
struct file *swap_storage;
struct page *from_page;
@@ -489,8 +524,8 @@ out_err:
fput(swap_storage);
return ret;
-}
#endif
+}
static void ttm_tt_clear_mapping(struct ttm_tt *ttm)
{
Index: src/sys/external/bsd/drm2/dist/include/drm/ttm/ttm_bo_driver.h
diff -u src/sys/external/bsd/drm2/dist/include/drm/ttm/ttm_bo_driver.h:1.2 src/sys/external/bsd/drm2/dist/include/drm/ttm/ttm_bo_driver.h:1.3
--- src/sys/external/bsd/drm2/dist/include/drm/ttm/ttm_bo_driver.h:1.2 Wed Jul 16 20:59:57 2014
+++ src/sys/external/bsd/drm2/dist/include/drm/ttm/ttm_bo_driver.h Sun Apr 24 04:26:12 2016
@@ -368,6 +368,15 @@ struct ttm_bo_driver {
void (*ttm_tt_unpopulate)(struct ttm_tt *ttm);
/**
+ * ttm_tt_swapout
+ *
+ * @ttm: The struct ttm_tt to contain the backing pages.
+ *
+ * Deactivate all backing pages, but don't free them
+ */
+ void (*ttm_tt_swapout)(struct ttm_tt *ttm);
+
+ /**
* struct ttm_bo_driver member invalidate_caches
*
* @bdev: the buffer object device.
@@ -666,6 +675,25 @@ extern void ttm_tt_destroy(struct ttm_tt
*/
extern void ttm_tt_unbind(struct ttm_tt *ttm);
+#ifdef __NetBSD__
+/**
+ * ttm_tt_wire
+ *
+ * @ttm The struct ttm_tt.
+ *
+ * Wire the pages of a ttm_tt, allocating pages for it if necessary.
+ */
+extern int ttm_tt_wire(struct ttm_tt *ttm);
+
+/**
+ * ttm_tt_unwire
+ *
+ * @ttm The struct ttm_tt.
+ *
+ * Unwire the pages of a ttm_tt.
+ */
+extern void ttm_tt_unwire(struct ttm_tt *ttm);
+#else
/**
* ttm_tt_swapin:
*
@@ -674,6 +702,7 @@ extern void ttm_tt_unbind(struct ttm_tt
* Swap in a previously swap out ttm_tt.
*/
extern int ttm_tt_swapin(struct ttm_tt *ttm);
+#endif
/**
* ttm_tt_cache_flush:
Index: src/sys/external/bsd/drm2/include/drm/ttm/ttm_page_alloc.h
diff -u src/sys/external/bsd/drm2/include/drm/ttm/ttm_page_alloc.h:1.1 src/sys/external/bsd/drm2/include/drm/ttm/ttm_page_alloc.h:1.2
--- src/sys/external/bsd/drm2/include/drm/ttm/ttm_page_alloc.h:1.1 Wed Jul 16 20:59:58 2014
+++ src/sys/external/bsd/drm2/include/drm/ttm/ttm_page_alloc.h Sun Apr 24 04:26:12 2016
@@ -1,4 +1,4 @@
-/* $NetBSD: ttm_page_alloc.h,v 1.1 2014/07/16 20:59:58 riastradh Exp $ */
+/* $NetBSD: ttm_page_alloc.h,v 1.2 2016/04/24 04:26:12 riastradh Exp $ */
/*-
* Copyright (c) 2014 The NetBSD Foundation, Inc.
@@ -37,6 +37,7 @@ struct ttm_mem_global;
int ttm_bus_dma_populate(struct ttm_dma_tt *);
void ttm_bus_dma_unpopulate(struct ttm_dma_tt *);
+void ttm_bus_dma_swapout(struct ttm_dma_tt *);
static inline int
ttm_page_alloc_init(struct ttm_mem_global *glob __unused,
Index: src/sys/external/bsd/drm2/ttm/ttm_bus_dma.c
diff -u src/sys/external/bsd/drm2/ttm/ttm_bus_dma.c:1.1 src/sys/external/bsd/drm2/ttm/ttm_bus_dma.c:1.2
--- src/sys/external/bsd/drm2/ttm/ttm_bus_dma.c:1.1 Wed Jul 16 20:59:58 2014
+++ src/sys/external/bsd/drm2/ttm/ttm_bus_dma.c Sun Apr 24 04:26:12 2016
@@ -1,4 +1,4 @@
-/* $NetBSD: ttm_bus_dma.c,v 1.1 2014/07/16 20:59:58 riastradh Exp $ */
+/* $NetBSD: ttm_bus_dma.c,v 1.2 2016/04/24 04:26:12 riastradh Exp $ */
/*-
* Copyright (c) 2014 The NetBSD Foundation, Inc.
@@ -30,7 +30,7 @@
*/
#include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: ttm_bus_dma.c,v 1.1 2014/07/16 20:59:58 riastradh Exp $");
+__KERNEL_RCSID(0, "$NetBSD: ttm_bus_dma.c,v 1.2 2016/04/24 04:26:12 riastradh Exp $");
#include <sys/bus.h>
@@ -40,17 +40,41 @@ __KERNEL_RCSID(0, "$NetBSD: ttm_bus_dma.
#include <ttm/ttm_bo_driver.h>
#include <ttm/ttm_page_alloc.h>
+/*
+ * ttm_bus_dma_populate(ttm_dma)
+ *
+ * If ttm_dma is not already populated, wire its pages and load
+ * its DMA map. The wiring and loading are stable as long as the
+ * associated bo is reserved.
+ *
+ * Transitions from tt_unpopulated or tt_unbound to tt_unbound.
+ * Marks as wired, a.k.a. !swapped.
+ */
int
ttm_bus_dma_populate(struct ttm_dma_tt *ttm_dma)
{
int ret;
- /* If it's already populated, nothing to do. */
- if (ttm_dma->ttm.state != tt_unpopulated)
- return 0;
+ KASSERT(ttm_dma->ttm.state != tt_bound);
+
+ /* Check the current state. */
+ if (ttm_dma->ttm.state == tt_unbound) {
+ /*
+ * If it's populated, then if the pages are wired and
+ * loaded already, nothing to do.
+ */
+ if (!ISSET(ttm_dma->ttm.page_flags, TTM_PAGE_FLAG_SWAPPED))
+ return 0;
+ } else if (ttm_dma->ttm.state == tt_unpopulated) {
+ /* If it's unpopulated, it can't be swapped. */
+ KASSERT(!ISSET(ttm_dma->ttm.page_flags,
+ TTM_PAGE_FLAG_SWAPPED));
+ /* Pretend it is now, for the sake of ttm_tt_wire. */
+ ttm_dma->ttm.page_flags |= TTM_PAGE_FLAG_SWAPPED;
+ }
- /* Wire the pages, allocating them if necessary. */
- ret = ttm_tt_swapin(&ttm_dma->ttm);
+ /* Wire the uvm pages and fill the ttm page array. */
+ ret = ttm_tt_wire(&ttm_dma->ttm);
if (ret)
goto fail0;
@@ -62,34 +86,86 @@ ttm_bus_dma_populate(struct ttm_dma_tt *
if (ret)
goto fail1;
- /* Success! */
+ /* Mark it wired. */
+ ttm_dma->ttm.page_flags &= ~TTM_PAGE_FLAG_SWAPPED;
+
+ /* Mark it populated but unbound. */
ttm_dma->ttm.state = tt_unbound;
+
+ /* Success! */
return 0;
fail2: __unused
bus_dmamap_unload(ttm_dma->ttm.bdev->dmat, ttm_dma->dma_address);
-fail1: ttm_tt_swapout(&ttm_dma->ttm, NULL);
+fail1: ttm_tt_unwire(&ttm_dma->ttm);
fail0: KASSERT(ret);
return ret;
}
-void
-ttm_bus_dma_unpopulate(struct ttm_dma_tt *ttm_dma)
+static void
+ttm_bus_dma_put(struct ttm_dma_tt *ttm_dma, int flags)
{
struct uvm_object *const uobj = ttm_dma->ttm.swap_storage;
const size_t size = (ttm_dma->ttm.num_pages << PAGE_SHIFT);
- /* Unload the DMA map. */
- bus_dmamap_unload(ttm_dma->ttm.bdev->dmat, ttm_dma->dma_address);
-
- /* Unwire the pages. */
- ttm_tt_swapout(&ttm_dma->ttm, NULL);
+ /*
+ * Can't be tt_bound -- still in use and needs to be removed
+ * from GPU page tables. Can't be tt_unpopulated -- if it
+ * were, why are you hnadling this? Hence tt_unbound.
+ */
+ KASSERTMSG((ttm_dma->ttm.state == tt_unbound),
+ "ttm_tt %p in invalid state for unpopulate/swapout: %d",
+ &ttm_dma->ttm, (int)ttm_dma->ttm.state);
+
+ /* If pages are wired and loaded, unload and unwire them. */
+ if (!ISSET(ttm_dma->ttm.page_flags, TTM_PAGE_FLAG_SWAPPED)) {
+ bus_dmamap_unload(ttm_dma->ttm.bdev->dmat,
+ ttm_dma->dma_address);
+ ttm_tt_unwire(&ttm_dma->ttm);
+ ttm_dma->ttm.page_flags |= TTM_PAGE_FLAG_SWAPPED;
+ }
/* We are using uvm_aobj, which had better have a pgo_put. */
KASSERT(uobj->pgops->pgo_put);
- /* Release the pages. */
+ /* Release or deactivate the pages. */
mutex_enter(uobj->vmobjlock);
- (void)(*uobj->pgops->pgo_put)(uobj, 0, size, PGO_CLEANIT|PGO_FREE);
+ (void)(*uobj->pgops->pgo_put)(uobj, 0, size, flags);
/* pgo_put unlocks uobj->vmobjlock. */
+
+ /* Mark it unpopulated. */
+ ttm_dma->ttm.state = tt_unpopulated;
+}
+
+/*
+ * ttmm_bus_dma_unpopulate(ttm_dma)
+ *
+ * Unload any DMA map, unwire any pages, and release any pages
+ * associated with ttm_dma.
+ *
+ * Transitions from tt_unbound to tt_unpopulated. Marks as
+ * unwired, a.k.a. swapped.
+ */
+void
+ttm_bus_dma_unpopulate(struct ttm_dma_tt *ttm_dma)
+{
+
+ ttm_bus_dma_put(ttm_dma, PGO_CLEANIT|PGO_FREE);
+}
+
+/*
+ * ttm_bus_dma_swapout(ttm_dma)
+ *
+ * Unload any DMA map, unwire any pages, and deactivate any pages
+ * associated with ttm_dma so that they can be swapped out, but
+ * don't release them.
+ *
+ * Transitions from tt_unbound to tt_unpopulated. Marks as
+ * unwired, a.k.a. swapped.
+ */
+void
+ttm_bus_dma_swapout(struct ttm_dma_tt *ttm_dma)
+{
+
+ ttm_bus_dma_put(ttm_dma, PGO_DEACTIVATE);
}