FreeBSD/sys/arm/arm/pmap-v4.c
/*
 * pmap_clean_page()
 *
 * This is a local function used to work out the best strategy to clean
 * a single page referenced by its entry in the PV table. It should be used by
 * pmap_copy_page, pmap_zero page and maybe some others later on.
 *
 * Its policy is effectively:
 *  o If there are no mappings, we don't bother doing anything with the cache.
 *  o If there is one mapping, we clean just that page.
 *  o If there are multiple mappings, we clean the entire cache.
 *
 * So that some functions can be further optimised, it returns 0 if it didn't
 * clean the entire cache, or 1 if it did.
 *
 * XXX One bug in this routine is that if the pv_entry has a single page
 * mapped at 0x00000000 a whole cache clean will be performed rather than
 * just the 1 page. Since this should not occur in everyday use and if it does
 * it will just result in not the most efficient clean for the page.
 *
 * We don't yet use this function but may want to.
 */
pmap_clean_page()
This is a local function used to work out the best strategy to clean
a single page referenced by its entry in the PV table. It should be used by
pmap_copy_page, pmap_zero page and maybe some others later on.

Its policy is effectively:
o If there are no mappings, we don't bother doing anything with the cache.
o If there is one mapping, we clean just that page.
o If there are multiple mappings, we clean the entire cache.

So that some functions can be further optimised, it returns 0 if it didn't
clean the entire cache, or 1 if it did.

XXX One bug in this routine is that if the pv_entry has a single page
mapped at 0x00000000 a whole cache clean will be performed rather than
just the 1 page. Since this should not occur in everyday use and if it does
it will just result in not the most efficient clean for the page.

We don't yet use this function but may want to.
pmap_clean_page () This is a local function used to work out the best strategy to clean a single page referenced by its entry in the PV table . It should be used by pmap_copy_page pmap_zero page and maybe some others later on . Its policy is effectively : o If there are no mappings we don ' t bother doing anything with the cache . o If there is one mapping we clean just that page . o If there are multiple mappings we clean the entire cache . So that some functions can be further optimised it returns 0 if it didn ' t clean the entire cache or 1 if it did . XXX One bug in this routine is that if the pv_entry has a single page mapped at 0x00000000 a whole cache clean will be performed rather than just the 1 page . Since this should not occur in everyday use and if it does it will just result in not the most efficient clean for the page . We don ' t yet use this function but may want to .
static int
pmap_clean_page(struct pv_entry *pv, boolean_t is_src)
{
	pmap_t pm, pm_to_clean = NULL;
	struct pv_entry *npv;
	u_int cache_needs_cleaning = 0;
	u_int flags = 0;
	vm_offset_t page_to_clean = 0;
	if (pv == NULL) {
		return (0);
	}
	if (curthread)
		pm = vmspace_pmap(curproc->p_vmspace);
	else
		pm = kernel_pmap;
	for (npv = pv; npv; npv = TAILQ_NEXT(npv, pv_list)) {
		if (npv->pv_pmap == kernel_pmap || npv->pv_pmap == pm) {
			flags |= npv->pv_flags;
			if (npv->pv_flags & PVF_NC) {
#ifdef DIAGNOSTIC
				if (cache_needs_cleaning)
					panic("pmap_clean_page: "
					    "cache inconsistency");
#endif
				break;
			} else if (is_src && (npv->pv_flags & PVF_WRITE) == 0)
				continue;
			if (cache_needs_cleaning) {
				page_to_clean = 0;
				break;
			} else {
				page_to_clean = npv->pv_va;
				pm_to_clean = npv->pv_pmap;
			}
			cache_needs_cleaning = 1;
		}
	}
	if (page_to_clean) {
		if (PV_BEEN_EXECD(flags))
			pmap_idcache_wbinv_range(pm_to_clean, page_to_clean,
			    PAGE_SIZE);
		else
			pmap_dcache_wb_range(pm_to_clean, page_to_clean,
			    PAGE_SIZE, !is_src, (flags & PVF_WRITE) == 0);
	} else if (cache_needs_cleaning) {
		if (PV_BEEN_EXECD(flags))
			pmap_idcache_wbinv_all(pm);
		else
			pmap_dcache_wbinv_all(pm);
		return (1);
	}
	return (0);
}
static int pmap_clean_page ( struct pv_entry * pv , boolean_t is_src ) { pmap_t pm , pm_to_clean = NULL ; struct pv_entry * npv ; u_int cache_needs_cleaning = 0 ; u_int flags = 0 ; vm_offset_t page_to_clean = 0 ; if ( pv == NULL ) { return ( 0 ) ; } if ( curthread ) pm = vmspace_pmap ( curproc -> p_vmspace ) ; else pm = kernel_pmap ; for ( npv = pv ; npv ; npv = TAILQ_NEXT ( npv , pv_list ) ) { if ( npv -> pv_pmap == kernel_pmap || npv -> pv_pmap == pm ) { flags |= npv -> pv_flags ; if ( npv -> pv_flags & PVF_NC ) { #ifdef DIAGNOSTIC if ( cache_needs_cleaning ) panic ( " " " " ) ; #endif break ; } else if ( is_src && ( npv -> pv_flags & PVF_WRITE ) == 0 ) continue ; if ( cache_needs_cleaning ) { page_to_clean = 0 ; break ; } else { page_to_clean = npv -> pv_va ; pm_to_clean = npv -> pv_pmap ; } cache_needs_cleaning = 1 ; } } if ( page_to_clean ) { if ( PV_BEEN_EXECD ( flags ) ) pmap_idcache_wbinv_range ( pm_to_clean , page_to_clean , PAGE_SIZE ) ; else pmap_dcache_wb_range ( pm_to_clean , page_to_clean , PAGE_SIZE , ! is_src , ( flags & PVF_WRITE ) == 0 ) ; } else if ( cache_needs_cleaning ) { if ( PV_BEEN_EXECD ( flags ) ) pmap_idcache_wbinv_all ( pm ) ; else pmap_dcache_wbinv_all ( pm ) ; return ( 1 ) ; } return ( 0 ) ; }
pmap_clean_page()
 This is a local function used to work out the best strategy to clean
 a single page referenced by its entry in the PV table.
pmap_clean_page () This is a local function used to work out the best strategy to clean a single page referenced by its entry in the PV table .
/* nothing mapped in so nothing to flush */ /*
	 * Since we flush the cache each time we change to a different
	 * user vmspace, we only need to flush the page if it is in the
	 * current pmap.
	 */ /*
			 * The page is mapped non-cacheable in
			 * this map.  No need to flush the cache.
			 */