aboutsummaryrefslogtreecommitdiffstats
path: root/arch/powerpc/sysdev
diff options
context:
space:
mode:
authorBenjamin Herrenschmidt <benh@kernel.crashing.org>2013-11-03 21:20:35 -0500
committerBenjamin Herrenschmidt <benh@kernel.crashing.org>2013-11-05 22:13:50 -0500
commitcda13552d5055a87dd39334dabf47249b01fc5aa (patch)
tree411f67ed12f3dae298eec8d086804bad38441277 /arch/powerpc/sysdev
parentd7a88c7eb46acb486922822eec3224c0bcab29dc (diff)
powerpc/scom: Improve debugfs interface
The current debugfs interface to scom is essentially unused and racy. It uses two different files "address" and "data" to perform accesses which is at best impractical for anything but manual use by a developer. This replaces it with an "access" file which represent the entire scom address space which can be lseek/read/writen too. This file only supports accesses that are 8 bytes aligned and multiple of 8 bytes in size. The offset is logically the SCOM address multiplied by 8. Since nothing in userspace exploits that file at the moment, the ABI change is a no-brainer. Signed-off-by: Benjamin Herrenschmidt <benh@kernel.crashing.org>
Diffstat (limited to 'arch/powerpc/sysdev')
-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}