Source-Changes-HG archive

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index][Old Index]

[src/uebayasi-xip]: src/sys/uvm Initial MD per-page data (struct vm_page_md) ...



details:   https://anonhg.NetBSD.org/src/rev/f9a7ab06802f
branches:  uebayasi-xip
changeset: 751552:f9a7ab06802f
user:      uebayasi <uebayasi%NetBSD.org@localhost>
date:      Wed Feb 10 02:12:39 2010 +0000

description:
Initial MD per-page data (struct vm_page_md) lookup code for XIP'able device
pages.  Compile tested only.

Always define uvm_pageisdevice_p().  Always false if kernel is !DEVICE_PAGE.

diffstat:

 sys/uvm/uvm_page.c |  163 +++++++++++++++++++++++++++++++++++++++++++++++++---
 sys/uvm/uvm_page.h |    6 +-
 2 files changed, 157 insertions(+), 12 deletions(-)

diffs (261 lines):

diff -r 02644391018e -r f9a7ab06802f sys/uvm/uvm_page.c
--- a/sys/uvm/uvm_page.c        Wed Feb 10 02:10:28 2010 +0000
+++ b/sys/uvm/uvm_page.c        Wed Feb 10 02:12:39 2010 +0000
@@ -1,4 +1,4 @@
-/*     $NetBSD: uvm_page.c,v 1.153.2.9 2010/02/09 14:12:00 uebayasi Exp $      */
+/*     $NetBSD: uvm_page.c,v 1.153.2.10 2010/02/10 02:12:39 uebayasi Exp $     */
 
 /*
  * Copyright (c) 1997 Charles D. Cranor and Washington University.
@@ -71,11 +71,12 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: uvm_page.c,v 1.153.2.9 2010/02/09 14:12:00 uebayasi Exp $");
+__KERNEL_RCSID(0, "$NetBSD: uvm_page.c,v 1.153.2.10 2010/02/10 02:12:39 uebayasi Exp $");
 
 #include "opt_ddb.h"
 #include "opt_uvmhist.h"
 #include "opt_readahead.h"
+#include "opt_device_page.h"
 #include "opt_xip.h"
 
 #include <sys/param.h>
@@ -103,7 +104,7 @@
 
 struct vm_physseg vm_physmem[VM_PHYSSEG_MAX];  /* XXXCDC: uvm.physmem */
 int vm_nphysmem = 0;                           /* XXXCDC: uvm.nphysmem */
-#ifdef XIP
+#ifdef DEVICE_PAGE
 struct vm_physseg vm_physdev[VM_PHYSSEG_MAX];  /* XXXCDC: uvm.physdev */
 int vm_nphysdev = 0;                           /* XXXCDC: uvm.nphysdev */
 #endif
@@ -901,7 +902,7 @@
            pframe, NULL, offp);
 }
 
-#ifdef XIP
+#ifdef DEVICE_PAGE
 int
 vm_physseg_find_device(paddr_t pframe, int *offp)
 {
@@ -1029,12 +1030,22 @@
 }
 
 
+#ifdef DEVICE_PAGE
 /*
- * PHYS_TO_VM_PAGE: find vm_page for a PA.   used by MI code to get vm_pages
- * back from an I/O mapping (ugh!).   used in some MD code as well.
+ * Device pages don't have struct vm_page objects for various reasons:
+ *
+ * - Device pages are volatile; not paging involved.  Which means we have
+ *   much less state information to keep for each page.
+ *
+ * - Volatile, directly memory-mappable devices (framebuffers, audio devices,
+ *   etc.) only need physical address and attribute (protection and some
+ *   accelaration specific to physical bus) common to all the pages.
+ *   Allocating vm_page objects to keep such informations is wasteful.
+ *
+ * - Per-page MD information is only used for XIP vnodes' copy-on-write from
+ *   a device page to anon.
  */
 
