diff options
author | Sonny Rao <sonnyrao@us.ibm.com> | 2008-11-09 09:15:11 -0500 |
---|---|---|
committer | Paul Mackerras <paulus@samba.org> | 2008-12-03 05:03:27 -0500 |
commit | a0e2f9f4a2487572803d5a00c7302db30e4c60d3 (patch) | |
tree | 91cdfc6ada0f25d0b84944e4abdd9b84e2a0bcb6 /drivers/char/bsr.c | |
parent | 6358d6cb328a772eb6f02c870da61709d539480f (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>
Diffstat (limited to 'drivers/char/bsr.c')
-rw-r--r-- | drivers/char/bsr.c | 84 |
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 | ||
70 | static unsigned num_bsr_devs; | 72 | static unsigned total_bsr_devs; |
71 | static struct bsr_dev *bsr_devs; | 73 | static struct list_head bsr_devs = LIST_HEAD_INIT(bsr_devs); |
72 | static struct class *bsr_class; | 74 | static struct class *bsr_class; |
73 | static int bsr_major; | 75 | static int bsr_major; |
74 | 76 | ||
@@ -146,24 +148,25 @@ const static struct file_operations bsr_fops = { | |||
146 | 148 | ||
147 | static void bsr_cleanup_devs(void) | 149 | static 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 | ||
161 | static int bsr_create_devs(struct device_node *bn) | 163 | static 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 | |||
261 | static 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 | ||
250 | static int __init bsr_init(void) | 276 | static 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 | ||