aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/char/bsr.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/char/bsr.c')
-rw-r--r--drivers/char/bsr.c84
1 files changed, 55 insertions, 29 deletions
diff --git a/drivers/char/bsr.c b/drivers/char/bsr.c
index 456f54db73e2..977dfb1096a0 100644
--- a/drivers/char/bsr.c
+++ b/drivers/char/bsr.c
@@ -60,6 +60,8 @@ struct bsr_dev {
60 unsigned bsr_num; /* bsr id number for its type */ 60 unsigned bsr_num; /* bsr id number for its type */
61 int bsr_minor; 61 int bsr_minor;
62 62
63 struct list_head bsr_list;
64
63 dev_t bsr_dev; 65 dev_t bsr_dev;
64 struct cdev bsr_cdev; 66 struct cdev bsr_cdev;
65 struct device *bsr_device; 67 struct device *bsr_device;
@@ -67,8 +69,8 @@ struct bsr_dev {
67 69
68}; 70};
69 71
70static unsigned num_bsr_devs; 72static unsigned total_bsr_devs;
71static struct bsr_dev *bsr_devs; 73static struct list_head bsr_devs = LIST_HEAD_INIT(bsr_devs);
72static struct class *bsr_class; 74static struct class *bsr_class;
73static int bsr_major; 75static int bsr_major;
74 76
@@ -146,24 +148,25 @@ const static struct file_operations bsr_fops = {
146 148
147static void bsr_cleanup_devs(void) 149static void bsr_cleanup_devs(void)
148{ 150{
149 int i; 151 struct bsr_dev *cur, *n;
150 for (i=0 ; i < num_bsr_devs; i++) { 152
151 struct bsr_dev *cur = bsr_devs + i; 153 list_for_each_entry_safe(cur, n, &bsr_devs, bsr_list) {
152 if (cur->bsr_device) { 154 if (cur->bsr_device) {
153 cdev_del(&cur->bsr_cdev); 155 cdev_del(&cur->bsr_cdev);
154 device_del(cur->bsr_device); 156 device_del(cur->bsr_device);
155 } 157 }
158 list_del(&cur->bsr_list);
159 kfree(cur);
156 } 160 }
157
158 kfree(bsr_devs);
159} 161}
160 162
161static int bsr_create_devs(struct device_node *bn) 163static int bsr_add_node(struct device_node *bn)
162{ 164{
163 int bsr_stride_len, bsr_bytes_len; 165 int bsr_stride_len, bsr_bytes_len, num_bsr_devs;
164 const u32 *bsr_stride; 166 const u32 *bsr_stride;
165 const u32 *bsr_bytes; 167 const u32 *bsr_bytes;
166 unsigned i; 168 unsigned i;
169 int ret = -ENODEV;
167 170
168 bsr_stride = of_get_property(bn, "ibm,lock-stride", &bsr_stride_len); 171 bsr_stride = of_get_property(bn, "ibm,lock-stride", &bsr_stride_len);
169 bsr_bytes = of_get_property(bn, "ibm,#lock-bytes", &bsr_bytes_len); 172 bsr_bytes = of_get_property(bn, "ibm,#lock-bytes", &bsr_bytes_len);
@@ -171,35 +174,36 @@ static int bsr_create_devs(struct device_node *bn)
171 if (!bsr_stride || !bsr_bytes || 174 if (!bsr_stride || !bsr_bytes ||
172 (bsr_stride_len != bsr_bytes_len)) { 175 (bsr_stride_len != bsr_bytes_len)) {
173 printk(KERN_ERR "bsr of-node has missing/incorrect property\n"); 176 printk(KERN_ERR "bsr of-node has missing/incorrect property\n");
174 return -ENODEV; 177 return ret;
175 } 178 }
176 179
177 num_bsr_devs = bsr_bytes_len / sizeof(u32); 180 num_bsr_devs = bsr_bytes_len / sizeof(u32);
178 181
179 /* only a warning, its informational since we'll fail and exit */
180 WARN_ON(num_bsr_devs > BSR_MAX_DEVS);
181
182 bsr_devs = kzalloc(sizeof(struct bsr_dev) * num_bsr_devs, GFP_KERNEL);
183 if (!bsr_devs)
184 return -ENOMEM;
185
186 for (i = 0 ; i < num_bsr_devs; i++) { 182 for (i = 0 ; i < num_bsr_devs; i++) {
187 struct bsr_dev *cur = bsr_devs + i; 183 struct bsr_dev *cur = kzalloc(sizeof(struct bsr_dev),
184 GFP_KERNEL);
188 struct resource res; 185 struct resource res;
189 int result; 186 int result;
190 187
188 if (!cur) {
189 printk(KERN_ERR "Unable to alloc bsr dev\n");
190 ret = -ENOMEM;
191 goto out_err;
192 }
193
191 result = of_address_to_resource(bn, i, &res); 194 result = of_address_to_resource(bn, i, &res);
192 if (result < 0) { 195 if (result < 0) {
193 printk(KERN_ERR "bsr of-node has invalid reg property\n"); 196 printk(KERN_ERR "bsr of-node has invalid reg property, skipping\n");
194 goto out_err; 197 kfree(cur);
198 continue;
195 } 199 }
196 200
197 cur->bsr_minor = i; 201 cur->bsr_minor = i + total_bsr_devs;
198 cur->bsr_addr = res.start; 202 cur->bsr_addr = res.start;
199 cur->bsr_len = res.end - res.start + 1; 203 cur->bsr_len = res.end - res.start + 1;
200 cur->bsr_bytes = bsr_bytes[i]; 204 cur->bsr_bytes = bsr_bytes[i];
201 cur->bsr_stride = bsr_stride[i]; 205 cur->bsr_stride = bsr_stride[i];
202 cur->bsr_dev = MKDEV(bsr_major, i); 206 cur->bsr_dev = MKDEV(bsr_major, i + total_bsr_devs);
203 207
204 switch(cur->bsr_bytes) { 208 switch(cur->bsr_bytes) {
205 case 8: 209 case 8:
@@ -220,14 +224,15 @@ static int bsr_create_devs(struct device_node *bn)
220 } 224 }
221 225
222 cur->bsr_num = bsr_types[cur->bsr_type]; 226 cur->bsr_num = bsr_types[cur->bsr_type];
223 bsr_types[cur->bsr_type] = cur->bsr_num + 1;
224 snprintf(cur->bsr_name, 32, "bsr%d_%d", 227 snprintf(cur->bsr_name, 32, "bsr%d_%d",
225 cur->bsr_bytes, cur->bsr_num); 228 cur->bsr_bytes, cur->bsr_num);
226 229
227 cdev_init(&cur->bsr_cdev, &bsr_fops); 230 cdev_init(&cur->bsr_cdev, &bsr_fops);
228 result = cdev_add(&cur->bsr_cdev, cur->bsr_dev, 1); 231 result = cdev_add(&cur->bsr_cdev, cur->bsr_dev, 1);
229 if (result) 232 if (result) {
233 kfree(cur);
230 goto out_err; 234 goto out_err;
235 }
231 236
232 cur->bsr_device = device_create(bsr_class, NULL, cur->bsr_dev, 237 cur->bsr_device = device_create(bsr_class, NULL, cur->bsr_dev,
233 cur, cur->bsr_name); 238 cur, cur->bsr_name);
@@ -235,16 +240,37 @@ static int bsr_create_devs(struct device_node *bn)
235 printk(KERN_ERR "device_create failed for %s\n", 240 printk(KERN_ERR "device_create failed for %s\n",
236 cur->bsr_name); 241 cur->bsr_name);
237 cdev_del(&cur->bsr_cdev); 242 cdev_del(&cur->bsr_cdev);
243 kfree(cur);
238 goto out_err; 244 goto out_err;
239 } 245 }
246
247 bsr_types[cur->bsr_type] = cur->bsr_num + 1;
248 list_add_tail(&cur->bsr_list, &bsr_devs);
240 } 249 }
241 250
251 total_bsr_devs += num_bsr_devs;
252
242 return 0; 253 return 0;
243 254
244 out_err: 255 out_err:
245 256
246 bsr_cleanup_devs(); 257 bsr_cleanup_devs();
247 return -ENODEV; 258 return ret;
259}
260
261static int bsr_create_devs(struct device_node *bn)
262{
263 int ret;
264
265 while (bn) {
266 ret = bsr_add_node(bn);
267 if (ret) {
268 of_node_put(bn);
269 return ret;
270 }
271 bn = of_find_compatible_node(bn, NULL, "ibm,bsr");
272 }
273 return 0;
248} 274}
249 275
250static int __init bsr_init(void) 276static int __init bsr_init(void)
@@ -254,7 +280,7 @@ static int __init bsr_init(void)
254 int ret = -ENODEV; 280 int ret = -ENODEV;
255 int result; 281 int result;
256 282
257 np = of_find_compatible_node(NULL, "ibm,bsr", "ibm,bsr"); 283 np = of_find_compatible_node(NULL, NULL, "ibm,bsr");
258 if (!np) 284 if (!np)
259 goto out_err; 285 goto out_err;
260 286
@@ -272,10 +298,10 @@ static int __init bsr_init(void)
272 goto out_err_2; 298 goto out_err_2;
273 } 299 }
274 300
275 if ((ret = bsr_create_devs(np)) < 0) 301 if ((ret = bsr_create_devs(np)) < 0) {
302 np = NULL;
276 goto out_err_3; 303 goto out_err_3;
277 304 }
278 of_node_put(np);
279 305
280 return 0; 306 return 0;
281 307