Module Name: src Committed By: matt Date: Fri Dec 23 22:31:30 UTC 2011
Modified Files: src/sys/arch/mips/conf [matt-nb5-mips64]: files.mips src/sys/arch/mips/include [matt-nb5-mips64]: pmap.h src/sys/arch/mips/mips [matt-nb5-mips64]: pmap.c pmap_tlb.c Added Files: src/sys/arch/mips/mips [matt-nb5-mips64]: pmap_syncicache.c Log Message: Split syncicache functions into separate file: pmap_syncicache. Support up to 1024 ASIDs. Always use atomic ops for manipulating pm_shootdown_pending Nuke PMAP_POOLPAGE_DEBUG defparam MIPS_PAGE_SHIFT Track colors of execpages. To generate a diff of this commit: cvs rdiff -u -r1.58.24.17 -r1.58.24.18 src/sys/arch/mips/conf/files.mips cvs rdiff -u -r1.54.26.19 -r1.54.26.20 src/sys/arch/mips/include/pmap.h cvs rdiff -u -r1.179.16.34 -r1.179.16.35 src/sys/arch/mips/mips/pmap.c cvs rdiff -u -r0 -r1.1.2.1 src/sys/arch/mips/mips/pmap_syncicache.c cvs rdiff -u -r1.1.2.20 -r1.1.2.21 src/sys/arch/mips/mips/pmap_tlb.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/mips/conf/files.mips diff -u src/sys/arch/mips/conf/files.mips:1.58.24.17 src/sys/arch/mips/conf/files.mips:1.58.24.18 --- src/sys/arch/mips/conf/files.mips:1.58.24.17 Fri Dec 2 00:01:37 2011 +++ src/sys/arch/mips/conf/files.mips Fri Dec 23 22:31:30 2011 @@ -3,8 +3,6 @@ defflag opt_cputype.h NOFPU FPEMUL MIPS64_SB1 - ENABLE_MIPS_16KB_PAGE - ENABLE_MIPS_8KB_PAGE ENABLE_MIPS_KSEGX MIPS64_XLP MIPS64_XLR MIPS64_XLS # and the rest... @@ -15,9 +13,10 @@ defflag opt_cputype.h NOFPU FPEMUL # ENABLE_MIPS_TX3900 # ENABLE_MIPS_R4700 # ENABLE_MIPS_R3NKK -defflag opt_mips_cache.h MIPS3_NO_PV_UNCACHED - ENABLE_MIPS4_CACHE_R10K -defflag opt_mips3_wired.h ENABLE_MIPS3_WIRED_MAP +defparam opt_cputype.h MIPS_PAGE_SHIFT +defflag opt_mips_cache.h MIPS3_NO_PV_UNCACHED + ENABLE_MIPS4_CACHE_R10K +defflag opt_mips3_wired.h ENABLE_MIPS3_WIRED_MAP defflag opt_ddb.h DDB_TRACE defflag opt_ddb.h MIPS_DDB_WATCH @@ -47,6 +46,7 @@ file arch/mips/mips/kgdb_machdep.c kgdb file arch/mips/mips/mem.c file arch/mips/mips/pmap.c file arch/mips/mips/pmap_segtab.c +file arch/mips/mips/pmap_syncicache.c file arch/mips/mips/pmap_tlb.c file arch/mips/mips/trap.c # trap handlers file arch/mips/mips/syscall.c # syscall entries Index: src/sys/arch/mips/include/pmap.h diff -u src/sys/arch/mips/include/pmap.h:1.54.26.19 src/sys/arch/mips/include/pmap.h:1.54.26.20 --- src/sys/arch/mips/include/pmap.h:1.54.26.19 Sat Dec 3 01:56:55 2011 +++ src/sys/arch/mips/include/pmap.h Fri Dec 23 22:31:30 2011 @@ -1,4 +1,4 @@ -/* $NetBSD: pmap.h,v 1.54.26.19 2011/12/03 01:56:55 matt Exp $ */ +/* $NetBSD: pmap.h,v 1.54.26.20 2011/12/23 22:31:30 matt Exp $ */ /* * Copyright (c) 1992, 1993 @@ -201,25 +201,26 @@ struct pmap_tlb_info { uint32_t ti_asid_mask; uint32_t ti_asid_max; LIST_HEAD(, pmap_asid_info) ti_pais; /* list of active ASIDs */ + uint32_t ti_syncicache_bitmap; /* page indices needing a syncicache */ + struct evcnt ti_evcnt_syncicache_asts; + struct evcnt ti_evcnt_syncicache_all; + struct evcnt ti_evcnt_syncicache_pages; + struct evcnt ti_evcnt_syncicache_desired; + struct evcnt ti_evcnt_syncicache_duplicate; #ifdef MULTIPROCESSOR kmutex_t *ti_hwlock; pmap_t ti_victim; - uint32_t ti_synci_page_bitmap; /* page indices needing a syncicache */ uint32_t ti_cpu_mask; /* bitmask of CPUs sharing this TLB */ enum tlb_invalidate_op ti_tlbinvop; u_int ti_index; #define tlbinfo_index(ti) ((ti)->ti_index) - struct evcnt ti_evcnt_synci_asts; - struct evcnt ti_evcnt_synci_all; - struct evcnt ti_evcnt_synci_pages; - struct evcnt ti_evcnt_synci_deferred; - struct evcnt ti_evcnt_synci_desired; - struct evcnt ti_evcnt_synci_duplicate; + struct evcnt ti_evcnt_syncipage_deferred; #else #define tlbinfo_index(ti) (0) #endif struct evcnt ti_evcnt_asid_reinits; - u_long ti_asid_bitmap[256 / (sizeof(u_long) * 8)]; + struct evcnt ti_evcnt_asid_reclaims; + u_long ti_asid_bitmap[1024 / (sizeof(u_long) * 8)]; }; #ifdef _KERNEL @@ -237,6 +238,8 @@ extern struct pmap_tlb_info pmap_tlb0_in extern struct pmap_tlb_info *pmap_tlbs[MAXCPUS]; extern u_int pmap_ntlbs; #endif +extern u_int pmap_syncipage_page_mask; +extern u_int pmap_syncipage_map_mask; extern paddr_t mips_avail_start; extern paddr_t mips_avail_end; extern vaddr_t mips_virtual_end; @@ -261,10 +264,12 @@ void pmap_procwr(struct proc *, vaddr_t, void pmap_tlb_shootdown_process(void); bool pmap_tlb_shootdown_bystanders(pmap_t pmap); void pmap_tlb_info_attach(struct pmap_tlb_info *, struct cpu_info *); -void pmap_tlb_syncicache_ast(struct cpu_info *); -void pmap_tlb_syncicache_wanted(struct cpu_info *); -void pmap_tlb_syncicache(vaddr_t, uint32_t); +void pmap_syncicache_wanted(struct cpu_info *); +void pmap_syncicache(uint32_t, uint32_t); #endif +void pmap_syncicache_page(struct vm_page *, uint32_t); +void pmap_syncicache_init(void); +void pmap_syncicache_ast(struct cpu_info *); void pmap_tlb_info_init(struct pmap_tlb_info *); void pmap_tlb_info_evcnt_attach(struct pmap_tlb_info *); void pmap_tlb_asid_acquire(pmap_t pmap, struct lwp *l); Index: src/sys/arch/mips/mips/pmap.c diff -u src/sys/arch/mips/mips/pmap.c:1.179.16.34 src/sys/arch/mips/mips/pmap.c:1.179.16.35 --- src/sys/arch/mips/mips/pmap.c:1.179.16.34 Fri Dec 16 23:15:39 2011 +++ src/sys/arch/mips/mips/pmap.c Fri Dec 23 22:31:30 2011 @@ -279,15 +279,6 @@ vaddr_t mips_virtual_end; /* VA of last pt_entry_t *Sysmap; /* kernel pte table */ unsigned int Sysmapsize; /* number of pte's in Sysmap */ -#ifdef PMAP_POOLPAGE_DEBUG -struct poolpage_info { - vaddr_t base; - vaddr_t size; - vaddr_t hint; - pt_entry_t *sysmap; -} poolpage; -#endif - static void pmap_pvlist_lock_init(void); /* @@ -367,38 +358,6 @@ pmap_set_mdpage_attributes(struct vm_pag #endif } -static inline void -pmap_page_syncicache(struct vm_page *pg) -{ - struct vm_page_md * const md = VM_PAGE_TO_MD(pg); -#ifdef MULTIPROCESSOR - pv_entry_t pv = &md->pvh_first; - uint32_t onproc = 0; - (void)PG_MD_PVLIST_LOCK(md, false); - if (pv->pv_pmap != NULL) { - for (; pv != NULL; pv = pv->pv_next) { - onproc |= pv->pv_pmap->pm_onproc; - if (onproc == cpus_running) - break; - } - } - PG_MD_PVLIST_UNLOCK(md); - kpreempt_disable(); - pmap_tlb_syncicache(md->pvh_first.pv_va, onproc); - kpreempt_enable(); -#else - if (MIPS_HAS_R4K_MMU) { - if (PG_MD_CACHED_P(md)) { - mips_icache_sync_range_index( - md->pvh_first.pv_va, PAGE_SIZE); - } - } else { - mips_icache_sync_range(MIPS_PHYS_TO_KSEG0(VM_PAGE_TO_PHYS(pg)), - PAGE_SIZE); - } -#endif -} - static vaddr_t pmap_map_ephemeral_page(struct vm_page *pg, int prot, pt_entry_t *old_pt_entry_p) { @@ -501,6 +460,8 @@ pmap_bootstrap(void) if (MIPS_CACHE_VIRTUAL_ALIAS && uvmexp.ncolors) pmap_page_colormask = (uvmexp.ncolors - 1) << PAGE_SHIFT; + KASSERT(uvmexp.ncolors <= 16 - PG_MD_EXECPAGE_SHIFT); + pmap_tlb_info_init(&pmap_tlb0_info); /* init the lock */ #ifdef ENABLE_MIPS_KSEGX @@ -547,10 +508,6 @@ pmap_bootstrap(void) #ifdef KSEG2IOBUFSIZE Sysmapsize += (KSEG2IOBUFSIZE >> PGSHIFT); #endif -#ifdef PMAP_POOLPAGE_DEBUG - poolpage.size = nkmempages + MCLBYTES * nmbclusters; - Sysmapsize += poolpage.size; -#endif #ifdef _LP64 /* * If we are using tmpfs, then we might want to use a great deal of @@ -586,7 +543,11 @@ pmap_bootstrap(void) } #endif - if (mips_virtual_end > VM_MAX_KERNEL_ADDRESS) { + if (mips_virtual_end > VM_MAX_KERNEL_ADDRESS + || mips_virtual_end < VM_MIN_KERNEL_ADDRESS) { + printf("%s: chaning last kernel VA from %#"PRIxVADDR + " to %#"PRIxVADDR"\n", __func__, + mips_virtual_end, VM_MAX_KERNEL_ADDRESS); mips_virtual_end = VM_MAX_KERNEL_ADDRESS; Sysmapsize = (VM_MAX_KERNEL_ADDRESS - VM_MIN_KERNEL_ADDRESS) / NBPG; @@ -601,11 +562,6 @@ pmap_bootstrap(void) Sysmap = (pt_entry_t *) uvm_pageboot_alloc(sizeof(pt_entry_t) * Sysmapsize); -#ifdef PMAP_POOLPAGE_DEBUG - mips_virtual_end -= poolpage.size; - poolpage.base = mips_virtual_end; - poolpage.sysmap = Sysmap + atop(poolpage.size); -#endif /* * Initialize the pools. */ @@ -1151,7 +1107,7 @@ pmap_page_protect(struct vm_page *pg, vm * Do this first so that for each unmapping, pmap_remove_pv * won't try to sync the icache. */ - if (pmap_clear_mdpage_attributes(md, PG_MD_EXECPAGE)) { + if (pmap_clear_mdpage_attributes(md, PG_MD_EXECPAGE_ANY)) { PMAP_COUNT(exec_uncached_page_protect); } (void)PG_MD_PVLIST_LOCK(md, false); @@ -1190,10 +1146,11 @@ pmap_pte_protect(pmap_t pmap, vaddr_t sv && MIPS_CACHE_VIRTUAL_ALIAS && PG_MD_CACHED_P(md)) mips_dcache_wbinv_range_index(sva, PAGE_SIZE); - if (PG_MD_EXECPAGE_P(md)) { + if (PG_MD_EXECPAGE_ANY_P(md)) { KASSERT(md->pvh_first.pv_pmap != NULL); if (PG_MD_CACHED_P(md)) { - pmap_page_syncicache(pg); + pmap_syncicache_page(pg, + PG_MD_EXECPAGES(md)); PMAP_COUNT(exec_synced_protect); } } @@ -1550,10 +1507,10 @@ pmap_enter(pmap_t pmap, vaddr_t va, padd && prot == (VM_PROT_READ | VM_PROT_EXECUTE)) { struct vm_page_md * const md = VM_PAGE_TO_MD(pg); PMAP_COUNT(enter_exec_mapping); - if (!PG_MD_EXECPAGE_P(md)) { + if (!PG_MD_EXECPAGE_P(md, va)) { mips_icache_sync_range(MIPS_PHYS_TO_KSEG0(pa), PAGE_SIZE); - pmap_set_mdpage_attributes(md, PG_MD_EXECPAGE); + pmap_set_mdpage_attributes(md, PG_MD_EXECPAGE(va)); PMAP_COUNT(exec_syncicache_entry); } } @@ -1679,9 +1636,9 @@ pmap_enter(pmap_t pmap, vaddr_t va, padd va - NBPG, pa); #endif PMAP_COUNT(exec_mappings); - if (!PG_MD_EXECPAGE_P(md) && PG_MD_CACHED_P(md)) { - pmap_page_syncicache(pg); - pmap_set_mdpage_attributes(md, PG_MD_EXECPAGE); + if (!PG_MD_EXECPAGE_P(md, va) && PG_MD_CACHED_P(md)) { + pmap_set_mdpage_attributes(md, PG_MD_EXECPAGE(va)); + pmap_syncicache_page(pg, PG_MD_EXECPAGE(va)); PMAP_COUNT(exec_synced_mappings); } } @@ -2061,12 +2018,12 @@ pmap_clear_modify(struct vm_page *pg) if (pmapdebug & PDB_FOLLOW) printf("pmap_clear_modify(%#"PRIxPADDR")\n", VM_PAGE_TO_PHYS(pg)); #endif - if (PG_MD_EXECPAGE_P(md)) { + if (PG_MD_EXECPAGE_ANY_P(md)) { if (pv->pv_pmap == NULL) { - pmap_clear_mdpage_attributes(md, PG_MD_EXECPAGE); + pmap_clear_mdpage_attributes(md, PG_MD_EXECPAGE_ANY); PMAP_COUNT(exec_uncached_clear_modify); } else { - pmap_page_syncicache(pg); + pmap_syncicache_page(pg, PG_MD_EXECPAGES(md)); PMAP_COUNT(exec_synced_clear_modify); } } @@ -2319,7 +2276,7 @@ again: pmap, va); #endif if (__predict_true(apv == NULL)) { -#if defined(MULTIPROCESSOR) || !defined(_LP64) || defined(PMAP_POOLPAGE_DEBUG) || defined(LOCKDEBUG) +#if defined(MULTIPROCESSOR) || !defined(_LP64) || defined(LOCKDEBUG) /* * To allocate a PV, we have to release the PVLIST lock * so get the page generation. We allocate the PV, and @@ -2330,7 +2287,7 @@ again: apv = (pv_entry_t)pmap_pv_alloc(); if (apv == NULL) panic("pmap_enter_pv: pmap_pv_alloc() failed"); -#if defined(MULTIPROCESSOR) || !defined(_LP64) || defined(PMAP_POOLPAGE_DEBUG) || defined(LOCKDEBUG) +#if defined(MULTIPROCESSOR) || !defined(_LP64) || defined(LOCKDEBUG) #ifdef MULTIPROCESSOR /* * If the generation has changed, then someone else @@ -2439,20 +2396,20 @@ pmap_remove_pv(pmap_t pmap, vaddr_t va, */ if (npv) pmap_pv_free(npv); - if (PG_MD_EXECPAGE_P(md) && dirty) { + if (PG_MD_EXECPAGE_P(md, va) && dirty) { if (last) { /* * If this was the page's last mapping, we no longer * care about its execness. */ - pmap_clear_mdpage_attributes(md, PG_MD_EXECPAGE); + pmap_clear_mdpage_attributes(md, PG_MD_EXECPAGE_ANY); PMAP_COUNT(exec_uncached_remove); } else { /* * Someone still has it mapped as an executable page * so we must sync it. */ - pmap_page_syncicache(pg); + pmap_syncicache_page(pg, PG_MD_EXECPAGES(md)); PMAP_COUNT(exec_synced_remove); } } @@ -2660,31 +2617,6 @@ mips_pmap_map_poolpage(paddr_t pa) struct vm_page_md * const md = VM_PAGE_TO_MD(pg); pmap_set_mdpage_attributes(md, PG_MD_POOLPAGE); -#ifdef PMAP_POOLPAGE_DEBUG - KASSERT((poolpage.hint & MIPS_CACHE_ALIAS_MASK) == 0); - vaddr_t va_offset = poolpage.hint + mips_cache_indexof(pa); - pt_entry_t *pte = poolpage.sysmap + atop(va_offset); - const size_t va_inc = MIPS_CACHE_ALIAS_MASK + PAGE_SIZE; - const size_t pte_inc = atop(va_inc); - - for (; va_offset < poolpage.size; - va_offset += va_inc, pte += pte_inc) { - if (!mips_pg_v(pte->pt_entry)) - break; - } - if (va_offset >= poolpage.size) { - for (va_offset -= poolpage.size, pte -= atop(poolpage.size); - va_offset < poolpage.hint; - va_offset += va_inc, pte += pte_inc) { - if (!mips_pg_v(pte->pt_entry)) - break; - } - } - KASSERT(!mips_pg_v(pte->pt_entry)); - va = poolpage.base + va_offset; - poolpage.hint = roundup2(va_offset + 1, va_inc); - pmap_kenter_pa(va, pa, VM_PROT_READ|VM_PORT_WRITE); -#else #ifdef _LP64 KASSERT(mips_options.mips3_xkphys_cached); va = MIPS_PHYS_TO_XKPHYS_CACHED(pa); @@ -2700,8 +2632,7 @@ mips_pmap_map_poolpage(paddr_t pa) else va = MIPS_PHYS_TO_KSEG0(pa); #endif -#endif -#if !defined(_LP64) || defined(PMAP_POOLPAGE_DEBUG) +#if !defined(_LP64) if (MIPS_CACHE_VIRTUAL_ALIAS) { /* * If this page was last mapped with an address that might @@ -2724,10 +2655,7 @@ paddr_t mips_pmap_unmap_poolpage(vaddr_t va) { paddr_t pa; -#ifdef PMAP_POOLPAGE_DEBUG - KASSERT(poolpage.base <= va && va < poolpage.base + poolpage.size); - pa = mips_tlbpfn_to_paddr(kvtopte(va)->pt_entry); -#elif defined(_LP64) +#if defined(_LP64) KASSERT(MIPS_XKPHYS_P(va)); pa = MIPS_XKPHYS_TO_PHYS(va); #else @@ -2752,9 +2680,6 @@ mips_pmap_unmap_poolpage(vaddr_t va) mips_dcache_inv_range(va, PAGE_SIZE); } #endif -#ifdef PMAP_POOLPAGE_DEBUG - pmap_kremove(va, PAGE_SIZE); -#endif return pa; } Index: src/sys/arch/mips/mips/pmap_tlb.c diff -u src/sys/arch/mips/mips/pmap_tlb.c:1.1.2.20 src/sys/arch/mips/mips/pmap_tlb.c:1.1.2.21 --- src/sys/arch/mips/mips/pmap_tlb.c:1.1.2.20 Tue Dec 6 17:49:34 2011 +++ src/sys/arch/mips/mips/pmap_tlb.c Fri Dec 23 22:31:30 2011 @@ -1,4 +1,4 @@ -/* $NetBSD: pmap_tlb.c,v 1.1.2.20 2011/12/06 17:49:34 matt Exp $ */ +/* $NetBSD: pmap_tlb.c,v 1.1.2.21 2011/12/23 22:31:30 matt Exp $ */ /*- * Copyright (c) 2010 The NetBSD Foundation, Inc. @@ -31,7 +31,7 @@ #include <sys/cdefs.h> -__KERNEL_RCSID(0, "$NetBSD: pmap_tlb.c,v 1.1.2.20 2011/12/06 17:49:34 matt Exp $"); +__KERNEL_RCSID(0, "$NetBSD: pmap_tlb.c,v 1.1.2.21 2011/12/23 22:31:30 matt Exp $"); /* * Manages address spaces in a TLB. @@ -170,8 +170,6 @@ struct pmap_tlb_info *pmap_tlbs[MAXCPUS] [0] = &pmap_tlb0_info, }; u_int pmap_ntlbs = 1; -u_int pmap_tlb_synci_page_mask; -u_int pmap_tlb_synci_map_mask; #endif #define __BITMAP_SET(bm, n) \ ((bm)[(n) / (8*sizeof(bm[0]))] |= 1LU << ((n) % (8*sizeof(bm[0])))) @@ -223,34 +221,38 @@ pmap_pai_reset(struct pmap_tlb_info *ti, void pmap_tlb_info_evcnt_attach(struct pmap_tlb_info *ti) { -#ifdef MULTIPROCESSOR - evcnt_attach_dynamic(&ti->ti_evcnt_synci_desired, + evcnt_attach_dynamic(&ti->ti_evcnt_syncicache_desired, EVCNT_TYPE_MISC, NULL, ti->ti_name, "icache syncs desired"); - evcnt_attach_dynamic(&ti->ti_evcnt_synci_asts, - EVCNT_TYPE_MISC, &ti->ti_evcnt_synci_desired, + evcnt_attach_dynamic(&ti->ti_evcnt_syncicache_asts, + EVCNT_TYPE_MISC, &ti->ti_evcnt_syncicache_desired, ti->ti_name, "icache sync asts"); - evcnt_attach_dynamic(&ti->ti_evcnt_synci_all, - EVCNT_TYPE_MISC, &ti->ti_evcnt_synci_asts, + evcnt_attach_dynamic(&ti->ti_evcnt_syncicache_all, + EVCNT_TYPE_MISC, &ti->ti_evcnt_syncicache_asts, ti->ti_name, "icache full syncs"); - evcnt_attach_dynamic(&ti->ti_evcnt_synci_pages, - EVCNT_TYPE_MISC, &ti->ti_evcnt_synci_asts, + evcnt_attach_dynamic(&ti->ti_evcnt_syncicache_pages, + EVCNT_TYPE_MISC, &ti->ti_evcnt_syncicache_asts, ti->ti_name, "icache pages synced"); - evcnt_attach_dynamic(&ti->ti_evcnt_synci_duplicate, - EVCNT_TYPE_MISC, &ti->ti_evcnt_synci_desired, + evcnt_attach_dynamic(&ti->ti_evcnt_syncicache_duplicate, + EVCNT_TYPE_MISC, &ti->ti_evcnt_syncicache_desired, ti->ti_name, "icache dup pages skipped"); - evcnt_attach_dynamic(&ti->ti_evcnt_synci_deferred, - EVCNT_TYPE_MISC, &ti->ti_evcnt_synci_desired, +#ifdef MULTIPROCESSOR + evcnt_attach_dynamic(&ti->ti_evcnt_syncicache_deferred, + EVCNT_TYPE_MISC, &ti->ti_evcnt_syncicache_desired, ti->ti_name, "icache pages deferred"); #endif /* MULTIPROCESSOR */ evcnt_attach_dynamic(&ti->ti_evcnt_asid_reinits, EVCNT_TYPE_MISC, NULL, ti->ti_name, "asid pool reinit"); + evcnt_attach_dynamic(&ti->ti_evcnt_asid_reclaims, + EVCNT_TYPE_MISC, NULL, + ti->ti_name, "asid pool reclaims"); } void pmap_tlb_info_init(struct pmap_tlb_info *ti) { + const struct mips_options * const opts = &mips_options; #ifdef MULTIPROCESSOR if (ti == &pmap_tlb0_info) { #endif /* MULTIPROCESSOR */ @@ -259,8 +261,11 @@ pmap_tlb_info_init(struct pmap_tlb_info #ifdef MULTIPROCESSOR mutex_init(ti->ti_hwlock, MUTEX_DEFAULT, IPL_SCHED); #endif - if (!CPUISMIPSNN || !__builtin_constant_p(MIPS_TLB_NUM_PIDS)) { - ti->ti_asid_max = mips_options.mips_num_tlb_entries - 1; + KASSERT(opts->mips_num_tlb_asids > 0); + if (!CPUISMIPSNN || !__builtin_constant_p(MIPS_TLB_NUM_PIDS) + || ti->ti_asid_max != opts->mips_num_tlb_asids - 1) { + KASSERT(ti->ti_asid_max + 1 <= sizeof(ti->ti_asid_bitmap)*8); + ti->ti_asid_max = opts->mips_num_tlb_asids - 1; ti->ti_asids_free = ti->ti_asid_max; ti->ti_asid_mask = ti->ti_asid_max; /* @@ -271,16 +276,7 @@ pmap_tlb_info_init(struct pmap_tlb_info ti->ti_asid_mask |= ti->ti_asid_mask >> 1; } } -#ifdef MULTIPROCESSOR - const u_int icache_way_pages = - mips_cache_info.mci_picache_way_size >> PGSHIFT; - KASSERT(icache_way_pages <= 8*sizeof(pmap_tlb_synci_page_mask)); - pmap_tlb_synci_page_mask = icache_way_pages - 1; - pmap_tlb_synci_map_mask = ~(~0 << icache_way_pages); - printf("tlb0: synci page mask %#x and map mask %#x used for %u pages\n", - pmap_tlb_synci_page_mask, pmap_tlb_synci_map_mask, - icache_way_pages); -#endif + pmap_syncicache_init(); return; #ifdef MULTIPROCESSOR } @@ -372,13 +368,20 @@ pmap_tlb_asid_reinitialize(struct pmap_t ti->ti_asid_bitmap[0] = 1; for (size_t word = 1; word <= asid_bitmap_words; word++) ti->ti_asid_bitmap[word] = 0; +#ifdef DIAGNOSTIC + for (size_t word = asid_bitmap_words + 1; + word < __arraycount(ti->ti_asid_bitmap); + word++) { + KASSERT(ti->ti_asid_bitmap[word] == 0); + } +#endif switch (op) { case TLBINV_ALL: tlb_invalidate_all(); break; case TLBINV_ALLUSER: - tlb_invalidate_asids(1, ti->ti_asid_mask); + tlb_invalidate_asids(1, ti->ti_asid_max + 1); break; case TLBINV_NOBODY: { /* @@ -396,11 +399,13 @@ pmap_tlb_asid_reinitialize(struct pmap_t pmap_tlb_asid_check(); KASSERT(asids_found == pmap_tlb_asid_count(ti)); if (__predict_false(asids_found >= ti->ti_asid_max / 2)) { - tlb_invalidate_asids(1, ti->ti_asid_mask); + tlb_invalidate_asids(1, ti->ti_asid_max + 1); + ti->ti_evcnt_asid_reinits.ev_count++; ti->ti_asid_bitmap[0] = 1; for (size_t word = 1; word <= asid_bitmap_words; word++) ti->ti_asid_bitmap[word] = 0; } else { + ti->ti_evcnt_asid_reclaims.ev_count++; ti->ti_asids_free -= asids_found; } break; @@ -643,7 +648,7 @@ pmap_tlb_update_addr(pmap_t pm, vaddr_t pmap_tlb_asid_check(); } #ifdef MULTIPROCESSOR - pm->pm_shootdown_pending = need_ipi; + atomic_or_uint(&pm->pm_shootdown_pending, need_ipi); #endif TLBINFO_UNLOCK(ti); @@ -666,7 +671,7 @@ pmap_tlb_invalidate_addr(pmap_t pm, vadd pmap_tlb_asid_check(); } #ifdef MULTIPROCESSOR - pm->pm_shootdown_pending = 1; + (void) atomic_swap_uint(&pm->pm_shootdown_pending, 1); #endif TLBINFO_UNLOCK(ti); } @@ -789,9 +794,9 @@ pmap_tlb_asid_acquire(pmap_t pm, struct * icache synched, make sure to do that before returning to * userland. */ - if (ti->ti_synci_page_bitmap) { + if (ti->ti_syncipage_page_bitmap) { l->l_md.md_astpending = 1; /* force call to ast() */ - ci->ci_evcnt_synci_activate_rqst.ev_count++; + ci->ci_evcnt_syncipage_activate_rqst.ev_count++; } atomic_or_ulong(&ci->ci_flags, CPUF_USERPMAP); #endif /* MULTIPROCESSOR */ @@ -879,160 +884,6 @@ pmap_tlb_asid_release_all(struct pmap *p #endif /* MULTIPROCESSOR */ } -#ifdef MULTIPROCESSOR -void -pmap_tlb_syncicache_ast(struct cpu_info *ci) -{ - struct pmap_tlb_info * const ti = ci->ci_tlb_info; - - kpreempt_disable(); - uint32_t page_bitmap = atomic_swap_32(&ti->ti_synci_page_bitmap, 0); -#if 0 - printf("%s: need to sync %#x\n", __func__, page_bitmap); -#endif - ti->ti_evcnt_synci_asts.ev_count++; - /* - * If every bit is set in the bitmap, sync the entire icache. - */ - if (page_bitmap == pmap_tlb_synci_map_mask) { - mips_icache_sync_all(); - ti->ti_evcnt_synci_all.ev_count++; - ti->ti_evcnt_synci_pages.ev_count += pmap_tlb_synci_page_mask+1; - kpreempt_enable(); - return; - } - - /* - * Loop through the bitmap clearing each set of indices for each page. - */ - for (vaddr_t va = 0; - page_bitmap != 0; - page_bitmap >>= 1, va += PAGE_SIZE) { - if (page_bitmap & 1) { - /* - * Each bit set represents a page to be synced. - */ - mips_icache_sync_range_index(va, PAGE_SIZE); - ti->ti_evcnt_synci_pages.ev_count++; - } - } - - kpreempt_enable(); -} - -void -pmap_tlb_syncicache(vaddr_t va, uint32_t page_onproc) -{ - KASSERT(kpreempt_disabled()); - /* - * We don't sync the icache here but let ast do it for us just before - * returning to userspace. We do this because we don't really know - * on which CPU we will return to userspace and if we synch the icache - * now it might not be on the CPU we need it on. In addition, others - * threads might sync the icache before we get to return to userland - * so there's no reason for us to do it. - * - * Each TLB/cache keeps a synci sequence number which gets advanced - * each that TLB/cache performs a mips_sync_icache_all. When we - * return to userland, we check the pmap's corresponding synci - * sequence number for that TLB/cache. If they match, it means that - * no one has yet synched the icache so we much do it ourselves. If - * they don't match someone has already synced the icache for us. - * - * There is a small chance that the generation numbers will wrap and - * then become equal but that's a one in 4 billion cache and will - * just cause an extra sync of the icache. - */ - const uint32_t cpu_mask = 1L << cpu_index(curcpu()); - const uint32_t page_mask = - 1L << ((va >> PGSHIFT) & pmap_tlb_synci_page_mask); - uint32_t onproc = 0; - for (size_t i = 0; i < pmap_ntlbs; i++) { - struct pmap_tlb_info * const ti = pmap_tlbs[0]; - TLBINFO_LOCK(ti); - for (;;) { - uint32_t old_page_bitmap = ti->ti_synci_page_bitmap; - if (old_page_bitmap & page_mask) { - ti->ti_evcnt_synci_duplicate.ev_count++; - break; - } - - uint32_t orig_page_bitmap = atomic_cas_32( - &ti->ti_synci_page_bitmap, old_page_bitmap, - old_page_bitmap | page_mask); - - if (orig_page_bitmap == old_page_bitmap) { - if (old_page_bitmap == 0) { - onproc |= ti->ti_cpu_mask; - } else { - ti->ti_evcnt_synci_deferred.ev_count++; - } - ti->ti_evcnt_synci_desired.ev_count++; - break; - } - } -#if 0 - printf("%s: %s: %x to %x on cpus %#x\n", __func__, - ti->ti_name, page_mask, ti->ti_synci_page_bitmap, - onproc & page_onproc & ti->ti_cpu_mask); -#endif - TLBINFO_UNLOCK(ti); - } - onproc &= page_onproc; - if (__predict_false(onproc != 0)) { - /* - * If the cpu need to sync this page, tell the current lwp - * to sync the icache before it returns to userspace. - */ - if (onproc & cpu_mask) { - if (curcpu()->ci_flags & CPUF_USERPMAP) { - curlwp->l_md.md_astpending = 1; /* force call to ast() */ - curcpu()->ci_evcnt_synci_onproc_rqst.ev_count++; - } else { - curcpu()->ci_evcnt_synci_deferred_rqst.ev_count++; - } - onproc ^= cpu_mask; - } - - /* - * For each cpu that is affect, send an IPI telling - * that CPU that the current thread needs to sync its icache. - * We might cause some spurious icache syncs but that's not - * going to break anything. - */ - for (u_int n = ffs(onproc); - onproc != 0; - onproc >>= n, onproc <<= n, n = ffs(onproc)) { - cpu_send_ipi(cpu_lookup(n-1), IPI_SYNCICACHE); - } - } -} - -void -pmap_tlb_syncicache_wanted(struct cpu_info *ci) -{ - struct pmap_tlb_info * const ti = ci->ci_tlb_info; - - KASSERT(cpu_intr_p()); - - TLBINFO_LOCK(ti); - - /* - * We might have been notified because another CPU changed an exec - * page and now needs us to sync the icache so tell the current lwp - * to do the next time it returns to userland (which should be very - * soon). - */ - if (ti->ti_synci_page_bitmap && (ci->ci_flags & CPUF_USERPMAP)) { - curlwp->l_md.md_astpending = 1; /* force call to ast() */ - ci->ci_evcnt_synci_ipi_rqst.ev_count++; - } - - TLBINFO_UNLOCK(ti); - -} -#endif /* MULTIPROCESSOR */ - void pmap_tlb_asid_check(void) { Added files: Index: src/sys/arch/mips/mips/pmap_syncicache.c diff -u /dev/null src/sys/arch/mips/mips/pmap_syncicache.c:1.1.2.1 --- /dev/null Fri Dec 23 22:31:30 2011 +++ src/sys/arch/mips/mips/pmap_syncicache.c Fri Dec 23 22:31:30 2011 @@ -0,0 +1,290 @@ +/* $NetBSD: pmap_syncicache.c,v 1.1.2.1 2011/12/23 22:31:30 matt Exp $ */ + +/*- + * Copyright (c) 2010 The NetBSD Foundation, Inc. + * All rights reserved. + * + * This code is derived from software contributed to The NetBSD Foundation + * by Matt Thomas at 3am Software Foundry. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#include <sys/cdefs.h> + +__KERNEL_RCSID(0, "$NetBSD: pmap_syncicache.c,v 1.1.2.1 2011/12/23 22:31:30 matt Exp $"); + +/* + * + */ + +#include "opt_multiprocessor.h" +#include "opt_sysv.h" +#include "opt_cputype.h" +#include "opt_mips_cache.h" +#include "opt_multiprocessor.h" + +#include <sys/param.h> +#include <sys/systm.h> +#include <sys/proc.h> +#include <sys/mutex.h> +#include <sys/atomic.h> +#include <sys/kernel.h> /* for cold */ +#include <sys/cpu.h> + +#include <uvm/uvm.h> + +#include <mips/cache.h> +#include <mips/cpuregs.h> +#include <mips/locore.h> +#include <mips/pte.h> + +u_int pmap_syncicache_page_mask; +u_int pmap_syncicache_map_mask; + +void +pmap_syncicache_init(void) +{ + const u_int icache_way_pages = + mips_cache_info.mci_picache_way_size >> PGSHIFT; + KASSERT(icache_way_pages <= 8*sizeof(pmap_syncicache_page_mask)); + pmap_syncicache_page_mask = icache_way_pages - 1; + KASSERT(pmap_syncicache_page_mask == atop(MIPS_ICACHE_ALIAS_MASK)); + pmap_syncicache_map_mask = ~(~0 << icache_way_pages); + KASSERT((pmap_syncicache_map_mask & ~(PG_MD_EXECPAGE_ANY >> PG_MD_EXECPAGE_SHIFT)) == 0); + printf("tlb0: synci page mask %#x and map mask %#x used for %u pages\n", + pmap_syncicache_page_mask, pmap_syncicache_map_mask, + icache_way_pages); +} + +void +pmap_syncicache_page(struct vm_page *pg, uint32_t colors) +{ + struct vm_page_md * const md = VM_PAGE_TO_MD(pg); +#ifdef MULTIPROCESSOR + pv_entry_t pv = &md->pvh_first; + uint32_t onproc = 0; + (void)PG_MD_PVLIST_LOCK(md, false); + if (pv->pv_pmap != NULL) { + for (; pv != NULL; pv = pv->pv_next) { + onproc |= pv->pv_pmap->pm_onproc; + if (onproc == cpus_running) + break; + } + } + PG_MD_PVLIST_UNLOCK(md); + kpreempt_disable(); + pmap_tlb_syncicache(colors & md->pvh_attrs, onproc); + kpreempt_enable(); +#else + if (!MIPS_HAS_R4K_MMU) { + mips_icache_sync_range(MIPS_PHYS_TO_KSEG0(VM_PAGE_TO_PHYS(pg)), + PAGE_SIZE); + } else if (PG_MD_CACHED_P(md)) { +#if 0 + struct cpu_info * const ci = curcpu(); + colors >>= PG_MD_EXECPAGE_SHIFT; + KASSERT(colors != 0); + + /* + * Record the colors to flushes the next time we return + * to userspace. + */ + u_int old = ci->ci_icache_badcolors; + atomic_or_uint(&ci->ci_icache_badcolors, colors); + if ((old & colors) == colors) { + ci->ci_evcnt_syncicache_duplicate.ev_count++; + } else { + ci->ci_evcnt_syncicache_desired.ev_count++; + } +#else + colors >>= PG_MD_EXECPAGE_SHIFT; + /* + * If not all the colors are in use, just flush the + * ones that are. + */ + for (vaddr_t va = MIPS_KSEG0_START; + colors != 0; + colors >>= 1, va += PAGE_SIZE) { + if (colors & 1) { + mips_icache_sync_range_index(va, PAGE_SIZE); + } + } +#endif + } +#endif +} + +void +pmap_syncicache_ast(struct cpu_info *ci) +{ + struct pmap_tlb_info * const ti = ci->ci_tlb_info; + + kpreempt_disable(); + uint32_t page_bitmap = atomic_swap_32(&ti->ti_syncicache_bitmap, 0); +#if 0 + printf("%s: need to sync %#x\n", __func__, page_bitmap); +#endif + ti->ti_evcnt_syncicache_asts.ev_count++; + /* + * If every bit is set in the bitmap, sync the entire icache. + */ + if (page_bitmap == pmap_syncicache_map_mask) { + mips_icache_sync_all(); + ti->ti_evcnt_syncicache_all.ev_count++; + ti->ti_evcnt_syncicache_pages.ev_count += pmap_syncicache_page_mask+1; + kpreempt_enable(); + return; + } + + /* + * Loop through the bitmap clearing each set of indices for each page. + */ + for (vaddr_t va = 0; + page_bitmap != 0; + page_bitmap >>= 1, va += PAGE_SIZE) { + if (page_bitmap & 1) { + /* + * Each bit set represents a page to be synced. + */ + mips_icache_sync_range_index(va, PAGE_SIZE); + ti->ti_evcnt_syncicache_pages.ev_count++; + } + } + + kpreempt_enable(); +} + +#ifdef MULTIPROCESSOR +void +pmap_syncicache(uint32_t colors, uint32_t page_onproc) +{ + KASSERT(kpreempt_disabled()); + /* + * We don't sync the icache here but let ast do it for us just before + * returning to userspace. We do this because we don't really know + * on which CPU we will return to userspace and if we synch the icache + * now it might not be on the CPU we need it on. In addition, others + * threads might sync the icache before we get to return to userland + * so there's no reason for us to do it. + * + * Each TLB/cache keeps a synci sequence number which gets advanced + * each that TLB/cache performs a mips_sync_icache_all. When we + * return to userland, we check the pmap's corresponding synci + * sequence number for that TLB/cache. If they match, it means that + * no one has yet synched the icache so we much do it ourselves. If + * they don't match someone has already synced the icache for us. + * + * There is a small chance that the generation numbers will wrap and + * then become equal but that's a one in 4 billion cache and will + * just cause an extra sync of the icache. + */ + const uint32_t cpu_mask = 1L << cpu_index(curcpu()); + const uint32_t page_mask = colors; + KASSERT((page_mask & ~pmap_syncicache_map_mask) == 0); + uint32_t onproc = 0; + for (size_t i = 0; i < pmap_ntlbs; i++) { + struct pmap_tlb_info * const ti = pmap_tlbs[0]; + TLBINFO_LOCK(ti); + for (;;) { + uint32_t old_page_bitmap = ti->ti_syncicache_bitmap; + + uint32_t orig_page_bitmap = atomic_cas_32( + &ti->ti_syncicache_bitmap, old_page_bitmap, + old_page_bitmap | page_mask); + + if ((orig_page_bitmap & page_mask) == page_mask) { + ti->ti_evcnt_syncicache_duplicate.ev_count++; + break; + } + + if (orig_page_bitmap == old_page_bitmap) { + if (old_page_bitmap == 0) { + onproc |= ti->ti_cpu_mask; + } else { + ti->ti_evcnt_syncicache_deferred.ev_count++; + } + ti->ti_evcnt_syncicache_desired.ev_count++; + break; + } + } +#if 0 + printf("%s: %s: %x to %x on cpus %#x\n", __func__, + ti->ti_name, page_mask, ti->ti_syncicache_bitmap, + onproc & page_onproc & ti->ti_cpu_mask); +#endif + TLBINFO_UNLOCK(ti); + } + onproc &= page_onproc; + if (__predict_false(onproc != 0)) { + /* + * If the cpu need to sync this page, tell the current lwp + * to sync the icache before it returns to userspace. + */ + if (onproc & cpu_mask) { + if (curcpu()->ci_flags & CPUF_USERPMAP) { + curlwp->l_md.md_astpending = 1; /* force call to ast() */ + curcpu()->ci_evcnt_syncicache_onproc_rqst.ev_count++; + } else { + curcpu()->ci_evcnt_syncicache_deferred_rqst.ev_count++; + } + onproc ^= cpu_mask; + } + + /* + * For each cpu that is affect, send an IPI telling + * that CPU that the current thread needs to sync its icache. + * We might cause some spurious icache syncs but that's not + * going to break anything. + */ + for (u_int n = ffs(onproc); + onproc != 0; + onproc >>= n, onproc <<= n, n = ffs(onproc)) { + cpu_send_ipi(cpu_lookup(n-1), IPI_SYNCICACHE); + } + } +} + +void +pmap_syncicache_wanted(struct cpu_info *ci) +{ + struct pmap_tlb_info * const ti = ci->ci_tlb_info; + + KASSERT(cpu_intr_p()); + + TLBINFO_LOCK(ti); + + /* + * We might have been notified because another CPU changed an exec + * page and now needs us to sync the icache so tell the current lwp + * to do the next time it returns to userland (which should be very + * soon). + */ + if (ti->ti_syncicache_bitmap && (ci->ci_flags & CPUF_USERPMAP)) { + curlwp->l_md.md_astpending = 1; /* force call to ast() */ + ci->ci_evcnt_syncicache_ipi_rqst.ev_count++; + } + + TLBINFO_UNLOCK(ti); + +} +#endif /* MULTIPROCESSOR */