if (n_pages >= 64) { 
if (n_pages >= 64 || ((start ^ (end - 1)) & PMD_MASK)) { 
static void sh64_dcache_purge_user_range(struct mm_struct *mm,			  unsigned long start, unsigned long end){	/* There are at least 5 choices for the implementation of this, with	   pros (+), cons(-), comments(*):	   1. ocbp each line in the range through the original user's ASID	      + no lines spuriously evicted	      - tlbmiss handling (must either handle faults on demand => extra		special-case code in tlbmiss critical path), or map the page in		advance (=> flush_tlb_range in advance to avoid multiple hits)	      - ASID switching	      - expensive for large ranges	   2. temporarily map each page in the range to a special effective	      address and ocbp through the temporary mapping; relies on the	      fact that SH-5 OCB* always do TLB lookup and match on ptags (they	      never look at the etags)	      + no spurious evictions	      - expensive for large ranges	      * surely cheaper than (1)	   3. walk all the lines in the cache, check the tags, if a match	      occurs create a page mapping to ocbp the line through	      + no spurious evictions	      - tag inspection overhead	      - (especially for small ranges)	      - potential cost of setting up/tearing down page mapping for		every line that matches the range	      * cost partly independent of range size	   4. walk all the lines in the cache, check the tags, if a match	      occurs use 4 * alloco to purge the line (+3 other probably	      innocent victims) by natural eviction	      + no tlb mapping overheads	      - spurious evictions	      - tag inspection overhead	   5. implement like flush_cache_all	      + no tag inspection overhead	      - spurious evictions	      - bad for small ranges	   (1) can be ruled out as more expensive than (2).  (2) appears best	   for small ranges.  The choice between (3), (4) and (5) for large	   ranges and the range size for the large/small boundary need	   benchmarking to determine.	   For now use approach (2) for small ranges and (5) for large ones.	   */	int n_pages;	n_pages = ((end - start) >> PAGE_SHIFT);	if (n_pages >= 64) {#if 1		sh64_dcache_purge_all();#else		unsigned long long set, way;		unsigned long mm_asid = mm->context & MMU_CONTEXT_ASID_MASK;		for (set = 0; set < cpu_data->dcache.sets; set++) {			unsigned long long set_base_config_addr = CACHE_OC_ADDRESS_ARRAY + (set << cpu_data->dcache.set_shift);			for (way = 0; way < cpu_data->dcache.ways; way++) {				unsigned long long config_addr = set_base_config_addr + (way << cpu_data->dcache.way_step_shift);				unsigned long long tag0;				unsigned long line_valid;				asm __volatile__("getcfg %1, 0, %0" : "=r" (tag0) : "r" (config_addr));				line_valid = tag0 & SH_CACHE_VALID;				if (line_valid) {					unsigned long cache_asid;					unsigned long epn;					cache_asid = (tag0 & cpu_data->dcache.asid_mask) >> cpu_data->dcache.asid_shift;					/* The next line needs some					   explanation.  The virtual tags					   encode bits [31:13] of the virtual					   address, bit [12] of the 'tag' being					   implied by the cache set index. */					epn = (tag0 & cpu_data->dcache.epn_mask) | ((set & 0x80) << cpu_data->dcache.entry_shift);					if ((cache_asid == mm_asid) && (start <= epn) && (epn < end)) {						/* TODO : could optimise this						   call by batching multiple						   adjacent sets together. */						sh64_dcache_purge_sets(set, 1);						break; /* Don't waste time inspecting other ways for this set */					}				}			}		}#endif	} else {		/* 'Small' range */		unsigned long aligned_start;		unsigned long eaddr;		unsigned long last_page_start;		aligned_start = start & PAGE_MASK;		/* 'end' is 1 byte beyond the end of the range */		last_page_start = (end - 1) & PAGE_MASK;		eaddr = aligned_start;		while (eaddr <= last_page_start) {			sh64_dcache_purge_user_page(mm, eaddr);			eaddr += PAGE_SIZE;		}	}	return;}
10457	/local/tlutelli/issta_data/temp/c/2005_temp/2005/10457/60ec5585496871345c1a8113d7b60ed9d9474866/cache.c/clean/arch/sh64/mm/cache.c