Linux Audio

Check our new training course

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