diff options
| -rw-r--r-- | drivers/mtd/mtdpart.c | 324 |
1 files changed, 166 insertions, 158 deletions
diff --git a/drivers/mtd/mtdpart.c b/drivers/mtd/mtdpart.c index 56a760a736a9..45c6f32b0bf1 100644 --- a/drivers/mtd/mtdpart.c +++ b/drivers/mtd/mtdpart.c | |||
| @@ -313,6 +313,170 @@ int del_mtd_partitions(struct mtd_info *master) | |||
| 313 | return 0; | 313 | return 0; |
| 314 | } | 314 | } |
| 315 | 315 | ||
| 316 | static struct mtd_part *add_one_partition(struct mtd_info *master, | ||
| 317 | const struct mtd_partition *part, int partno, | ||
| 318 | u_int32_t cur_offset) | ||
| 319 | { | ||
| 320 | struct mtd_part *slave; | ||
| 321 | |||
| 322 | /* allocate the partition structure */ | ||
| 323 | slave = kzalloc (sizeof(*slave), GFP_KERNEL); | ||
| 324 | if (!slave) { | ||
| 325 | printk("memory allocation error while creating partitions for \"%s\"\n", | ||
| 326 | master->name); | ||
| 327 | del_mtd_partitions(master); | ||
| 328 | return NULL; | ||
| 329 | } | ||
| 330 | list_add(&slave->list, &mtd_partitions); | ||
| 331 | |||
| 332 | /* set up the MTD object for this partition */ | ||
| 333 | slave->mtd.type = master->type; | ||
| 334 | slave->mtd.flags = master->flags & ~part->mask_flags; | ||
| 335 | slave->mtd.size = part->size; | ||
| 336 | slave->mtd.writesize = master->writesize; | ||
| 337 | slave->mtd.oobsize = master->oobsize; | ||
| 338 | slave->mtd.oobavail = master->oobavail; | ||
| 339 | slave->mtd.subpage_sft = master->subpage_sft; | ||
| 340 | |||
| 341 | slave->mtd.name = part->name; | ||
| 342 | slave->mtd.owner = master->owner; | ||
| 343 | |||
| 344 | slave->mtd.read = part_read; | ||
| 345 | slave->mtd.write = part_write; | ||
| 346 | |||
| 347 | if (master->panic_write) | ||
| 348 | slave->mtd.panic_write = part_panic_write; | ||
| 349 | |||
| 350 | if(master->point && master->unpoint){ | ||
| 351 | slave->mtd.point = part_point; | ||
| 352 | slave->mtd.unpoint = part_unpoint; | ||
| 353 | } | ||
| 354 | |||
| 355 | if (master->read_oob) | ||
| 356 | slave->mtd.read_oob = part_read_oob; | ||
| 357 | if (master->write_oob) | ||
| 358 | slave->mtd.write_oob = part_write_oob; | ||
| 359 | if(master->read_user_prot_reg) | ||
| 360 | slave->mtd.read_user_prot_reg = part_read_user_prot_reg; | ||
| 361 | if(master->read_fact_prot_reg) | ||
| 362 | slave->mtd.read_fact_prot_reg = part_read_fact_prot_reg; | ||
| 363 | if(master->write_user_prot_reg) | ||
| 364 | slave->mtd.write_user_prot_reg = part_write_user_prot_reg; | ||
| 365 | if(master->lock_user_prot_reg) | ||
| 366 | slave->mtd.lock_user_prot_reg = part_lock_user_prot_reg; | ||
| 367 | if(master->get_user_prot_info) | ||
| 368 | slave->mtd.get_user_prot_info = part_get_user_prot_info; | ||
| 369 | if(master->get_fact_prot_info) | ||
| 370 | slave->mtd.get_fact_prot_info = part_get_fact_prot_info; | ||
| 371 | if (master->sync) | ||
| 372 | slave->mtd.sync = part_sync; | ||
| 373 | if (!partno && master->suspend && master->resume) { | ||
| 374 | slave->mtd.suspend = part_suspend; | ||
| 375 | slave->mtd.resume = part_resume; | ||
| 376 | } | ||
| 377 | if (master->writev) | ||
| 378 | slave->mtd.writev = part_writev; | ||
| 379 | if (master->lock) | ||
| 380 | slave->mtd.lock = part_lock; | ||
| 381 | if (master->unlock) | ||
| 382 | slave->mtd.unlock = part_unlock; | ||
| 383 | if (master->block_isbad) | ||
| 384 | slave->mtd.block_isbad = part_block_isbad; | ||
| 385 | if (master->block_markbad) | ||
| 386 | slave->mtd.block_markbad = part_block_markbad; | ||
| 387 | slave->mtd.erase = part_erase; | ||
| 388 | slave->master = master; | ||
| 389 | slave->offset = part->offset; | ||
| 390 | slave->index = partno; | ||
| 391 | |||
| 392 | if (slave->offset == MTDPART_OFS_APPEND) | ||
| 393 | slave->offset = cur_offset; | ||
| 394 | if (slave->offset == MTDPART_OFS_NXTBLK) { | ||
| 395 | slave->offset = cur_offset; | ||
| 396 | if ((cur_offset % master->erasesize) != 0) { | ||
| 397 | /* Round up to next erasesize */ | ||
| 398 | slave->offset = ((cur_offset / master->erasesize) + 1) * master->erasesize; | ||
| 399 | printk(KERN_NOTICE "Moving partition %d: " | ||
| 400 | "0x%08x -> 0x%08x\n", partno, | ||
| 401 | cur_offset, slave->offset); | ||
| 402 | } | ||
| 403 | } | ||
| 404 | if (slave->mtd.size == MTDPART_SIZ_FULL) | ||
| 405 | slave->mtd.size = master->size - slave->offset; | ||
| 406 | |||
| 407 | printk (KERN_NOTICE "0x%08x-0x%08x : \"%s\"\n", slave->offset, | ||
| 408 | slave->offset + slave->mtd.size, slave->mtd.name); | ||
| 409 | |||
| 410 | /* let's do some sanity checks */ | ||
| 411 | if (slave->offset >= master->size) { | ||
| 412 | /* let's register it anyway to preserve ordering */ | ||
| 413 | slave->offset = 0; | ||
| 414 | slave->mtd.size = 0; | ||
| 415 | printk ("mtd: partition \"%s\" is out of reach -- disabled\n", | ||
| 416 | part->name); | ||
| 417 | } | ||
| 418 | if (slave->offset + slave->mtd.size > master->size) { | ||
| 419 | slave->mtd.size = master->size - slave->offset; | ||
| 420 | printk ("mtd: partition \"%s\" extends beyond the end of device \"%s\" -- size truncated to %#x\n", | ||
| 421 | part->name, master->name, slave->mtd.size); | ||
| 422 | } | ||
| 423 | if (master->numeraseregions>1) { | ||
| 424 | /* Deal with variable erase size stuff */ | ||
| 425 | int i; | ||
| 426 | struct mtd_erase_region_info *regions = master->eraseregions; | ||
| 427 | |||
| 428 | /* Find the first erase regions which is part of this partition. */ | ||
| 429 | for (i=0; i < master->numeraseregions && regions[i].offset <= slave->offset; i++) | ||
| 430 | ; | ||
| 431 | |||
| 432 | for (i--; i < master->numeraseregions && regions[i].offset < slave->offset + slave->mtd.size; i++) { | ||
| 433 | if (slave->mtd.erasesize < regions[i].erasesize) { | ||
| 434 | slave->mtd.erasesize = regions[i].erasesize; | ||
| 435 | } | ||
| 436 | } | ||
| 437 | } else { | ||
| 438 | /* Single erase size */ | ||
| 439 | slave->mtd.erasesize = master->erasesize; | ||
| 440 | } | ||
| 441 | |||
| 442 | if ((slave->mtd.flags & MTD_WRITEABLE) && | ||
| 443 | (slave->offset % slave->mtd.erasesize)) { | ||
| 444 | /* Doesn't start on a boundary of major erase size */ | ||
| 445 | /* FIXME: Let it be writable if it is on a boundary of _minor_ erase size though */ | ||
| 446 | slave->mtd.flags &= ~MTD_WRITEABLE; | ||
| 447 | printk ("mtd: partition \"%s\" doesn't start on an erase block boundary -- force read-only\n", | ||
| 448 | part->name); | ||
| 449 | } | ||
| 450 | if ((slave->mtd.flags & MTD_WRITEABLE) && | ||
| 451 | (slave->mtd.size % slave->mtd.erasesize)) { | ||
| 452 | slave->mtd.flags &= ~MTD_WRITEABLE; | ||
| 453 | printk ("mtd: partition \"%s\" doesn't end on an erase block -- force read-only\n", | ||
| 454 | part->name); | ||
| 455 | } | ||
| 456 | |||
| 457 | slave->mtd.ecclayout = master->ecclayout; | ||
| 458 | if (master->block_isbad) { | ||
| 459 | uint32_t offs = 0; | ||
| 460 | |||
| 461 | while(offs < slave->mtd.size) { | ||
| 462 | if (master->block_isbad(master, | ||
| 463 | offs + slave->offset)) | ||
| 464 | slave->mtd.ecc_stats.badblocks++; | ||
| 465 | offs += slave->mtd.erasesize; | ||
| 466 | } | ||
| 467 | } | ||
| 468 | |||
| 469 | if(part->mtdp) { /* store the object pointer (caller may or may not register it */ | ||
| 470 | *part->mtdp = &slave->mtd; | ||
| 471 | slave->registered = 0; | ||
| 472 | } else { | ||
| 473 | /* register our partition */ | ||
| 474 | add_mtd_device(&slave->mtd); | ||
| 475 | slave->registered = 1; | ||
| 476 | } | ||
| 477 | return slave; | ||
| 478 | } | ||
| 479 | |||
| 316 | /* | 480 | /* |
| 317 | * This function, given a master MTD object and a partition table, creates | 481 | * This function, given a master MTD object and a partition table, creates |
| 318 | * and registers slave MTD objects which are bound to the master according to | 482 | * and registers slave MTD objects which are bound to the master according to |
| @@ -331,166 +495,10 @@ int add_mtd_partitions(struct mtd_info *master, | |||
| 331 | printk (KERN_NOTICE "Creating %d MTD partitions on \"%s\":\n", nbparts, master->name); | 495 | printk (KERN_NOTICE "Creating %d MTD partitions on \"%s\":\n", nbparts, master->name); |
| 332 | 496 | ||
| 333 | for (i = 0; i < nbparts; i++) { | 497 | for (i = 0; i < nbparts; i++) { |
| 334 | 498 | slave = add_one_partition(master, parts + i, i, cur_offset); | |
| 335 | /* allocate the partition structure */ | 499 | if (!slave) |
| 336 | slave = kzalloc (sizeof(*slave), GFP_KERNEL); | ||
| 337 | if (!slave) { | ||
| 338 | printk ("memory allocation error while creating partitions for \"%s\"\n", | ||
| 339 | master->name); | ||
| 340 | del_mtd_partitions(master); | ||
| 341 | return -ENOMEM; | 500 | return -ENOMEM; |
| 342 | } | ||
| 343 | list_add(&slave->list, &mtd_partitions); | ||
| 344 | |||
| 345 | /* set up the MTD object for this partition */ | ||
| 346 | slave->mtd.type = master->type; | ||
| 347 | slave->mtd.flags = master->flags & ~parts[i].mask_flags; | ||
| 348 | slave->mtd.size = parts[i].size; | ||
| 349 | slave->mtd.writesize = master->writesize; | ||
| 350 | slave->mtd.oobsize = master->oobsize; | ||
| 351 | slave->mtd.oobavail = master->oobavail; | ||
| 352 | slave->mtd.subpage_sft = master->subpage_sft; | ||
| 353 | |||
| 354 | slave->mtd.name = parts[i].name; | ||
| 355 | slave->mtd.owner = master->owner; | ||
| 356 | |||
| 357 | slave->mtd.read = part_read; | ||
| 358 | slave->mtd.write = part_write; | ||
| 359 | |||
| 360 | if (master->panic_write) | ||
| 361 | slave->mtd.panic_write = part_panic_write; | ||
| 362 | |||
| 363 | if(master->point && master->unpoint){ | ||
| 364 | slave->mtd.point = part_point; | ||
| 365 | slave->mtd.unpoint = part_unpoint; | ||
| 366 | } | ||
| 367 | |||
| 368 | if (master->read_oob) | ||
| 369 | slave->mtd.read_oob = part_read_oob; | ||
| 370 | if (master->write_oob) | ||
| 371 | slave->mtd.write_oob = part_write_oob; | ||
| 372 | if(master->read_user_prot_reg) | ||
| 373 | slave->mtd.read_user_prot_reg = part_read_user_prot_reg; | ||
| 374 | if(master->read_fact_prot_reg) | ||
| 375 | slave->mtd.read_fact_prot_reg = part_read_fact_prot_reg; | ||
| 376 | if(master->write_user_prot_reg) | ||
| 377 | slave->mtd.write_user_prot_reg = part_write_user_prot_reg; | ||
| 378 | if(master->lock_user_prot_reg) | ||
| 379 | slave->mtd.lock_user_prot_reg = part_lock_user_prot_reg; | ||
| 380 | if(master->get_user_prot_info) | ||
| 381 | slave->mtd.get_user_prot_info = part_get_user_prot_info; | ||
| 382 | if(master->get_fact_prot_info) | ||
| 383 | slave->mtd.get_fact_prot_info = part_get_fact_prot_info; | ||
| 384 | if (master->sync) | ||
| 385 | slave->mtd.sync = part_sync; | ||
| 386 | if (!i && master->suspend && master->resume) { | ||
| 387 | slave->mtd.suspend = part_suspend; | ||
| 388 | slave->mtd.resume = part_resume; | ||
| 389 | } | ||
| 390 | if (master->writev) | ||
| 391 | slave->mtd.writev = part_writev; | ||
| 392 | if (master->lock) | ||
| 393 | slave->mtd.lock = part_lock; | ||
| 394 | if (master->unlock) | ||
| 395 | slave->mtd.unlock = part_unlock; | ||
| 396 | if (master->block_isbad) | ||
| 397 | slave->mtd.block_isbad = part_block_isbad; | ||
| 398 | if (master->block_markbad) | ||
| 399 | slave->mtd.block_markbad = part_block_markbad; | ||
| 400 | slave->mtd.erase = part_erase; | ||
| 401 | slave->master = master; | ||
| 402 | slave->offset = parts[i].offset; | ||
| 403 | slave->index = i; | ||
| 404 | |||
| 405 | if (slave->offset == MTDPART_OFS_APPEND) | ||
| 406 | slave->offset = cur_offset; | ||
| 407 | if (slave->offset == MTDPART_OFS_NXTBLK) { | ||
| 408 | slave->offset = cur_offset; | ||
| 409 | if ((cur_offset % master->erasesize) != 0) { | ||
| 410 | /* Round up to next erasesize */ | ||
| 411 | slave->offset = ((cur_offset / master->erasesize) + 1) * master->erasesize; | ||
| 412 | printk(KERN_NOTICE "Moving partition %d: " | ||
| 413 | "0x%08x -> 0x%08x\n", i, | ||
| 414 | cur_offset, slave->offset); | ||
| 415 | } | ||
| 416 | } | ||
| 417 | if (slave->mtd.size == MTDPART_SIZ_FULL) | ||
| 418 | slave->mtd.size = master->size - slave->offset; | ||
| 419 | cur_offset = slave->offset + slave->mtd.size; | 501 | cur_offset = slave->offset + slave->mtd.size; |
| 420 | |||
| 421 | printk (KERN_NOTICE "0x%08x-0x%08x : \"%s\"\n", slave->offset, | ||
| 422 | slave->offset + slave->mtd.size, slave->mtd.name); | ||
| 423 | |||
| 424 | /* let's do some sanity checks */ | ||
| 425 | if (slave->offset >= master->size) { | ||
| 426 | /* let's register it anyway to preserve ordering */ | ||
| 427 | slave->offset = 0; | ||
| 428 | slave->mtd.size = 0; | ||
| 429 | printk ("mtd: partition \"%s\" is out of reach -- disabled\n", | ||
| 430 | parts[i].name); | ||
| 431 | } | ||
| 432 | if (slave->offset + slave->mtd.size > master->size) { | ||
| 433 | slave->mtd.size = master->size - slave->offset; | ||
| 434 | printk ("mtd: partition \"%s\" extends beyond the end of device \"%s\" -- size truncated to %#x\n", | ||
| 435 | parts[i].name, master->name, slave->mtd.size); | ||
| 436 | } | ||
| 437 | if (master->numeraseregions>1) { | ||
| 438 | /* Deal with variable erase size stuff */ | ||
| 439 | int i; | ||
| 440 | struct mtd_erase_region_info *regions = master->eraseregions; | ||
| 441 | |||
| 442 | /* Find the first erase regions which is part of this partition. */ | ||
| 443 | for (i=0; i < master->numeraseregions && slave->offset >= regions[i].offset; i++) | ||
| 444 | ; | ||
| 445 | |||
| 446 | for (i--; i < master->numeraseregions && slave->offset + slave->mtd.size > regions[i].offset; i++) { | ||
| 447 | if (slave->mtd.erasesize < regions[i].erasesize) { | ||
| 448 | slave->mtd.erasesize = regions[i].erasesize; | ||
| 449 | } | ||
| 450 | } | ||
| 451 | } else { | ||
| 452 | /* Single erase size */ | ||
| 453 | slave->mtd.erasesize = master->erasesize; | ||
| 454 | } | ||
| 455 | |||
| 456 | if ((slave->mtd.flags & MTD_WRITEABLE) && | ||
| 457 | (slave->offset % slave->mtd.erasesize)) { | ||
| 458 | /* Doesn't start on a boundary of major erase size */ | ||
| 459 | /* FIXME: Let it be writable if it is on a boundary of _minor_ erase size though */ | ||
| 460 | slave->mtd.flags &= ~MTD_WRITEABLE; | ||
| 461 | printk ("mtd: partition \"%s\" doesn't start on an erase block boundary -- force read-only\n", | ||
| 462 | parts[i].name); | ||
| 463 | } | ||
| 464 | if ((slave->mtd.flags & MTD_WRITEABLE) && | ||
| 465 | (slave->mtd.size % slave->mtd.erasesize)) { | ||
| 466 | slave->mtd.flags &= ~MTD_WRITEABLE; | ||
| 467 | printk ("mtd: partition \"%s\" doesn't end on an erase block -- force read-only\n", | ||
| 468 | parts[i].name); | ||
| 469 | } | ||
| 470 | |||
| 471 | slave->mtd.ecclayout = master->ecclayout; | ||
| 472 | if (master->block_isbad) { | ||
| 473 | uint32_t offs = 0; | ||
| 474 | |||
| 475 | while(offs < slave->mtd.size) { | ||
| 476 | if (master->block_isbad(master, | ||
| 477 | offs + slave->offset)) | ||
| 478 | slave->mtd.ecc_stats.badblocks++; | ||
| 479 | offs += slave->mtd.erasesize; | ||
| 480 | } | ||
| 481 | } | ||
| 482 | |||
| 483 | if(parts[i].mtdp) | ||
| 484 | { /* store the object pointer (caller may or may not register it */ | ||
| 485 | *parts[i].mtdp = &slave->mtd; | ||
| 486 | slave->registered = 0; | ||
| 487 | } | ||
| 488 | else | ||
| 489 | { | ||
| 490 | /* register our partition */ | ||
| 491 | add_mtd_device(&slave->mtd); | ||
| 492 | slave->registered = 1; | ||
| 493 | } | ||
| 494 | } | 502 | } |
| 495 | 503 | ||
| 496 | return 0; | 504 | return 0; |
