fw_env: fix writing environment for mtd devices
[platform/kernel/u-boot.git] / common / env_ubi.c
1 /*
2  * (c) Copyright 2012 by National Instruments,
3  *        Joe Hershberger <joe.hershberger@ni.com>
4  *
5  * SPDX-License-Identifier:     GPL-2.0+ 
6  */
7
8 #include <common.h>
9
10 #include <command.h>
11 #include <environment.h>
12 #include <errno.h>
13 #include <malloc.h>
14 #include <search.h>
15 #include <ubi_uboot.h>
16 #undef crc32
17
18 char *env_name_spec = "UBI";
19
20 env_t *env_ptr;
21
22 DECLARE_GLOBAL_DATA_PTR;
23
24 int env_init(void)
25 {
26         /* use default */
27         gd->env_addr = (ulong)&default_environment[0];
28         gd->env_valid = 1;
29
30         return 0;
31 }
32
33 #ifdef CONFIG_CMD_SAVEENV
34 #ifdef CONFIG_SYS_REDUNDAND_ENVIRONMENT
35 static unsigned char env_flags;
36
37 int saveenv(void)
38 {
39         ALLOC_CACHE_ALIGN_BUFFER(env_t, env_new, 1);
40         ssize_t len;
41         char *res;
42
43         res = (char *)&env_new->data;
44         len = hexport_r(&env_htab, '\0', 0, &res, ENV_SIZE, 0, NULL);
45         if (len < 0) {
46                 error("Cannot export environment: errno = %d\n", errno);
47                 return 1;
48         }
49
50         if (ubi_part(CONFIG_ENV_UBI_PART, NULL)) {
51                 printf("\n** Cannot find mtd partition \"%s\"\n",
52                        CONFIG_ENV_UBI_PART);
53                 return 1;
54         }
55
56         env_new->crc = crc32(0, env_new->data, ENV_SIZE);
57         env_new->flags = ++env_flags; /* increase the serial */
58
59         if (gd->env_valid == 1) {
60                 puts("Writing to redundant UBI... ");
61                 if (ubi_volume_write(CONFIG_ENV_UBI_VOLUME_REDUND,
62                                      (void *)env_new, CONFIG_ENV_SIZE)) {
63                         printf("\n** Unable to write env to %s:%s **\n",
64                                CONFIG_ENV_UBI_PART,
65                                CONFIG_ENV_UBI_VOLUME_REDUND);
66                         return 1;
67                 }
68         } else {
69                 puts("Writing to UBI... ");
70                 if (ubi_volume_write(CONFIG_ENV_UBI_VOLUME,
71                                      (void *)env_new, CONFIG_ENV_SIZE)) {
72                         printf("\n** Unable to write env to %s:%s **\n",
73                                CONFIG_ENV_UBI_PART,
74                                CONFIG_ENV_UBI_VOLUME);
75                         return 1;
76                 }
77         }
78
79         puts("done\n");
80
81         gd->env_valid = gd->env_valid == 2 ? 1 : 2;
82
83         return 0;
84 }
85 #else /* ! CONFIG_SYS_REDUNDAND_ENVIRONMENT */
86 int saveenv(void)
87 {
88         ALLOC_CACHE_ALIGN_BUFFER(env_t, env_new, 1);
89         ssize_t len;
90         char *res;
91
92         res = (char *)&env_new->data;
93         len = hexport_r(&env_htab, '\0', 0, &res, ENV_SIZE, 0, NULL);
94         if (len < 0) {
95                 error("Cannot export environment: errno = %d\n", errno);
96                 return 1;
97         }
98
99         if (ubi_part(CONFIG_ENV_UBI_PART, NULL)) {
100                 printf("\n** Cannot find mtd partition \"%s\"\n",
101                        CONFIG_ENV_UBI_PART);
102                 return 1;
103         }
104
105         env_new->crc = crc32(0, env_new->data, ENV_SIZE);
106
107         if (ubi_volume_write(CONFIG_ENV_UBI_VOLUME, (void *)env_new,
108                              CONFIG_ENV_SIZE)) {
109                 printf("\n** Unable to write env to %s:%s **\n",
110                        CONFIG_ENV_UBI_PART, CONFIG_ENV_UBI_VOLUME);
111                 return 1;
112         }
113
114         puts("done\n");
115         return 0;
116 }
117 #endif /* CONFIG_SYS_REDUNDAND_ENVIRONMENT */
118 #endif /* CONFIG_CMD_SAVEENV */
119
120 #ifdef CONFIG_SYS_REDUNDAND_ENVIRONMENT
121 void env_relocate_spec(void)
122 {
123         ALLOC_CACHE_ALIGN_BUFFER(char, env1_buf, CONFIG_ENV_SIZE);
124         ALLOC_CACHE_ALIGN_BUFFER(char, env2_buf, CONFIG_ENV_SIZE);
125         int crc1_ok = 0, crc2_ok = 0;
126         env_t *ep, *tmp_env1, *tmp_env2;
127
128         tmp_env1 = (env_t *)env1_buf;
129         tmp_env2 = (env_t *)env2_buf;
130
131         if (ubi_part(CONFIG_ENV_UBI_PART, NULL)) {
132                 printf("\n** Cannot find mtd partition \"%s\"\n",
133                        CONFIG_ENV_UBI_PART);
134                 set_default_env(NULL);
135                 return;
136         }
137
138         if (ubi_volume_read(CONFIG_ENV_UBI_VOLUME, (void *)tmp_env1,
139                             CONFIG_ENV_SIZE)) {
140                 printf("\n** Unable to read env from %s:%s **\n",
141                        CONFIG_ENV_UBI_PART, CONFIG_ENV_UBI_VOLUME);
142         }
143
144         if (ubi_volume_read(CONFIG_ENV_UBI_VOLUME_REDUND, (void *)tmp_env2,
145                             CONFIG_ENV_SIZE)) {
146                 printf("\n** Unable to read redundant env from %s:%s **\n",
147                        CONFIG_ENV_UBI_PART, CONFIG_ENV_UBI_VOLUME_REDUND);
148         }
149
150         crc1_ok = crc32(0, tmp_env1->data, ENV_SIZE) == tmp_env1->crc;
151         crc2_ok = crc32(0, tmp_env2->data, ENV_SIZE) == tmp_env2->crc;
152
153         if (!crc1_ok && !crc2_ok) {
154                 set_default_env("!bad CRC");
155                 return;
156         } else if (crc1_ok && !crc2_ok) {
157                 gd->env_valid = 1;
158         } else if (!crc1_ok && crc2_ok) {
159                 gd->env_valid = 2;
160         } else {
161                 /* both ok - check serial */
162                 if (tmp_env1->flags == 255 && tmp_env2->flags == 0)
163                         gd->env_valid = 2;
164                 else if (tmp_env2->flags == 255 && tmp_env1->flags == 0)
165                         gd->env_valid = 1;
166                 else if (tmp_env1->flags > tmp_env2->flags)
167                         gd->env_valid = 1;
168                 else if (tmp_env2->flags > tmp_env1->flags)
169                         gd->env_valid = 2;
170                 else /* flags are equal - almost impossible */
171                         gd->env_valid = 1;
172         }
173
174         if (gd->env_valid == 1)
175                 ep = tmp_env1;
176         else
177                 ep = tmp_env2;
178
179         env_flags = ep->flags;
180         env_import((char *)ep, 0);
181 }
182 #else /* ! CONFIG_SYS_REDUNDAND_ENVIRONMENT */
183 void env_relocate_spec(void)
184 {
185         ALLOC_CACHE_ALIGN_BUFFER(char, buf, CONFIG_ENV_SIZE);
186
187         if (ubi_part(CONFIG_ENV_UBI_PART, NULL)) {
188                 printf("\n** Cannot find mtd partition \"%s\"\n",
189                        CONFIG_ENV_UBI_PART);
190                 set_default_env(NULL);
191                 return;
192         }
193
194         if (ubi_volume_read(CONFIG_ENV_UBI_VOLUME, (void *)&buf,
195                             CONFIG_ENV_SIZE)) {
196                 printf("\n** Unable to read env from %s:%s **\n",
197                        CONFIG_ENV_UBI_PART, CONFIG_ENV_UBI_VOLUME);
198                 set_default_env(NULL);
199                 return;
200         }
201
202         env_import(buf, 1);
203 }
204 #endif /* CONFIG_SYS_REDUNDAND_ENVIRONMENT */