Source-Changes-HG archive

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

[src/sommerfeld_i386mp_1]: src/sys/arch/i386/i386 Preliminary TLB shootdown s...



details:   https://anonhg.NetBSD.org/src/rev/204ca13ff370
branches:  sommerfeld_i386mp_1
changeset: 482173:204ca13ff370
user:      sommerfeld <sommerfeld%NetBSD.org@localhost>
date:      Sun Feb 20 18:14:44 2000 +0000

description:
Preliminary TLB shootdown support.
In liu of previous deferred invalidation support, use TLB shootdown
queues even on uniprocessor.

Defer enabling global page support in CR4 until processor class has
been identified.  On a GENERIC kernel which includes 386 support,
turning on global page support before identifycpu has set cpu_class
results in stale global TLB entries which confuse the MP BIOS probe
code.

diffstat:

 sys/arch/i386/i386/pmap.c |  714 ++++++++++++++++++++++++++++++++++++++++-----
 1 files changed, 622 insertions(+), 92 deletions(-)

diffs (truncated from 1081 to 300 lines):

diff -r 95ee264e3cf9 -r 204ca13ff370 sys/arch/i386/i386/pmap.c
--- a/sys/arch/i386/i386/pmap.c Sun Feb 20 18:06:41 2000 +0000
+++ b/sys/arch/i386/i386/pmap.c Sun Feb 20 18:14:44 2000 +0000
@@ -1,4 +1,4 @@
-/*     $NetBSD: pmap.c,v 1.83 1999/12/11 19:39:31 sommerfeld Exp $     */
+/*     $NetBSD: pmap.c,v 1.83.2.1 2000/02/20 18:14:44 sommerfeld Exp $ */
 
 /*
  *
@@ -284,6 +284,54 @@
 
 #endif
 
+#ifndef I386_MAXPROCS
+#define I386_MAXPROCS 0
+#define cpu_number() 0
+#endif
+
+/*
+ * TLB Shootdown:
+ *
+ * When a mapping is changed in a pmap, the TLB entry corresponding to
+ * the virtual address must be invalidated on all processors.  In order
+ * to accomplish this on systems with multiple processors, messages are
+ * sent from the processor which performs the mapping change to all
+ * processors on which the pmap is active.  For other processors, the
+ * ASN generation numbers for that processor is invalidated, so that
+ * the next time the pmap is activated on that processor, a new ASN
+ * will be allocated (which implicitly invalidates all TLB entries).
+ *
+ * Note, we can use the pool allocator to allocate job entries
+ * since pool pages are mapped with K0SEG, not with the TLB.
+ */
+struct pmap_tlb_shootdown_job {
+       TAILQ_ENTRY(pmap_tlb_shootdown_job) pj_list;
+       vaddr_t pj_va;                  /* virtual address */
+       pmap_t pj_pmap;                 /* the pmap which maps the address */
+       pt_entry_t pj_pte;              /* the PTE bits */
+};
+
+struct pmap_tlb_shootdown_q {
+       TAILQ_HEAD(, pmap_tlb_shootdown_job) pq_head;
+       int pq_pte;                     /* aggregate PTE bits */
+       int pq_count;                   /* number of pending requests */
+       struct simplelock pq_slock;     /* spin lock on queue */
+       int pq_flushg;          /* pending flush global */
+       int pq_flushu;          /* pending flush user */
+} pmap_tlb_shootdown_q[I386_MAXPROCS];
+
+struct pool pmap_tlb_shootdown_job_pool;
+int pj_nentries, pj_nbytes;
+void *pj_page;
+
+void   pmap_tlb_shootdown_q_drain __P((struct pmap_tlb_shootdown_q *));
+struct pmap_tlb_shootdown_job *pmap_tlb_shootdown_job_get
+           __P((struct pmap_tlb_shootdown_q *));
+void   pmap_tlb_shootdown_job_put __P((struct pmap_tlb_shootdown_q *,
+           struct pmap_tlb_shootdown_job *));
+
+void pmap_tlb_shootnow __P((void));
+
 /*
  * global data structures
  */
@@ -406,13 +454,14 @@
 static void             pmap_free_pvpage __P((void));
 static struct vm_page  *pmap_get_ptp __P((struct pmap *, int, boolean_t));
 static boolean_t        pmap_is_curpmap __P((struct pmap *));
