aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorSonny Rao <sonnyrao@us.ibm.com>2008-11-09 09:15:11 -0500
committerPaul Mackerras <paulus@samba.org>2008-12-03 05:03:27 -0500
commita0e2f9f4a2487572803d5a00c7302db30e4c60d3 (patch)
tree91cdfc6ada0f25d0b84944e4abdd9b84e2a0bcb6
parent6358d6cb328a772eb6f02c870da61709d539480f (diff)
powerpc/BSR: Support multiple OF-node description of BSR
This adds support for multiple BSR nodes in the OF device tree. Previously, the BSR driver only supported a single OF node describing a BSR. Apparently when an LPAR is set to use "all system resources" the BSR appears as a single node, but when it is handed out in pieces, each 8 byte piece gets its own node. So, this keeps a list of BSR devices instead of the array and includes all nodes. Also, this makes the code be more inclusive of what BSR devices we accept by only checking compatibility and not the device name property (which might change in the future versions of BSR). Signed-off-by: Sonny Rao <sonnyrao@us.ibm.com> Signed-off-by: Paul Mackerras <paulus@samba.org>
-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