aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorBen Hutchings <bhutchings@solarflare.com>2010-01-29 15:59:42 -0500
committerDavid Woodhouse <David.Woodhouse@intel.com>2010-02-25 06:55:14 -0500
commitb520e412faaaad35641aeedd6059179f9f1b393c (patch)
treed49554d8972d8e9360155fcda648636be350ceaa
parent4d1ee80f3a7df7fe9cdec26e651e6201c45b10d4 (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.c151
-rw-r--r--drivers/mtd/mtdcore.h12
-rw-r--r--include/linux/mtd/mtd.h1
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
37static 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 */
38DEFINE_MUTEX(mtd_table_mutex); 41DEFINE_MUTEX(mtd_table_mutex);
39struct mtd_info *mtd_table[MAX_MTD_DEVICES];
40
41EXPORT_SYMBOL_GPL(mtd_table_mutex); 42EXPORT_SYMBOL_GPL(mtd_table_mutex);
42EXPORT_SYMBOL_GPL(mtd_table); 43
44struct mtd_info *__mtd_next_device(int i)
45{
46 return idr_get_next(&mtd_idr, &i);
47}
48EXPORT_SYMBOL_GPL(__mtd_next_device);
43 49
44static LIST_HEAD(mtd_notifiers); 50static 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
242int add_mtd_device(struct mtd_info *mtd) 247int 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
333fail_added:
334 idr_remove(&mtd_idr, i);
335fail_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 }
diff --git a/drivers/mtd/mtdcore.h b/drivers/mtd/mtdcore.h
index e2f93a300738..6a64fdebc898 100644
--- a/drivers/mtd/mtdcore.h
+++ b/drivers/mtd/mtdcore.h
@@ -8,17 +8,7 @@
8 should not use them for _anything_ else */ 8 should not use them for _anything_ else */
9 9
10extern struct mutex mtd_table_mutex; 10extern struct mutex mtd_table_mutex;
11extern struct mtd_info *mtd_table[MAX_MTD_DEVICES]; 11extern struct mtd_info *__mtd_next_device(int i);
12
13static inline struct mtd_info *__mtd_next_device(int i)
14{
15 while (i < MAX_MTD_DEVICES) {
16 if (mtd_table[i])
17 return mtd_table[i];
18 i++;
19 }
20 return NULL;
21}
22 12
23#define mtd_for_each_device(mtd) \ 13#define mtd_for_each_device(mtd) \
24 for ((mtd) = __mtd_next_device(0); \ 14 for ((mtd) = __mtd_next_device(0); \
diff --git a/include/linux/mtd/mtd.h b/include/linux/mtd/mtd.h
index 0f32a9b6ff55..ba53ecca107c 100644
--- a/include/linux/mtd/mtd.h
+++ b/include/linux/mtd/mtd.h
@@ -20,7 +20,6 @@
20 20
21#define MTD_CHAR_MAJOR 90 21#define MTD_CHAR_MAJOR 90
22#define MTD_BLOCK_MAJOR 31 22#define MTD_BLOCK_MAJOR 31
23#define MAX_MTD_DEVICES 32
24 23
25#define MTD_ERASE_PENDING 0x01 24#define MTD_ERASE_PENDING 0x01
26#define MTD_ERASING 0x02 25#define MTD_ERASING 0x02