X-Git-Url: http://git.onelab.eu/?a=blobdiff_plain;f=arch%2Fparisc%2Fkernel%2Fcache.c;h=f46a07a792187626370dd139e9496dc0551bb6f0;hb=6a77f38946aaee1cd85eeec6cf4229b204c15071;hp=0703ab036826fa36d39f9a41c3ae1e9359c1e185;hpb=87fc8d1bb10cd459024a742c6a10961fefcef18f;p=linux-2.6.git diff --git a/arch/parisc/kernel/cache.c b/arch/parisc/kernel/cache.c index 0703ab036..f46a07a79 100644 --- a/arch/parisc/kernel/cache.c +++ b/arch/parisc/kernel/cache.c @@ -33,6 +33,17 @@ int dcache_stride; int icache_stride; EXPORT_SYMBOL(dcache_stride); + +#if defined(CONFIG_SMP) +/* On some machines (e.g. ones with the Merced bus), there can be + * only a single PxTLB broadcast at a time; this must be guaranteed + * by software. We put a spinlock around all TLB flushes to + * ensure this. + */ +DEFINE_SPINLOCK(pa_tlb_lock); +EXPORT_SYMBOL(pa_tlb_lock); +#endif + struct pdc_cache_info cache_info; #ifndef CONFIG_PA20 static struct pdc_btlb_info btlb_info; @@ -44,6 +55,11 @@ flush_data_cache(void) { on_each_cpu((void (*)(void *))flush_data_cache_local, NULL, 1, 1); } +void +flush_instruction_cache(void) +{ + on_each_cpu((void (*)(void *))flush_instruction_cache_local, NULL, 1, 1); +} #endif void @@ -306,3 +322,45 @@ EXPORT_SYMBOL(flush_kernel_dcache_range_asm); EXPORT_SYMBOL(flush_kernel_dcache_page); EXPORT_SYMBOL(flush_data_cache_local); EXPORT_SYMBOL(flush_kernel_icache_range_asm); + +void clear_user_page_asm(void *page, unsigned long vaddr) +{ + /* This function is implemented in assembly in pacache.S */ + extern void __clear_user_page_asm(void *page, unsigned long vaddr); + + purge_tlb_start(); + __clear_user_page_asm(page, vaddr); + purge_tlb_end(); +} + +#define FLUSH_THRESHOLD 0x80000 /* 0.5MB */ +int parisc_cache_flush_threshold = FLUSH_THRESHOLD; + +void parisc_setup_cache_timing(void) +{ + unsigned long rangetime, alltime; + extern char _text; /* start of kernel code, defined by linker */ + extern char _end; /* end of BSS, defined by linker */ + unsigned long size; + + alltime = mfctl(16); + flush_data_cache(); + alltime = mfctl(16) - alltime; + + size = (unsigned long)(&_end - _text); + rangetime = mfctl(16); + flush_kernel_dcache_range((unsigned long)&_text, size); + rangetime = mfctl(16) - rangetime; + + printk(KERN_DEBUG "Whole cache flush %lu cycles, flushing %lu bytes %lu cycles\n", + alltime, size, rangetime); + + /* Racy, but if we see an intermediate value, it's ok too... */ + parisc_cache_flush_threshold = size * alltime / rangetime; + + parisc_cache_flush_threshold = (parisc_cache_flush_threshold + L1_CACHE_BYTES - 1) &~ (L1_CACHE_BYTES - 1); + if (!parisc_cache_flush_threshold) + parisc_cache_flush_threshold = FLUSH_THRESHOLD; + + printk("Setting cache flush threshold to %x (%d CPUs online)\n", parisc_cache_flush_threshold, num_online_cpus()); +}