diff options
author | Ben Hutchings <bhutchings@solarflare.com> | 2010-01-29 15:59:42 -0500 |
---|---|---|
committer | David Woodhouse <David.Woodhouse@intel.com> | 2010-02-25 06:55:14 -0500 |
commit | b520e412faaaad35641aeedd6059179f9f1b393c (patch) | |
tree | d49554d8972d8e9360155fcda648636be350ceaa /drivers/mtd/mtdcore.c | |
parent | 4d1ee80f3a7df7fe9cdec26e651e6201c45b10d4 (diff) |
mtd: Replace static array of devices with an idr structure
Signed-off-by: Ben Hutchings <bhutchings@solarflare.com>
Signed-off-by: Artem Bityutskiy <Artem.Bityutskiy@nokia.com>
Signed-off-by: David Woodhouse <David.Woodhouse@intel.com>
Diffstat (limited to 'drivers/mtd/mtdcore.c')
-rw-r--r-- | drivers/mtd/mtdcore.c | 151 |
1 files changed, 80 insertions, 71 deletions
diff --git a/drivers/mtd/mtdcore.c b/drivers/mtd/mtdcore.c index 402d41723c3..b3b98d1fffc 100644 --- a/drivers/mtd/mtdcore.c +++ b/drivers/mtd/mtdcore.c | |||
@@ -17,6 +17,7 @@ | |||
17 | #include <linux/init.h> | 17 | #include <linux/init.h> |
18 | #include <linux/mtd/compatmac.h> | 18 | #include <linux/mtd/compatmac.h> |
19 | #include <linux/proc_fs.h> | 19 | #include <linux/proc_fs.h> |
20 | #include <linux/idr.h> | ||
20 | 21 | ||
21 | #include <linux/mtd/mtd.h> | 22 | #include <linux/mtd/mtd.h> |
22 | #include "internal.h" | 23 | #include "internal.h" |
@@ -33,13 +34,18 @@ static struct class mtd_class = { | |||
33 | .resume = mtd_cls_resume, | 34 | .resume = mtd_cls_resume, |
34 | }; | 35 | }; |
35 | 36 | ||
37 | static DEFINE_IDR(mtd_idr); | ||
38 | |||
36 | /* These are exported solely for the purpose of mtd_blkdevs.c. You | 39 | /* These are exported solely for the purpose of mtd_blkdevs.c. You |
37 | should not use them for _anything_ else */ | 40 | should not use them for _anything_ else */ |
38 | DEFINE_MUTEX(mtd_table_mutex); | 41 | DEFINE_MUTEX(mtd_table_mutex); |
39 | struct mtd_info *mtd_table[MAX_MTD_DEVICES]; | ||
40 | |||
41 | EXPORT_SYMBOL_GPL(mtd_table_mutex); | 42 | EXPORT_SYMBOL_GPL(mtd_table_mutex); |
42 | EXPORT_SYMBOL_GPL(mtd_table); | 43 | |
44 | struct mtd_info *__mtd_next_device(int i) | ||
45 | { | ||
46 | return idr_get_next(&mtd_idr, &i); | ||
47 | } | ||
48 | EXPORT_SYMBOL_GPL(__mtd_next_device); | ||
43 | 49 | ||
44 | static LIST_HEAD(mtd_notifiers); | 50 | static LIST_HEAD(mtd_notifiers); |
45 | 51 | ||
@@ -235,13 +241,13 @@ static struct device_type mtd_devtype = { | |||
235 | * Add a device to the list of MTD devices present in the system, and | 241 | * Add a device to the list of MTD devices present in the system, and |
236 | * notify each currently active MTD 'user' of its arrival. Returns | 242 | * notify each currently active MTD 'user' of its arrival. Returns |
237 | * zero on success or 1 on failure, which currently will only happen | 243 | * zero on success or 1 on failure, which currently will only happen |
238 | * if the number of present devices exceeds MAX_MTD_DEVICES (i.e. 16) | 244 | * if there is insufficient memory or a sysfs error. |
239 | * or there's a sysfs error. | ||
240 | */ | 245 | */ |
241 | 246 | ||
242 | int add_mtd_device(struct mtd_info *mtd) | 247 | int add_mtd_device(struct mtd_info *mtd) |
243 | { | 248 | { |
244 | int i; | 249 | struct mtd_notifier *not; |
250 | int i, error; | ||
245 | 251 | ||
246 | if (!mtd->backing_dev_info) { | 252 | if (!mtd->backing_dev_info) { |
247 | switch (mtd->type) { | 253 | switch (mtd->type) { |
@@ -260,70 +266,73 @@ int add_mtd_device(struct mtd_info *mtd) | |||
260 | BUG_ON(mtd->writesize == 0); | 266 | BUG_ON(mtd->writesize == 0); |
261 | mutex_lock(&mtd_table_mutex); | 267 | mutex_lock(&mtd_table_mutex); |
262 | 268 | ||
263 | for (i=0; i < MAX_MTD_DEVICES; i++) | 269 | do { |
264 | if (!mtd_table[i]) { | 270 | if (!idr_pre_get(&mtd_idr, GFP_KERNEL)) |
265 | struct mtd_notifier *not; | 271 | goto fail_locked; |
266 | 272 | error = idr_get_new(&mtd_idr, mtd, &i); | |
267 | mtd_table[i] = mtd; | 273 | } while (error == -EAGAIN); |
268 | mtd->index = i; | ||
269 | mtd->usecount = 0; | ||
270 | |||
271 | if (is_power_of_2(mtd->erasesize)) | ||
272 | mtd->erasesize_shift = ffs(mtd->erasesize) - 1; | ||
273 | else | ||
274 | mtd->erasesize_shift = 0; | ||
275 | |||
276 | if (is_power_of_2(mtd->writesize)) | ||
277 | mtd->writesize_shift = ffs(mtd->writesize) - 1; | ||
278 | else | ||
279 | mtd->writesize_shift = 0; | ||
280 | |||
281 | mtd->erasesize_mask = (1 << mtd->erasesize_shift) - 1; | ||
282 | mtd->writesize_mask = (1 << mtd->writesize_shift) - 1; | ||
283 | |||
284 | /* Some chips always power up locked. Unlock them now */ | ||
285 | if ((mtd->flags & MTD_WRITEABLE) | ||
286 | && (mtd->flags & MTD_POWERUP_LOCK) && mtd->unlock) { | ||
287 | if (mtd->unlock(mtd, 0, mtd->size)) | ||
288 | printk(KERN_WARNING | ||
289 | "%s: unlock failed, " | ||
290 | "writes may not work\n", | ||
291 | mtd->name); | ||
292 | } | ||
293 | 274 | ||
294 | /* Caller should have set dev.parent to match the | 275 | if (error) |
295 | * physical device. | 276 | goto fail_locked; |
296 | */ | ||
297 | mtd->dev.type = &mtd_devtype; | ||
298 | mtd->dev.class = &mtd_class; | ||
299 | mtd->dev.devt = MTD_DEVT(i); | ||
300 | dev_set_name(&mtd->dev, "mtd%d", i); | ||
301 | dev_set_drvdata(&mtd->dev, mtd); | ||
302 | if (device_register(&mtd->dev) != 0) { | ||
303 | mtd_table[i] = NULL; | ||
304 | break; | ||
305 | } | ||
306 | 277 | ||
307 | if (MTD_DEVT(i)) | 278 | mtd->index = i; |
308 | device_create(&mtd_class, mtd->dev.parent, | 279 | mtd->usecount = 0; |
309 | MTD_DEVT(i) + 1, | 280 | |
310 | NULL, "mtd%dro", i); | 281 | if (is_power_of_2(mtd->erasesize)) |
311 | 282 | mtd->erasesize_shift = ffs(mtd->erasesize) - 1; | |
312 | DEBUG(0, "mtd: Giving out device %d to %s\n",i, mtd->name); | 283 | else |
313 | /* No need to get a refcount on the module containing | 284 | mtd->erasesize_shift = 0; |
314 | the notifier, since we hold the mtd_table_mutex */ | 285 | |
315 | list_for_each_entry(not, &mtd_notifiers, list) | 286 | if (is_power_of_2(mtd->writesize)) |
316 | not->add(mtd); | 287 | mtd->writesize_shift = ffs(mtd->writesize) - 1; |
317 | 288 | else | |
318 | mutex_unlock(&mtd_table_mutex); | 289 | mtd->writesize_shift = 0; |
319 | /* We _know_ we aren't being removed, because | 290 | |
320 | our caller is still holding us here. So none | 291 | mtd->erasesize_mask = (1 << mtd->erasesize_shift) - 1; |
321 | of this try_ nonsense, and no bitching about it | 292 | mtd->writesize_mask = (1 << mtd->writesize_shift) - 1; |
322 | either. :) */ | 293 | |
323 | __module_get(THIS_MODULE); | 294 | /* Some chips always power up locked. Unlock them now */ |
324 | return 0; | 295 | if ((mtd->flags & MTD_WRITEABLE) |
325 | } | 296 | && (mtd->flags & MTD_POWERUP_LOCK) && mtd->unlock) { |
297 | if (mtd->unlock(mtd, 0, mtd->size)) | ||
298 | printk(KERN_WARNING | ||
299 | "%s: unlock failed, writes may not work\n", | ||
300 | mtd->name); | ||
301 | } | ||
302 | |||
303 | /* Caller should have set dev.parent to match the | ||
304 | * physical device. | ||
305 | */ | ||
306 | mtd->dev.type = &mtd_devtype; | ||
307 | mtd->dev.class = &mtd_class; | ||
308 | mtd->dev.devt = MTD_DEVT(i); | ||
309 | dev_set_name(&mtd->dev, "mtd%d", i); | ||
310 | dev_set_drvdata(&mtd->dev, mtd); | ||
311 | if (device_register(&mtd->dev) != 0) | ||
312 | goto fail_added; | ||
313 | |||
314 | if (MTD_DEVT(i)) | ||
315 | device_create(&mtd_class, mtd->dev.parent, | ||
316 | MTD_DEVT(i) + 1, | ||
317 | NULL, "mtd%dro", i); | ||
318 | |||
319 | DEBUG(0, "mtd: Giving out device %d to %s\n", i, mtd->name); | ||
320 | /* No need to get a refcount on the module containing | ||
321 | the notifier, since we hold the mtd_table_mutex */ | ||
322 | list_for_each_entry(not, &mtd_notifiers, list) | ||
323 | not->add(mtd); | ||
324 | |||
325 | mutex_unlock(&mtd_table_mutex); | ||
326 | /* We _know_ we aren't being removed, because | ||
327 | our caller is still holding us here. So none | ||
328 | of this try_ nonsense, and no bitching about it | ||
329 | either. :) */ | ||
330 | __module_get(THIS_MODULE); | ||
331 | return 0; | ||
326 | 332 | ||
333 | fail_added: | ||
334 | idr_remove(&mtd_idr, i); | ||
335 | fail_locked: | ||
327 | mutex_unlock(&mtd_table_mutex); | 336 | mutex_unlock(&mtd_table_mutex); |
328 | return 1; | 337 | return 1; |
329 | } | 338 | } |
@@ -344,7 +353,7 @@ int del_mtd_device (struct mtd_info *mtd) | |||
344 | 353 | ||
345 | mutex_lock(&mtd_table_mutex); | 354 | mutex_lock(&mtd_table_mutex); |
346 | 355 | ||
347 | if (mtd_table[mtd->index] != mtd) { | 356 | if (idr_find(&mtd_idr, mtd->index) != mtd) { |
348 | ret = -ENODEV; | 357 | ret = -ENODEV; |
349 | } else if (mtd->usecount) { | 358 | } else if (mtd->usecount) { |
350 | printk(KERN_NOTICE "Removing MTD device #%d (%s) with use count %d\n", | 359 | printk(KERN_NOTICE "Removing MTD device #%d (%s) with use count %d\n", |
@@ -360,7 +369,7 @@ int del_mtd_device (struct mtd_info *mtd) | |||
360 | list_for_each_entry(not, &mtd_notifiers, list) | 369 | list_for_each_entry(not, &mtd_notifiers, list) |
361 | not->remove(mtd); | 370 | not->remove(mtd); |
362 | 371 | ||
363 | mtd_table[mtd->index] = NULL; | 372 | idr_remove(&mtd_idr, mtd->index); |
364 | 373 | ||
365 | module_put(THIS_MODULE); | 374 | module_put(THIS_MODULE); |
366 | ret = 0; | 375 | ret = 0; |
@@ -448,8 +457,8 @@ struct mtd_info *get_mtd_device(struct mtd_info *mtd, int num) | |||
448 | break; | 457 | break; |
449 | } | 458 | } |
450 | } | 459 | } |
451 | } else if (num >= 0 && num < MAX_MTD_DEVICES) { | 460 | } else if (num >= 0) { |
452 | ret = mtd_table[num]; | 461 | ret = idr_find(&mtd_idr, num); |
453 | if (mtd && mtd != ret) | 462 | if (mtd && mtd != ret) |
454 | ret = NULL; | 463 | ret = NULL; |
455 | } | 464 | } |