+static boolean_t        pmap_is_active __P((struct pmap *));
 static pt_entry_t      *pmap_map_ptes __P((struct pmap *));
 static struct pv_entry *pmap_remove_pv __P((struct pv_head *, struct pmap *,
                                             vaddr_t));
 static boolean_t        pmap_remove_pte __P((struct pmap *, struct vm_page *,
                                              pt_entry_t *, vaddr_t));
 static void             pmap_remove_ptes __P((struct pmap *,
-                                              struct pmap_remove_record *,
+                                              void *,
                                               struct vm_page *, vaddr_t,
                                               vaddr_t, vaddr_t));
 static struct vm_page  *pmap_steal_ptp __P((struct uvm_object *,
@@ -434,6 +483,13 @@
 void                   pmap_pinit __P((pmap_t));
 void                   pmap_release __P((pmap_t));
 
+static void            pmap_defer_flush __P((void *prr,
+                                        struct pmap *pmap,
+                                        vaddr_t va, pt_entry_t));
+
+static void            pmap_flush_deferred __P((void *prr,
+                                        struct pmap *pmap));
+
 /*
  * p m a p   i n l i n e   h e l p e r   f u n c t i o n s
  */
@@ -452,6 +508,18 @@
 }
 
 /*
+ * pmap_is_active: is this pmap loaded into any processor's %cr3?
+ *             XXX we assume it is for now.  
+ */
+
+__inline static boolean_t
+pmap_is_active(pmap)
+       struct pmap *pmap;
+{
+       return((pmap == pmap_kernel()) || 1);
+}
+
+/*
  * pmap_tmpmap_pa: map a page in for tmp usage
  *
  * => returns with pmap_tmpptp_lock held
@@ -485,6 +553,13 @@
 #endif
        *ptp_pte = 0;           /* zap! */
        pmap_update_pg((vaddr_t)ptpp);
+#ifdef MULTIPROCESSOR
+       /*
+        * No need for tlb shootdown here, since ptp_pte is protected by
+        * pmap_tmpptp_lock.
+        * XXX MP is this true, given potential prefetching?
+        */
+#endif
        simple_unlock(&pmap_tmpptp_lock);
 }
 
@@ -566,8 +641,10 @@
        opde = *APDP_PDE;
        if (!pmap_valid_entry(opde) || (opde & PG_FRAME) != pmap->pm_pdirpa) {
                *APDP_PDE = (pd_entry_t) (pmap->pm_pdirpa | PG_RW | PG_V);
-               if (pmap_valid_entry(opde))
+               if (pmap_valid_entry(opde)) {
                        pmap_update();
+                       /* XXX MP do invalidate on all cpu's touching this pmap */
+               }
        }
        return(APTE_BASE);
 }
@@ -586,6 +663,11 @@
        if (pmap_is_curpmap(pmap)) {
                simple_unlock(&pmap->pm_obj.vmobjlock);
        } else {
+#if 0
+               *APDP_PDE = 0;
+               pmap_update();
+               /* XXX MP need floosh here? */
+#endif
                simple_unlock(&pmap->pm_obj.vmobjlock);
                simple_unlock(&curpcb->pcb_pmap->pm_obj.vmobjlock);
        }
@@ -618,8 +700,12 @@
        opte = *pte;
        *pte = pa | ((prot & VM_PROT_WRITE)? PG_RW : PG_RO) |
                PG_V | pmap_pg_g;       /* zap! */
-       if (pmap_valid_entry(opte))
+       if (pmap_valid_entry(opte)) {
                pmap_update_pg(va);
+#ifdef MULTIPROCESSOR
+               pmap_tlb_shootdown(pmap_kernel(), va, opte);
+#endif
+       }
 }
 
 /*
@@ -638,21 +724,30 @@
        vaddr_t va;
        vsize_t len;
 {
-       pt_entry_t *pte;
+       pt_entry_t *pte, opte;
 
        len >>= PAGE_SHIFT;
        for ( /* null */ ; len ; len--, va += NBPG) {
                pte = vtopte(va);
+               /* XXX R/M update goo? */
+               opte = *pte;
+               *pte = 0;               /* zap! */
 #ifdef DIAGNOSTIC
-               if (*pte & PG_PVLIST)
+               if (opte & PG_PVLIST)
                        panic("pmap_kremove: PG_PVLIST mapping for 0x%lx\n",
                              va);
 #endif
-               *pte = 0;               /* zap! */
+
 #if defined(I386_CPU)
                if (cpu_class != CPUCLASS_386)
 #endif
+               {
                        pmap_update_pg(va);
+#ifdef MULTIPROCESSOR
+                       pmap_tlb_shootdown(pmap_kernel(), va, opte);
+#endif
+               }
+               
        }
 #if defined(I386_CPU)
        if (cpu_class == CPUCLASS_386)
