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 | |
| 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>
| -rw-r--r-- | drivers/mtd/mtdcore.c | 151 | ||||
| -rw-r--r-- | drivers/mtd/mtdcore.h | 12 | ||||
| -rw-r--r-- | include/linux/mtd/mtd.h | 1 |
3 files changed, 81 insertions, 83 deletions
diff --git a/drivers/mtd/mtdcore.c b/drivers/mtd/mtdcore.c index 402d41723c3f..b3b98d1fffc3 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); |
