diff options
-rw-r--r-- | arch/mips/bcm47xx/nvram.c | 46 |
1 files changed, 39 insertions, 7 deletions
diff --git a/arch/mips/bcm47xx/nvram.c b/arch/mips/bcm47xx/nvram.c index 6cf3ef29d844..b4a47fcb4f64 100644 --- a/arch/mips/bcm47xx/nvram.c +++ b/arch/mips/bcm47xx/nvram.c | |||
@@ -3,7 +3,7 @@ | |||
3 | * | 3 | * |
4 | * Copyright (C) 2005 Broadcom Corporation | 4 | * Copyright (C) 2005 Broadcom Corporation |
5 | * Copyright (C) 2006 Felix Fietkau <nbd@openwrt.org> | 5 | * Copyright (C) 2006 Felix Fietkau <nbd@openwrt.org> |
6 | * Copyright (C) 2010-2011 Hauke Mehrtens <hauke@hauke-m.de> | 6 | * Copyright (C) 2010-2012 Hauke Mehrtens <hauke@hauke-m.de> |
7 | * | 7 | * |
8 | * This program is free software; you can redistribute it and/or modify it | 8 | * This program is free software; you can redistribute it and/or modify it |
9 | * under the terms of the GNU General Public License as published by the | 9 | * under the terms of the GNU General Public License as published by the |
@@ -23,42 +23,74 @@ | |||
23 | 23 | ||
24 | static char nvram_buf[NVRAM_SPACE]; | 24 | static char nvram_buf[NVRAM_SPACE]; |
25 | 25 | ||
26 | static u32 find_nvram_size(u32 end) | ||
27 | { | ||
28 | struct nvram_header *header; | ||
29 | u32 nvram_sizes[] = {0x8000, 0xF000, 0x10000}; | ||
30 | int i; | ||
31 | |||
32 | for (i = 0; i < ARRAY_SIZE(nvram_sizes); i++) { | ||
33 | header = (struct nvram_header *)KSEG1ADDR(end - nvram_sizes[i]); | ||
34 | if (header->magic == NVRAM_HEADER) | ||
35 | return nvram_sizes[i]; | ||
36 | } | ||
37 | |||
38 | return 0; | ||
39 | } | ||
40 | |||
41 | /* Probe for NVRAM header */ | ||
26 | static int nvram_find_and_copy(u32 base, u32 lim) | 42 | static int nvram_find_and_copy(u32 base, u32 lim) |
27 | { | 43 | { |
28 | struct nvram_header *header; | 44 | struct nvram_header *header; |
29 | int i; | 45 | int i; |
30 | u32 off; | 46 | u32 off; |
31 | u32 *src, *dst; | 47 | u32 *src, *dst; |
48 | u32 size; | ||
32 | 49 | ||
33 | /* TODO: when nvram is on nand flash check for bad blocks first. */ | 50 | /* TODO: when nvram is on nand flash check for bad blocks first. */ |
34 | off = FLASH_MIN; | 51 | off = FLASH_MIN; |
35 | while (off <= lim) { | 52 | while (off <= lim) { |
36 | /* Windowed flash access */ | 53 | /* Windowed flash access */ |
37 | header = (struct nvram_header *) | 54 | size = find_nvram_size(base + off); |
38 | KSEG1ADDR(base + off - NVRAM_SPACE); | 55 | if (size) { |
39 | if (header->magic == NVRAM_HEADER) | 56 | header = (struct nvram_header *)KSEG1ADDR(base + off - |
57 | size); | ||
40 | goto found; | 58 | goto found; |
59 | } | ||
41 | off <<= 1; | 60 | off <<= 1; |
42 | } | 61 | } |
43 | 62 | ||
44 | /* Try embedded NVRAM at 4 KB and 1 KB as last resorts */ | 63 | /* Try embedded NVRAM at 4 KB and 1 KB as last resorts */ |
45 | header = (struct nvram_header *) KSEG1ADDR(base + 4096); | 64 | header = (struct nvram_header *) KSEG1ADDR(base + 4096); |
46 | if (header->magic == NVRAM_HEADER) | 65 | if (header->magic == NVRAM_HEADER) { |
66 | size = NVRAM_SPACE; | ||
47 | goto found; | 67 | goto found; |
68 | } | ||
48 | 69 | ||
49 | header = (struct nvram_header *) KSEG1ADDR(base + 1024); | 70 | header = (struct nvram_header *) KSEG1ADDR(base + 1024); |
50 | if (header->magic == NVRAM_HEADER) | 71 | if (header->magic == NVRAM_HEADER) { |
72 | size = NVRAM_SPACE; | ||
51 | goto found; | 73 | goto found; |
74 | } | ||
52 | 75 | ||
76 | pr_err("no nvram found\n"); | ||
53 | return -ENXIO; | 77 | return -ENXIO; |
54 | 78 | ||
55 | found: | 79 | found: |
80 | |||
81 | if (header->len > size) | ||
82 | pr_err("The nvram size accoridng to the header seems to be bigger than the partition on flash\n"); | ||
83 | if (header->len > NVRAM_SPACE) | ||
84 | pr_err("nvram on flash (%i bytes) is bigger than the reserved space in memory, will just copy the first %i bytes\n", | ||
85 | header->len, NVRAM_SPACE); | ||
86 | |||
56 | src = (u32 *) header; | 87 | src = (u32 *) header; |
57 | dst = (u32 *) nvram_buf; | 88 | dst = (u32 *) nvram_buf; |
58 | for (i = 0; i < sizeof(struct nvram_header); i += 4) | 89 | for (i = 0; i < sizeof(struct nvram_header); i += 4) |
59 | *dst++ = *src++; | 90 | *dst++ = *src++; |
60 | for (; i < header->len && i < NVRAM_SPACE; i += 4) | 91 | for (; i < header->len && i < NVRAM_SPACE && i < size; i += 4) |
61 | *dst++ = le32_to_cpu(*src++); | 92 | *dst++ = le32_to_cpu(*src++); |
93 | memset(dst, 0x0, NVRAM_SPACE - i); | ||
62 | 94 | ||
63 | return 0; | 95 | return 0; |
64 | } | 96 | } |