linux/arch/sh/mm/cache-debugfs.c
<<
>>
Prefs
   1/*
   2 * debugfs ops for the L1 cache
   3 *
   4 *  Copyright (C) 2006  Paul Mundt
   5 *
   6 * This file is subject to the terms and conditions of the GNU General Public
   7 * License.  See the file "COPYING" in the main directory of this archive
   8 * for more details.
   9 */
  10#include <linux/init.h>
  11#include <linux/module.h>
  12#include <linux/debugfs.h>
  13#include <linux/seq_file.h>
  14#include <asm/processor.h>
  15#include <asm/uaccess.h>
  16#include <asm/cache.h>
  17#include <asm/io.h>
  18
  19enum cache_type {
  20        CACHE_TYPE_ICACHE,
  21        CACHE_TYPE_DCACHE,
  22        CACHE_TYPE_UNIFIED,
  23};
  24
  25static int cache_seq_show(struct seq_file *file, void *iter)
  26{
  27        unsigned int cache_type = (unsigned int)file->private;
  28        struct cache_info *cache;
  29        unsigned int waysize, way, cache_size;
  30        unsigned long ccr, base;
  31        static unsigned long addrstart = 0;
  32
  33        /*
  34         * Go uncached immediately so we don't skew the results any
  35         * more than we already are..
  36         */
  37        jump_to_uncached();
  38
  39        ccr = __raw_readl(CCR);
  40        if ((ccr & CCR_CACHE_ENABLE) == 0) {
  41                back_to_cached();
  42
  43                seq_printf(file, "disabled\n");
  44                return 0;
  45        }
  46
  47        if (cache_type == CACHE_TYPE_DCACHE) {
  48                base = CACHE_OC_ADDRESS_ARRAY;
  49                cache = &current_cpu_data.dcache;
  50        } else {
  51                base = CACHE_IC_ADDRESS_ARRAY;
  52                cache = &current_cpu_data.icache;
  53        }
  54
  55        /*
  56         * Due to the amount of data written out (depending on the cache size),
  57         * we may be iterated over multiple times. In this case, keep track of
  58         * the entry position in addrstart, and rewind it when we've hit the
  59         * end of the cache.
  60         *
  61         * Likewise, the same code is used for multiple caches, so care must
  62         * be taken for bouncing addrstart back and forth so the appropriate
  63         * cache is hit.
  64         */
  65        cache_size = cache->ways * cache->sets * cache->linesz;
  66        if (((addrstart & 0xff000000) != base) ||
  67             (addrstart & 0x00ffffff) > cache_size)
  68                addrstart = base;
  69
  70        waysize = cache->sets;
  71
  72        /*
  73         * If the OC is already in RAM mode, we only have
  74         * half of the entries to consider..
  75         */
  76        if ((ccr & CCR_CACHE_ORA) && cache_type == CACHE_TYPE_DCACHE)
  77                waysize >>= 1;
  78
  79        waysize <<= cache->entry_shift;
  80
  81        for (way = 0; way < cache->ways; way++) {
  82                unsigned long addr;
  83                unsigned int line;
  84
  85                seq_printf(file, "-----------------------------------------\n");
  86                seq_printf(file, "Way %d\n", way);
  87                seq_printf(file, "-----------------------------------------\n");
  88
  89                for (addr = addrstart, line = 0;
  90                     addr < addrstart + waysize;
  91                     addr += cache->linesz, line++) {
  92                        unsigned long data = __raw_readl(addr);
  93
  94                        /* Check the V bit, ignore invalid cachelines */
  95                        if ((data & 1) == 0)
  96                                continue;
  97
  98                        /* U: Dirty, cache tag is 10 bits up */
  99                        seq_printf(file, "%3d: %c 0x%lx\n",
 100                                   line, data & 2 ? 'U' : ' ',
 101                                   data & 0x1ffffc00);
 102                }
 103
 104                addrstart += cache->way_incr;
 105        }
 106
 107        back_to_cached();
 108
 109        return 0;
 110}
 111
 112static int cache_debugfs_open(struct inode *inode, struct file *file)
 113{
 114        return single_open(file, cache_seq_show, inode->i_private);
 115}
 116
 117static const struct file_operations cache_debugfs_fops = {
 118        .owner          = THIS_MODULE,
 119        .open           = cache_debugfs_open,
 120        .read           = seq_read,
 121        .llseek         = seq_lseek,
 122        .release        = single_release,
 123};
 124
 125static int __init cache_debugfs_init(void)
 126{
 127        struct dentry *dcache_dentry, *icache_dentry;
 128
 129        dcache_dentry = debugfs_create_file("dcache", S_IRUSR, arch_debugfs_dir,
 130                                            (unsigned int *)CACHE_TYPE_DCACHE,
 131                                            &cache_debugfs_fops);
 132        if (!dcache_dentry)
 133                return -ENOMEM;
 134
 135        icache_dentry = debugfs_create_file("icache", S_IRUSR, arch_debugfs_dir,
 136                                            (unsigned int *)CACHE_TYPE_ICACHE,
 137                                            &cache_debugfs_fops);
 138        if (!icache_dentry) {
 139                debugfs_remove(dcache_dentry);
 140                return -ENOMEM;
 141        }
 142
 143        return 0;
 144}
 145module_init(cache_debugfs_init);
 146
 147MODULE_LICENSE("GPL v2");
 148