-#ifdef XIP
 /* Assume struct vm_page * is aligned to 4 bytes. */
 #define        VM_PAGE_DEVICE_MAGIC            0x2
 #define        VM_PAGE_DEVICE_MAGIC_MASK       0x3
@@ -1064,6 +1075,12 @@
 }
 #endif
 
+
+/*
+ * PHYS_TO_VM_PAGE: find vm_page for a PA.   used by MI code to get vm_pages
+ * back from an I/O mapping (ugh!).   used in some MD code as well.
+ */
+
 struct vm_page *
 uvm_phys_to_vm_page(paddr_t pa)
 {
@@ -1071,7 +1088,7 @@
        int     off;
        int     psi;
 
-#ifdef XIP
+#ifdef DEVICE_PAGE
        psi = vm_physseg_find_device(pf, &off);
        if (psi != -1)
                return(PHYS_TO_VM_PAGE_DEVICE(pa));
@@ -1088,7 +1105,7 @@
        const struct vm_physseg *seg;
        int psi;
 
-#ifdef XIP
+#ifdef DEVICE_PAGE
        if (uvm_pageisdevice_p(pg)) {
                return VM_PAGE_DEVICE_TO_PHYS(pg);
        }
@@ -1099,6 +1116,132 @@
        return (seg->start + pg - seg->pgs) * PAGE_SIZE;
 }
 
