diff options
-rw-r--r-- | arch/powerpc/sysdev/scom.c | 136 |
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 | ||
29 | const struct scom_controller *scom_controller; | 30 | const struct scom_controller *scom_controller; |
30 | EXPORT_SYMBOL_GPL(scom_controller); | 31 | EXPORT_SYMBOL_GPL(scom_controller); |
@@ -98,61 +99,89 @@ EXPORT_SYMBOL_GPL(scom_map_device); | |||
98 | #ifdef CONFIG_SCOM_DEBUGFS | 99 | #ifdef CONFIG_SCOM_DEBUGFS |
99 | struct scom_debug_entry { | 100 | struct 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 | ||
108 | static int scom_addr_set(void *data, u64 val) | 106 | static 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 | |||
124 | static 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 | } |
130 | DEFINE_SIMPLE_ATTRIBUTE(scom_addr_fops, scom_addr_get, scom_addr_set, | ||
131 | "0x%llx\n"); | ||
132 | 142 | ||
133 | static int scom_val_set(void *data, u64 val) | 143 | static 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 | ||
145 | static int scom_val_get(void *data, u64 *val) | 179 | static 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 | } | ||
154 | DEFINE_SIMPLE_ATTRIBUTE(scom_val_fops, scom_val_get, scom_val_set, | ||
155 | "0x%llx\n"); | ||
156 | 185 | ||
157 | static int scom_debug_init_one(struct dentry *root, struct device_node *dn, | 186 | static 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 | } |