@@ -680,6 +775,7 @@
        for (lcv = 0 ; lcv < npgs ; lcv++) {
                tva = va + lcv * NBPG;
                pte = vtopte(tva);
+               /* XXX pte update goo? R/M bits? */
                opte = *pte;
                *pte = VM_PAGE_TO_PHYS(pgs[lcv]) | PG_RW | PG_V | pmap_pg_g;
 #if defined(I386_CPU)
@@ -689,8 +785,12 @@
                        continue;
                }
 #endif
-               if (pmap_valid_entry(opte))
+               if (pmap_valid_entry(opte)) {
                        pmap_update_pg(tva);
+#ifdef MULTIPROCESSOR
+                       pmap_tlb_shootdown(pmap_kernel(), va, opte);
+#endif
+               }
        }
 #if defined(I386_CPU)
        if (need_update && cpu_class == CPUCLASS_386)
@@ -726,6 +826,7 @@
        vaddr_t kva;
        pt_entry_t *pte;
        int first16q;
+       int i;
 
        /*
         * set the page size (default value is 4K which is ok)
@@ -801,12 +902,18 @@
        curpcb->pcb_pmap = kpm; /* proc0's pcb */
 
        /*
-        * enable global TLB entries if they are supported
+        * Begin to enable global TLB entries if they are supported.
+        * The G bit has no effect until the CR4_PGE bit is set in CR4,
+        * which happens in cpu_init(), which is run on each cpu
+        * (and happens later)
         */
 
        if (cpu_feature & CPUID_PGE) {
+               pmap_pg_g = PG_G;               /* enable software */
+
+#if 0
                lcr4(rcr4() | CR4_PGE); /* enable hardware (via %cr4) */
-               pmap_pg_g = PG_G;               /* enable software */
+#endif
 
                /* add PG_G attribute to already mapped kernel pages */
                for (kva = VM_MIN_KERNEL_ADDRESS ; kva < virtual_avail ;
@@ -919,6 +1026,22 @@
        }
 
        /*
+        * Initialize the TLB shootdown queues.
+        */
+
+       pool_init(&pmap_tlb_shootdown_job_pool,
+           sizeof(struct pmap_tlb_shootdown_job),
+           0,                  /* align.  XXX cache-line align these?? */
+           0,                  /* ioff */
+           PR_STATIC,
+           "pmaptlbpl",
+           0, NULL, NULL, M_VMPMAP);
+       for (i = 0; i < I386_MAXPROCS; i++) {
+               TAILQ_INIT(&pmap_tlb_shootdown_q[i].pq_head);
+               simple_lock_init(&pmap_tlb_shootdown_q[i].pq_slock);
+       }
+
+       /*
         * ensure the TLB is sync'd with reality by flushing it...
         */
 
@@ -987,6 +1110,20 @@
        (void) pmap_add_pvpage(pv_initpage, FALSE);
 
        /*
+        * Prime the TLB shootdown job pool.
+        */
+       pj_nentries = pmap_tlb_shootdown_job_pool.pr_itemsperpage;
+       pj_nbytes =  pmap_tlb_shootdown_job_pool.pr_pagesz;
+       printf("%d pool entries; page size %d\n", pj_nentries, pj_nbytes);
+       pj_page = (void *)uvm_km_alloc (kernel_map, pj_nbytes);
+       if (pj_page == NULL)
+               panic("pmap_init: pj_page");
+       pool_prime (&pmap_tlb_shootdown_job_pool, pj_nentries, pj_page);
+       pool_setlowat(&pmap_tlb_shootdown_job_pool, 0);
+       pool_sethiwat(&pmap_tlb_shootdown_job_pool, pj_nentries);
+       pool_sethardlimit(&pmap_tlb_shootdown_job_pool, pj_nentries, 0, 0);
+
+       /*
         * done: pmap module is up (and ready for business)
         */
 
@@ -1240,9 +1377,15 @@
        if (*ptep & PG_W) {
                ptep = NULL;    /* wired page, avoid stealing this one */
        } else {
+#ifdef MULTIPROCESSOR
+               pt_entry_t opte = *ptep;



Home | Main Index | Thread Index | Old Index