diff options
Diffstat (limited to 'arch/powerpc')
-rw-r--r-- | arch/powerpc/kernel/nvram_64.c | 108 |
1 files changed, 62 insertions, 46 deletions
diff --git a/arch/powerpc/kernel/nvram_64.c b/arch/powerpc/kernel/nvram_64.c index 02737e687559..eabee7c61183 100644 --- a/arch/powerpc/kernel/nvram_64.c +++ b/arch/powerpc/kernel/nvram_64.c | |||
@@ -313,9 +313,15 @@ static int __init nvram_remove_os_partition(void) | |||
313 | * @sig: signature of the partition to create | 313 | * @sig: signature of the partition to create |
314 | * @req_size: size of data to allocate in bytes | 314 | * @req_size: size of data to allocate in bytes |
315 | * @min_size: minimum acceptable size (0 means req_size) | 315 | * @min_size: minimum acceptable size (0 means req_size) |
316 | * | ||
317 | * Returns a negative error code or a positive nvram index | ||
318 | * of the beginning of the data area of the newly created | ||
319 | * partition. If you provided a min_size smaller than req_size | ||
320 | * you need to query for the actual size yourself after the | ||
321 | * call using nvram_partition_get_size(). | ||
316 | */ | 322 | */ |
317 | static int __init nvram_create_partition(const char *name, int sig, | 323 | static loff_t __init nvram_create_partition(const char *name, int sig, |
318 | int req_size, int min_size) | 324 | int req_size, int min_size) |
319 | { | 325 | { |
320 | struct nvram_partition *part; | 326 | struct nvram_partition *part; |
321 | struct nvram_partition *new_part; | 327 | struct nvram_partition *new_part; |
@@ -334,6 +340,8 @@ static int __init nvram_create_partition(const char *name, int sig, | |||
334 | */ | 340 | */ |
335 | if (min_size == 0) | 341 | if (min_size == 0) |
336 | min_size = req_size; | 342 | min_size = req_size; |
343 | if (min_size > req_size) | ||
344 | return -EINVAL; | ||
337 | 345 | ||
338 | /* Now add one block to each for the header */ | 346 | /* Now add one block to each for the header */ |
339 | req_size += 1; | 347 | req_size += 1; |
@@ -362,7 +370,7 @@ static int __init nvram_create_partition(const char *name, int sig, | |||
362 | /* Create our OS partition */ | 370 | /* Create our OS partition */ |
363 | new_part = kmalloc(sizeof(*new_part), GFP_KERNEL); | 371 | new_part = kmalloc(sizeof(*new_part), GFP_KERNEL); |
364 | if (!new_part) { | 372 | if (!new_part) { |
365 | printk(KERN_ERR "nvram_create_os_partition: kmalloc failed\n"); | 373 | pr_err("nvram_create_os_partition: kmalloc failed\n"); |
366 | return -ENOMEM; | 374 | return -ENOMEM; |
367 | } | 375 | } |
368 | 376 | ||
@@ -374,12 +382,29 @@ static int __init nvram_create_partition(const char *name, int sig, | |||
374 | 382 | ||
375 | rc = nvram_write_header(new_part); | 383 | rc = nvram_write_header(new_part); |
376 | if (rc <= 0) { | 384 | if (rc <= 0) { |
377 | printk(KERN_ERR "nvram_create_os_partition: nvram_write_header " | 385 | pr_err("nvram_create_os_partition: nvram_write_header " |
378 | "failed (%d)\n", rc); | 386 | "failed (%d)\n", rc); |
379 | return rc; | 387 | return rc; |
380 | } | 388 | } |
389 | list_add_tail(&new_part->partition, &free_part->partition); | ||
390 | |||
391 | /* Adjust or remove the partition we stole the space from */ | ||
392 | if (free_part->header.length > size) { | ||
393 | free_part->index += size * NVRAM_BLOCK_LEN; | ||
394 | free_part->header.length -= size; | ||
395 | free_part->header.checksum = nvram_checksum(&free_part->header); | ||
396 | rc = nvram_write_header(free_part); | ||
397 | if (rc <= 0) { | ||
398 | pr_err("nvram_create_os_partition: nvram_write_header " | ||
399 | "failed (%d)\n", rc); | ||
400 | return rc; | ||
401 | } | ||
402 | } else { | ||
403 | list_del(&free_part->partition); | ||
404 | kfree(free_part); | ||
405 | } | ||
381 | 406 | ||
382 | /* Clear the partition */ | 407 | /* Clear the new partition */ |
383 | for (tmp_index = new_part->index + NVRAM_HEADER_LEN; | 408 | for (tmp_index = new_part->index + NVRAM_HEADER_LEN; |
384 | tmp_index < ((size - 1) * NVRAM_BLOCK_LEN); | 409 | tmp_index < ((size - 1) * NVRAM_BLOCK_LEN); |
385 | tmp_index += NVRAM_BLOCK_LEN) { | 410 | tmp_index += NVRAM_BLOCK_LEN) { |
@@ -390,31 +415,24 @@ static int __init nvram_create_partition(const char *name, int sig, | |||
390 | } | 415 | } |
391 | } | 416 | } |
392 | 417 | ||
393 | nvram_error_log_index = new_part->index + NVRAM_HEADER_LEN; | 418 | return new_part->index + NVRAM_HEADER_LEN; |
394 | nvram_error_log_size = ((part->header.length - 1) * | 419 | } |
395 | NVRAM_BLOCK_LEN) - sizeof(struct err_log_info); | ||
396 | |||
397 | list_add_tail(&new_part->partition, &free_part->partition); | ||
398 | |||
399 | if (free_part->header.length <= size) { | ||
400 | list_del(&free_part->partition); | ||
401 | kfree(free_part); | ||
402 | return 0; | ||
403 | } | ||
404 | 420 | ||
405 | /* Adjust the partition we stole the space from */ | 421 | /** |
406 | free_part->index += size * NVRAM_BLOCK_LEN; | 422 | * nvram_get_partition_size - Get the data size of an nvram partition |
407 | free_part->header.length -= size; | 423 | * @data_index: This is the offset of the start of the data of |
408 | free_part->header.checksum = nvram_checksum(&free_part->header); | 424 | * the partition. The same value that is returned by |
425 | * nvram_create_partition(). | ||
426 | */ | ||
427 | static int nvram_get_partition_size(loff_t data_index) | ||
428 | { | ||
429 | struct nvram_partition *part; | ||
409 | 430 | ||
410 | rc = nvram_write_header(free_part); | 431 | list_for_each_entry(part, &nvram_part->partition, partition) { |
411 | if (rc <= 0) { | 432 | if (part->index + NVRAM_HEADER_LEN == data_index) |
412 | printk(KERN_ERR "nvram_create_os_partition: nvram_write_header " | 433 | return (part->header.length - 1) * NVRAM_BLOCK_LEN; |
413 | "failed (%d)\n", rc); | ||
414 | return rc; | ||
415 | } | 434 | } |
416 | 435 | return -1; | |
417 | return 0; | ||
418 | } | 436 | } |
419 | 437 | ||
420 | 438 | ||
@@ -469,30 +487,28 @@ static int __init nvram_setup_partition(void) | |||
469 | } | 487 | } |
470 | 488 | ||
471 | /* try creating a partition with the free space we have */ | 489 | /* try creating a partition with the free space we have */ |
472 | rc = nvram_create_partition("ppc64,linux", NVRAM_SIG_OS, | 490 | rc = nvram_create_partition("ppc64,linux", NVRAM_SIG_OS, |
473 | NVRAM_MAX_REQ, NVRAM_MIN_REQ); | 491 | NVRAM_MAX_REQ, NVRAM_MIN_REQ); |
474 | if (!rc) | 492 | if (rc < 0) { |
475 | return 0; | 493 | /* need to free up some space */ |
476 | 494 | rc = nvram_remove_os_partition(); | |
477 | /* need to free up some space */ | 495 | if (rc) |
478 | rc = nvram_remove_os_partition(); | 496 | return rc; |
479 | if (rc) { | 497 | /* create a partition in this new space */ |
480 | return rc; | 498 | rc = nvram_create_partition("ppc64,linux", NVRAM_SIG_OS, |
481 | } | 499 | NVRAM_MAX_REQ, NVRAM_MIN_REQ); |
482 | 500 | if (rc < 0) { | |
483 | /* create a partition in this new space */ | 501 | pr_err("nvram_create_partition: Could not find" |
484 | rc = nvram_create_partition("ppc64,linux", NVRAM_SIG_OS, | 502 | " enough space in NVRAM for partition\n"); |
485 | NVRAM_MAX_REQ, NVRAM_MIN_REQ); | 503 | return rc; |
486 | if (rc) { | 504 | } |
487 | printk(KERN_ERR "nvram_create_partition: Could not find a " | ||
488 | "NVRAM partition large enough\n"); | ||
489 | return rc; | ||
490 | } | 505 | } |
491 | 506 | ||
507 | nvram_error_log_index = rc; | ||
508 | nvram_error_log_size = nvram_get_partition_size(rc) - sizeof(struct err_log_info); | ||
492 | return 0; | 509 | return 0; |
493 | } | 510 | } |
494 | 511 | ||
495 | |||
496 | static int __init nvram_scan_partitions(void) | 512 | static int __init nvram_scan_partitions(void) |
497 | { | 513 | { |
498 | loff_t cur_index = 0; | 514 | loff_t cur_index = 0; |