Loading...
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 | /*
* arch/blackfin/kernel/cplbinfo.c - display CPLB status
*
* Copyright 2004-2008 Analog Devices Inc.
*
* Licensed under the GPL-2 or later.
*/
#include <linux/ctype.h>
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/proc_fs.h>
#include <linux/seq_file.h>
#include <linux/uaccess.h>
#include <asm/cplbinit.h>
#include <asm/blackfin.h>
static char const page_strtbl[][4] = {
"1K", "4K", "1M", "4M",
#ifdef CONFIG_BF60x
"16K", "64K", "16M", "64M",
#endif
};
#define page(flags) (((flags) & 0x70000) >> 16)
#define strpage(flags) page_strtbl[page(flags)]
struct cplbinfo_data {
loff_t pos;
char cplb_type;
u32 mem_control;
struct cplb_entry *tbl;
int switched;
};
static void cplbinfo_print_header(struct seq_file *m)
{
seq_printf(m, "Index\tAddress\t\tData\tSize\tU/RD\tU/WR\tS/WR\tSwitch\n");
}
static int cplbinfo_nomore(struct cplbinfo_data *cdata)
{
return cdata->pos >= MAX_CPLBS;
}
static int cplbinfo_show(struct seq_file *m, void *p)
{
struct cplbinfo_data *cdata;
unsigned long data, addr;
loff_t pos;
cdata = p;
pos = cdata->pos;
addr = cdata->tbl[pos].addr;
data = cdata->tbl[pos].data;
seq_printf(m,
"%d\t0x%08lx\t%05lx\t%s\t%c\t%c\t%c\t%c\n",
(int)pos, addr, data, strpage(data),
(data & CPLB_USER_RD) ? 'Y' : 'N',
(data & CPLB_USER_WR) ? 'Y' : 'N',
(data & CPLB_SUPV_WR) ? 'Y' : 'N',
pos < cdata->switched ? 'N' : 'Y');
return 0;
}
static void cplbinfo_seq_init(struct cplbinfo_data *cdata, unsigned int cpu)
{
if (cdata->cplb_type == 'I') {
cdata->mem_control = bfin_read_IMEM_CONTROL();
cdata->tbl = icplb_tbl[cpu];
cdata->switched = first_switched_icplb;
} else {
cdata->mem_control = bfin_read_DMEM_CONTROL();
cdata->tbl = dcplb_tbl[cpu];
cdata->switched = first_switched_dcplb;
}
}
static void *cplbinfo_start(struct seq_file *m, loff_t *pos)
{
struct cplbinfo_data *cdata = m->private;
if (!*pos) {
seq_printf(m, "%cCPLBs are %sabled: 0x%x\n", cdata->cplb_type,
(cdata->mem_control & ENDCPLB ? "en" : "dis"),
cdata->mem_control);
cplbinfo_print_header(m);
} else if (cplbinfo_nomore(cdata))
return NULL;
get_cpu();
return cdata;
}
static void *cplbinfo_next(struct seq_file *m, void *p, loff_t *pos)
{
struct cplbinfo_data *cdata = p;
cdata->pos = ++(*pos);
if (cplbinfo_nomore(cdata))
return NULL;
else
return cdata;
}
static void cplbinfo_stop(struct seq_file *m, void *p)
{
put_cpu();
}
static const struct seq_operations cplbinfo_sops = {
.start = cplbinfo_start,
.next = cplbinfo_next,
.stop = cplbinfo_stop,
.show = cplbinfo_show,
};
#define CPLBINFO_DCPLB_FLAG 0x80000000
static int cplbinfo_open(struct inode *inode, struct file *file)
{
char cplb_type;
unsigned int cpu = (unsigned long)PDE_DATA(file_inode(file));
int ret;
struct seq_file *m;
struct cplbinfo_data *cdata;
cplb_type = cpu & CPLBINFO_DCPLB_FLAG ? 'D' : 'I';
cpu &= ~CPLBINFO_DCPLB_FLAG;
if (!cpu_online(cpu))
return -ENODEV;
ret = seq_open_private(file, &cplbinfo_sops, sizeof(*cdata));
if (ret)
return ret;
m = file->private_data;
cdata = m->private;
cdata->pos = 0;
cdata->cplb_type = cplb_type;
cplbinfo_seq_init(cdata, cpu);
return 0;
}
static const struct file_operations cplbinfo_fops = {
.open = cplbinfo_open,
.read = seq_read,
.llseek = seq_lseek,
.release = seq_release_private,
};
static int __init cplbinfo_init(void)
{
struct proc_dir_entry *cplb_dir, *cpu_dir;
char buf[10];
unsigned int cpu;
cplb_dir = proc_mkdir("cplbinfo", NULL);
if (!cplb_dir)
return -ENOMEM;
for_each_possible_cpu(cpu) {
sprintf(buf, "cpu%i", cpu);
cpu_dir = proc_mkdir(buf, cplb_dir);
if (!cpu_dir)
return -ENOMEM;
proc_create_data("icplb", S_IRUGO, cpu_dir, &cplbinfo_fops,
(void *)cpu);
proc_create_data("dcplb", S_IRUGO, cpu_dir, &cplbinfo_fops,
(void *)(cpu | CPLBINFO_DCPLB_FLAG));
}
return 0;
}
late_initcall(cplbinfo_init);
|