+
+#ifdef XIP
+/*
+ * Device page's mdpage lookup.
+ *
+ * - Hashing code is based on sys/arch/x86/x86/pmap.c.
+ *
+ * - 
+ * XXX Consider to allocate slots on-demand.
+ */
+
+void vm_page_device_mdpage_insert(struct vm_page *);
+void vm_page_device_mdpage_remove(struct vm_page *);
+struct vm_page_md *vm_page_device_mdpage_lookup(struct vm_page *);
+
+struct vm_page_device_mdpage_entry {
+       struct vm_page_md mde_mdpage;
+       SLIST_ENTRY(vm_page_device_mdpage_entry) mde_hash;
+       paddr_t mde_pf;
+};
+
+/*
+ * These can be optimized depending on the size of XIP'ed executables' .data
+ * segments.  If page size is 4K and .data is 1M, .data spans across 256
+ * pages.  Considering these pages' physical addresses are continuous, linear
+ * hash should suffice.
+ */
+#define        MDPG_HASH_SIZE          256     /* XXX */
+#define        MDPG_HASH_LOCK_CNT      4       /* XXX */
+
+struct vm_page_device_mdpage {
+       kmutex_t locks[MDPG_HASH_LOCK_CNT];
+       struct vm_page_device_mdpage_head {
+               SLIST_HEAD(, vm_page_device_mdpage_entry) list;
+       } heads[MDPG_HASH_SIZE];
+};
+
+/* Global for now.  Consider to make this per-vm_physseg. */
+struct vm_page_device_mdpage vm_page_device_mdpage;
+
+static u_int
+vm_page_device_mdpage_hash(struct vm_page *pg)
+{
+
+       return VM_PAGE_DEVICE_TO_PHYS(pg);
+}
+
+static struct vm_page_device_mdpage_head *
+vm_page_device_mdpage_head(u_int hash)
+{
+
+       return &vm_page_device_mdpage.heads[hash % MDPG_HASH_SIZE];
+}
+
+static kmutex_t *
+vm_page_device_mdpage_lock(u_int hash)
+{
+
+       return &vm_page_device_mdpage.locks[hash % MDPG_HASH_LOCK_CNT];
+}
+
+void
+vm_page_device_mdpage_insert(struct vm_page *pg)
+{
+       paddr_t pf = VM_PAGE_DEVICE_TO_PHYS(pg);
+       u_int hash = vm_page_device_mdpage_hash(pg);
+       kmutex_t *lock = vm_page_device_mdpage_lock(hash);
+       struct vm_page_device_mdpage_head *head = vm_page_device_mdpage_head(hash);
+
+       struct vm_page_device_mdpage_entry *mde = kmem_zalloc(sizeof(*mde), KM_SLEEP);
+       mde->mde_pf = pf;
+
+       mutex_spin_enter(lock);
+       SLIST_INSERT_HEAD(&head->list, mde, mde_hash);
+       mutex_spin_exit(lock);
+}
+
+void
+vm_page_device_mdpage_remove(struct vm_page *pg)
+{
+       paddr_t pf = VM_PAGE_DEVICE_TO_PHYS(pg);
+       u_int hash = vm_page_device_mdpage_hash(pg);
+       kmutex_t *lock = vm_page_device_mdpage_lock(hash);
+       struct vm_page_device_mdpage_head *head = vm_page_device_mdpage_head(hash);
+
+       struct vm_page_device_mdpage_entry *mde;
+       struct vm_page_device_mdpage_entry *prev = NULL;
+
+       mutex_spin_enter(lock);
+       SLIST_FOREACH(mde, &head->list, mde_hash) {
+               if (mde->mde_pf == pf) {
+                       if (prev != NULL) {
+                               SLIST_REMOVE_AFTER(prev, mde_hash);
+                       } else {
+                               SLIST_REMOVE_HEAD(&head->list, mde_hash);
+                       }
+                       break;
+               }
+               prev = mde;
+       }
+       mutex_spin_exit(lock);
+       KASSERT(mde != NULL);
+       kmem_free(mde, sizeof(*mde));
+}
+
+struct vm_page_md *
+vm_page_device_mdpage_lookup(struct vm_page *pg)
+{
+       paddr_t pf = VM_PAGE_DEVICE_TO_PHYS(pg);
+       u_int hash = vm_page_device_mdpage_hash(pg);
+       kmutex_t *lock = vm_page_device_mdpage_lock(hash);
+       struct vm_page_device_mdpage_head *head = vm_page_device_mdpage_head(hash);
+
+       struct vm_page_device_mdpage_entry *mde;
+
+       mutex_spin_enter(lock);
+       SLIST_FOREACH(mde, &head->list, mde_hash)
+               if (mde->mde_pf == pf)
+                       break;
+       mutex_spin_exit(lock);
+       KASSERT(mde != NULL);
+       return &mde->mde_mdpage;
+}
+#endif
+
+
 /*
  * uvm_page_recolor: Recolor the pages if the new bucket count is
  * larger than the old one.
@@ -2094,7 +2237,7 @@
 {
 
        return
-#ifdef XIP
+#ifdef DEVICE_PAGE
            (vm_physseg_find_device(atop(pa), NULL) != -1) ||
 #endif
            (vm_physseg_find(atop(pa), NULL) != -1);
diff -r 02644391018e -r f9a7ab06802f sys/uvm/uvm_page.h
--- a/sys/uvm/uvm_page.h        Wed Feb 10 02:10:28 2010 +0000
+++ b/sys/uvm/uvm_page.h        Wed Feb 10 02:12:39 2010 +0000
@@ -1,4 +1,4 @@
-/*     $NetBSD: uvm_page.h,v 1.59.2.6 2010/02/09 13:06:17 uebayasi Exp $       */
+/*     $NetBSD: uvm_page.h,v 1.59.2.7 2010/02/10 02:12:39 uebayasi Exp $       */
 
 /*
  * Copyright (c) 1997 Charles D. Cranor and Washington University.
@@ -291,8 +291,10 @@
 void uvm_pagewire(struct vm_page *);
 void uvm_pagezero(struct vm_page *);
 bool uvm_pageismanaged(paddr_t);
-#ifdef XIP
+#ifdef DEVICE_PAGE
 bool uvm_pageisdevice_p(const struct vm_page *);
+#else
+#define        uvm_pageisdevice_p      false
 #endif
 
 int uvm_page_lookup_freelist(struct vm_page *);



Home | Main Index | Thread Index | Old Index