aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--arch/powerpc/sysdev/scom.c136
1 files changed, 81 insertions, 55 deletions
diff --git a/arch/powerpc/sysdev/scom.c b/arch/powerpc/sysdev/scom.c
index 3963d995648a..6f5a8d177c42 100644
--- a/arch/powerpc/sysdev/scom.c
+++ b/arch/powerpc/sysdev/scom.c
@@ -25,6 +25,7 @@
25#include <asm/debug.h> 25#include <asm/debug.h>
26#include <asm/prom.h> 26#include <asm/prom.h>
27#include <asm/scom.h> 27#include <asm/scom.h>
28#include <asm/uaccess.h>
28 29
29const struct scom_controller *scom_controller; 30const struct scom_controller *scom_controller;
30EXPORT_SYMBOL_GPL(scom_controller); 31EXPORT_SYMBOL_GPL(scom_controller);
@@ -98,61 +99,89 @@ EXPORT_SYMBOL_GPL(scom_map_device);
98#ifdef CONFIG_SCOM_DEBUGFS 99#ifdef CONFIG_SCOM_DEBUGFS
99struct scom_debug_entry { 100struct scom_debug_entry {
100 struct device_node *dn; 101 struct device_node *dn;
101 unsigned long addr; 102 struct debugfs_blob_wrapper path;
102 scom_map_t map; 103 char name[16];
103 spinlock_t lock;
104 char name[8];
105 struct debugfs_blob_wrapper blob;
106}; 104};
107 105
108static int scom_addr_set(void *data, u64 val) 106static ssize_t scom_debug_read(struct file *filp, char __user *ubuf,
109{ 107 size_t count, loff_t *ppos)
110 struct scom_debug_entry *ent = data;
111
112 ent->addr = 0;
113 scom_unmap(ent->map);
114
115 ent->map = scom_map(ent->dn, val, 1);
116 if (scom_map_ok(ent->map))
117 ent->addr = val;
118 else
119 return -EFAULT;
120
121 return 0;
122}
123
124static int scom_addr_get(void *data, u64 *val)
125{ 108{
126 struct scom_debug_entry *ent = data; 109 struct scom_debug_entry *ent = filp->private_data;
127 *val = ent->addr; 110 u64 __user *ubuf64 = (u64 __user *)ubuf;
128 return 0; 111 loff_t off = *ppos;
112 ssize_t done = 0;
113 u64 reg, reg_cnt, val;
114 scom_map_t map;
115 int rc;
116
117 if (off < 0 || (off & 7) || (count & 7))
118 return -EINVAL;
119 reg = off >> 3;
120 reg_cnt = count >> 3;
121
122 map = scom_map(ent->dn, reg, reg_cnt);
123 if (!scom_map_ok(map))
124 return -ENXIO;
125
126 for (reg = 0; reg < reg_cnt; reg++) {
127 rc = scom_read(map, reg, &val);
128 if (!rc)
129 rc = put_user(val, ubuf64);
130 if (rc) {
131 if (!done)
132 done = rc;
133 break;
134 }
135 ubuf64++;
136 *ppos += 8;
137 done += 8;
138 }
139 scom_unmap(map);
140 return done;
129} 141}
130DEFINE_SIMPLE_ATTRIBUTE(scom_addr_fops, scom_addr_get, scom_addr_set,
131 "0x%llx\n");
132 142
133static int scom_val_set(void *data, u64 val) 143static ssize_t scom_debug_write(struct file* filp, const char __user *ubuf,
144 size_t count, loff_t *ppos)
134{ 145{
135 struct scom_debug_entry *ent = data; 146 struct scom_debug_entry *ent = filp->private_data;
136 147 u64 __user *ubuf64 = (u64 __user *)ubuf;
137 if (!scom_map_ok(ent->map)) 148 loff_t off = *ppos;
138 return -EFAULT; 149 ssize_t done = 0;
139 150 u64 reg, reg_cnt, val;
140 scom_write(ent->map, 0, val); 151 scom_map_t map;
141 152 int rc;
142 return 0; 153
154 if (off < 0 || (off & 7) || (count & 7))
155 return -EINVAL;
156 reg = off >> 3;
157 reg_cnt = count >> 3;
158
159 map = scom_map(ent->dn, reg, reg_cnt);
160 if (!scom_map_ok(map))
161 return -ENXIO;
162
163 for (reg = 0; reg < reg_cnt; reg++) {
164 rc = get_user(val, ubuf64);
165 if (!rc)
166 rc = scom_write(map, reg, val);
167 if (rc) {
168 if (!done)
169 done = rc;
170 break;
171 }
172 ubuf64++;
173 done += 8;
174 }
175 scom_unmap(map);
176 return done;
143} 177}
144 178
145static int scom_val_get(void *data, u64 *val) 179static const struct file_operations scom_debug_fops = {
146{ 180 .read = scom_debug_read,
147 struct scom_debug_entry *ent = data; 181 .write = scom_debug_write,
148 182 .open = simple_open,
149 if (!scom_map_ok(ent->map)) 183 .llseek = default_llseek,
150 return -EFAULT; 184};
151
152 return scom_read(ent->map, 0, val);
153}
154DEFINE_SIMPLE_ATTRIBUTE(scom_val_fops, scom_val_get, scom_val_set,
155 "0x%llx\n");
156 185
157static int scom_debug_init_one(struct dentry *root, struct device_node *dn, 186static int scom_debug_init_one(struct dentry *root, struct device_node *dn,
158 int i) 187 int i)
@@ -165,11 +194,9 @@ static int scom_debug_init_one(struct dentry *root, struct device_node *dn,
165 return -ENOMEM; 194 return -ENOMEM;
166 195
167 ent->dn = of_node_get(dn); 196 ent->dn = of_node_get(dn);
168 ent->map = SCOM_MAP_INVALID; 197 snprintf(ent->name, 16, "%08x", i);
169 spin_lock_init(&ent->lock); 198 ent->path.data = (void*) dn->full_name;
170 snprintf(ent->name, 8, "scom%d", i); 199 ent->path.size = strlen(dn->full_name);
171 ent->blob.data = (void*) dn->full_name;
172 ent->blob.size = strlen(dn->full_name);
173 200
174 dir = debugfs_create_dir(ent->name, root); 201 dir = debugfs_create_dir(ent->name, root);
175 if (!dir) { 202 if (!dir) {
@@ -178,9 +205,8 @@ static int scom_debug_init_one(struct dentry *root, struct device_node *dn,
178 return -1; 205 return -1;
179 } 206 }
180 207
181 debugfs_create_file("addr", 0600, dir, ent, &scom_addr_fops); 208 debugfs_create_blob("devspec", 0400, dir, &ent->path);
182 debugfs_create_file("value", 0600, dir, ent, &scom_val_fops); 209 debugfs_create_file("access", 0600, dir, ent, &scom_debug_fops);
183 debugfs_create_blob("devspec", 0400, dir, &ent->blob);
184 210
185 return 0; 211 return 0;
186} 212}