[Home]Latency Killer/Flushy

Last edit: StephaneFillod on March 14, 2005 14:01 (5056 days, 20 hours and 57 minutes ago) (diff)
Rtai.Dk | Latency Killer | RecentChanges | Preferences | DIAPM RTAI

/*
 *   flushy.c
 *
 *   Copyright (C) 2005 Stephane Fillod
 *
 *   This program is free software; you can redistribute it and/or modify
 *   it under the terms of the GNU General Public License as published by
 *   the Free Software Foundation, Inc., 675 Mass Ave, Cambridge MA 02139,
 *   USA; either version 2 of the License, or (at your option) any later
 *   version.
 *
 *   This program is distributed in the hope that it will be useful,
 *   but WITHOUT ANY WARRANTY; without even the implied warranty of
 *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *   GNU General Public License for more details.
 *
 *   You should have received a copy of the GNU General Public License
 *   along with this program; if not, write to the Free Software
 *   Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
 *
 *   This Linux kernel module loves to flush your I&D caches and TLB. 2005/03/14.
 *
 *   Under PPC, you will need a small patch to EXPORT_SYMBOL(flush_tlb_all)
 *   of the definition void flush_tlb_all(void) {_tlbia();}
 *
 *   TODO: mark FPU and SIMD unit registers dirty.
 */

#include <linux/config.h>
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/moduleparam.h>

#include <linux/sched.h>
#include <linux/jiffies.h>
#include <asm/system.h>
#include <linux/errno.h>

#include <asm/cacheflush.h>
#include <asm/tlbflush.h>

int duration_s = 1;

MODULE_PARM(duration_s, "i");
MODULE_PARM_DESC(duration_s, "duration in second (default: 1)");

int dcache_opt = 1;
int icache_opt = 1;

MODULE_PARM(dcache_opt, "i");
MODULE_PARM_DESC(dcache_opt, "flush D-cache (default: 1)");
MODULE_PARM(icache_opt, "i");
MODULE_PARM_DESC(icache_opt, "flush I-cache (default: 1)");

#ifdef HAVE_FLUSH_TLB_ALL
int tlb_opt = 1;

MODULE_PARM(tlb_opt, "i");
MODULE_PARM_DESC(tlb_opt, "flush TLB (default: 1)");
#endif



#ifdef FLUSH_L1
#define CACHE_NWAYS     64
#define CACHE_NLINES    16
#else
/* on MPC8560/e500, L2 is 256KiB */
#define CACHE_NWAYS     8
#define CACHE_NLINES    1024
#endif

int cache_nways = CACHE_NWAYS;
int cache_nlines = CACHE_NLINES;
MODULE_PARM(cache_nways, "i");
MODULE_PARM_DESC(cache_nways, "Cache N-ways (default: 8)");
MODULE_PARM(cache_nlines, "i");
MODULE_PARM_DESC(cache_nlines, "Cache N-lines (default: 1024)");

#ifndef KERNELBASE
#define KERNELBASE PAGE_OFFSET
#endif

#ifdef __i386__
#define flush_instruction_cache()          __asm__ __volatile__ ("wbinvd": : :"memory")

#endif

/*
 * This is a portable flush_dcache_all.
 * Hardware "flash" flushing, where available, would be better.
 *
 * NB: alt_flush_dcache_all does flushing by eviction.
 *      lines locked in cache stays in.
 *
 *      To be more cruel, we could also make the lines dirty
 *      (with another base pointer of course), so all
 *      is left is a poisoned apple, ie. a cold cache with
 *      write I/O  to be done before allocation. Now,
 *      it's even better if one makes each line partly dirty
 *      to possibly force an extra read..
 *
 */
static void alt_flush_dcache_all(void)
{
        int i;
        volatile unsigned int *p = (volatile unsigned int *)KERNELBASE;

        for (i = 2 * cache_nways * cache_nlines; i>0; i--) {

                /*
                 * Load one word from every line
                 *
                 * Rem: If you do not trust your compiler,
                 * you may disassemble this function, and verify
                 * a load instruction is really generated
                 * and not optimized out.
                 */

                *p;

                p += L1_CACHE_BYTES/sizeof(unsigned int);
        }
}


int flushy_init(void)
{
        unsigned long expire;

        expire = jiffies + duration_s*HZ;

        printk("Cache size: %dKiB, duration: %ds\n",
                        (L1_CACHE_BYTES * cache_nways * cache_nlines)/1024,
                         duration_s);

        do {
                if ((jiffies % HZ) == 0)
                        printk("Best greetings from flushy:%s%s%s..\n",
                                dcache_opt?" D-cache":"",
                                icache_opt?" I-cache":"",
                                tlb_opt?" TLB":""
                                );

                /*
                 * attempt D-Cache flusing
                 */
                if (dcache_opt)
                        alt_flush_dcache_all();

                /*
                 * flush kernel (TLB) dynamic mapping's
                 *
                 * note: you may have to add an EXPORT_SYMBOL() in your kernel.
                 * ppc linux has no flush_tlb_all, you can define it as _tlbia
                 */
#ifdef HAVE_FLUSH_TLB_ALL
                if (tlb_opt)
                        flush_tlb_all();
#endif

                /*
                 * Flush I-Cache last, so flush_dcache still runs fast
                 *
                 * NB: flush_instruction_cache() may not flush L2 if unified
                 */
                if (icache_opt)
                        flush_instruction_cache();


                /* have fun guys.. */
                schedule();

        } while (expire > jiffies);


        printk("Done with flushy.\n");

        return -ETIME;  /* no need to rmmod...*/
}

void flushy_exit(void)
{
        printk("Bybye flushy.\n");
}


MODULE_LICENSE("GPL");

module_init(flushy_init);
module_exit(flushy_exit);

Edit text of this page | View other revisions | Download Rtai.dk
Search: