Commit 0f4ac132365e56802cbe377313491aa84086371c
Committed by
Benjamin Herrenschmidt
1 parent
6dd2270029
Exists in
master
and in
7 other branches
powerpc/nvram: Generalize code for OS partitions in NVRAM
Adapt the functions used to create and write to the RTAS-log partition to work with any OS-type partition. Signed-off-by: Jim Keniston <jkenisto@us.ibm.com> Signed-off-by: Benjamin Herrenschmidt <benh@kernel.crashing.org>
Showing 3 changed files with 113 additions and 64 deletions Side-by-side Diff
arch/powerpc/include/asm/nvram.h
... | ... | @@ -51,7 +51,8 @@ |
51 | 51 | extern int __init nvram_scan_partitions(void); |
52 | 52 | extern loff_t nvram_create_partition(const char *name, int sig, |
53 | 53 | int req_size, int min_size); |
54 | -extern int nvram_remove_partition(const char *name, int sig); | |
54 | +extern int nvram_remove_partition(const char *name, int sig, | |
55 | + const char *exceptions[]); | |
55 | 56 | extern int nvram_get_partition_size(loff_t data_index); |
56 | 57 | extern loff_t nvram_find_partition(const char *name, int sig, int *out_size); |
57 | 58 |
arch/powerpc/kernel/nvram_64.c
... | ... | @@ -237,22 +237,45 @@ |
237 | 237 | return c_sum; |
238 | 238 | } |
239 | 239 | |
240 | +/* | |
241 | + * Per the criteria passed via nvram_remove_partition(), should this | |
242 | + * partition be removed? 1=remove, 0=keep | |
243 | + */ | |
244 | +static int nvram_can_remove_partition(struct nvram_partition *part, | |
245 | + const char *name, int sig, const char *exceptions[]) | |
246 | +{ | |
247 | + if (part->header.signature != sig) | |
248 | + return 0; | |
249 | + if (name) { | |
250 | + if (strncmp(name, part->header.name, 12)) | |
251 | + return 0; | |
252 | + } else if (exceptions) { | |
253 | + const char **except; | |
254 | + for (except = exceptions; *except; except++) { | |
255 | + if (!strncmp(*except, part->header.name, 12)) | |
256 | + return 0; | |
257 | + } | |
258 | + } | |
259 | + return 1; | |
260 | +} | |
261 | + | |
240 | 262 | /** |
241 | 263 | * nvram_remove_partition - Remove one or more partitions in nvram |
242 | 264 | * @name: name of the partition to remove, or NULL for a |
243 | 265 | * signature only match |
244 | 266 | * @sig: signature of the partition(s) to remove |
267 | + * @exceptions: When removing all partitions with a matching signature, | |
268 | + * leave these alone. | |
245 | 269 | */ |
246 | 270 | |
247 | -int __init nvram_remove_partition(const char *name, int sig) | |
271 | +int __init nvram_remove_partition(const char *name, int sig, | |
272 | + const char *exceptions[]) | |
248 | 273 | { |
249 | 274 | struct nvram_partition *part, *prev, *tmp; |
250 | 275 | int rc; |
251 | 276 | |
252 | 277 | list_for_each_entry(part, &nvram_partitions, partition) { |
253 | - if (part->header.signature != sig) | |
254 | - continue; | |
255 | - if (name && strncmp(name, part->header.name, 12)) | |
278 | + if (!nvram_can_remove_partition(part, name, sig, exceptions)) | |
256 | 279 | continue; |
257 | 280 | |
258 | 281 | /* Make partition a free partition */ |
arch/powerpc/platforms/pseries/nvram.c
... | ... | @@ -30,18 +30,31 @@ |
30 | 30 | static char nvram_buf[NVRW_CNT]; /* assume this is in the first 4GB */ |
31 | 31 | static DEFINE_SPINLOCK(nvram_lock); |
32 | 32 | |
33 | -static long nvram_error_log_index = -1; | |
34 | -static long nvram_error_log_size = 0; | |
35 | - | |
36 | 33 | struct err_log_info { |
37 | 34 | int error_type; |
38 | 35 | unsigned int seq_num; |
39 | 36 | }; |
40 | -#define NVRAM_MAX_REQ 2079 | |
41 | -#define NVRAM_MIN_REQ 1055 | |
42 | 37 | |
43 | -#define NVRAM_LOG_PART_NAME "ibm,rtas-log" | |
38 | +struct nvram_os_partition { | |
39 | + const char *name; | |
40 | + int req_size; /* desired size, in bytes */ | |
41 | + int min_size; /* minimum acceptable size (0 means req_size) */ | |
42 | + long size; /* size of data portion of partition */ | |
43 | + long index; /* offset of data portion of partition */ | |
44 | +}; | |
44 | 45 | |
46 | +static struct nvram_os_partition rtas_log_partition = { | |
47 | + .name = "ibm,rtas-log", | |
48 | + .req_size = 2079, | |
49 | + .min_size = 1055, | |
50 | + .index = -1 | |
51 | +}; | |
52 | + | |
53 | +static const char *pseries_nvram_os_partitions[] = { | |
54 | + "ibm,rtas-log", | |
55 | + NULL | |
56 | +}; | |
57 | + | |
45 | 58 | static ssize_t pSeries_nvram_read(char *buf, size_t count, loff_t *index) |
46 | 59 | { |
47 | 60 | unsigned int i; |
... | ... | @@ -134,7 +147,7 @@ |
134 | 147 | } |
135 | 148 | |
136 | 149 | |
137 | -/* nvram_write_error_log | |
150 | +/* nvram_write_os_partition, nvram_write_error_log | |
138 | 151 | * |
139 | 152 | * We need to buffer the error logs into nvram to ensure that we have |
140 | 153 | * the failure information to decode. If we have a severe error there |
141 | 154 | |
142 | 155 | |
143 | 156 | |
144 | 157 | |
145 | 158 | |
146 | 159 | |
147 | 160 | |
... | ... | @@ -156,48 +169,55 @@ |
156 | 169 | * The 'data' section would look like (in bytes): |
157 | 170 | * +--------------+------------+-----------------------------------+ |
158 | 171 | * | event_logged | sequence # | error log | |
159 | - * |0 3|4 7|8 nvram_error_log_size-1| | |
172 | + * |0 3|4 7|8 error_log_size-1| | |
160 | 173 | * +--------------+------------+-----------------------------------+ |
161 | 174 | * |
162 | 175 | * event_logged: 0 if event has not been logged to syslog, 1 if it has |
163 | 176 | * sequence #: The unique sequence # for each event. (until it wraps) |
164 | 177 | * error log: The error log from event_scan |
165 | 178 | */ |
166 | -int nvram_write_error_log(char * buff, int length, | |
167 | - unsigned int err_type, unsigned int error_log_cnt) | |
179 | +int nvram_write_os_partition(struct nvram_os_partition *part, char * buff, | |
180 | + int length, unsigned int err_type, unsigned int error_log_cnt) | |
168 | 181 | { |
169 | 182 | int rc; |
170 | 183 | loff_t tmp_index; |
171 | 184 | struct err_log_info info; |
172 | 185 | |
173 | - if (nvram_error_log_index == -1) { | |
186 | + if (part->index == -1) { | |
174 | 187 | return -ESPIPE; |
175 | 188 | } |
176 | 189 | |
177 | - if (length > nvram_error_log_size) { | |
178 | - length = nvram_error_log_size; | |
190 | + if (length > part->size) { | |
191 | + length = part->size; | |
179 | 192 | } |
180 | 193 | |
181 | 194 | info.error_type = err_type; |
182 | 195 | info.seq_num = error_log_cnt; |
183 | 196 | |
184 | - tmp_index = nvram_error_log_index; | |
197 | + tmp_index = part->index; | |
185 | 198 | |
186 | 199 | rc = ppc_md.nvram_write((char *)&info, sizeof(struct err_log_info), &tmp_index); |
187 | 200 | if (rc <= 0) { |
188 | - printk(KERN_ERR "nvram_write_error_log: Failed nvram_write (%d)\n", rc); | |
201 | + pr_err("%s: Failed nvram_write (%d)\n", __FUNCTION__, rc); | |
189 | 202 | return rc; |
190 | 203 | } |
191 | 204 | |
192 | 205 | rc = ppc_md.nvram_write(buff, length, &tmp_index); |
193 | 206 | if (rc <= 0) { |
194 | - printk(KERN_ERR "nvram_write_error_log: Failed nvram_write (%d)\n", rc); | |
207 | + pr_err("%s: Failed nvram_write (%d)\n", __FUNCTION__, rc); | |
195 | 208 | return rc; |
196 | 209 | } |
197 | 210 | |
198 | 211 | return 0; |
199 | 212 | } |
200 | 213 | |
214 | +int nvram_write_error_log(char * buff, int length, | |
215 | + unsigned int err_type, unsigned int error_log_cnt) | |
216 | +{ | |
217 | + return nvram_write_os_partition(&rtas_log_partition, buff, length, | |
218 | + err_type, error_log_cnt); | |
219 | +} | |
220 | + | |
201 | 221 | /* nvram_read_error_log |
202 | 222 | * |
203 | 223 | * Reads nvram for error log for at most 'length' |
204 | 224 | |
205 | 225 | |
... | ... | @@ -209,13 +229,13 @@ |
209 | 229 | loff_t tmp_index; |
210 | 230 | struct err_log_info info; |
211 | 231 | |
212 | - if (nvram_error_log_index == -1) | |
232 | + if (rtas_log_partition.index == -1) | |
213 | 233 | return -1; |
214 | 234 | |
215 | - if (length > nvram_error_log_size) | |
216 | - length = nvram_error_log_size; | |
235 | + if (length > rtas_log_partition.size) | |
236 | + length = rtas_log_partition.size; | |
217 | 237 | |
218 | - tmp_index = nvram_error_log_index; | |
238 | + tmp_index = rtas_log_partition.index; | |
219 | 239 | |
220 | 240 | rc = ppc_md.nvram_read((char *)&info, sizeof(struct err_log_info), &tmp_index); |
221 | 241 | if (rc <= 0) { |
222 | 242 | |
... | ... | @@ -244,10 +264,10 @@ |
244 | 264 | int clear_word = ERR_FLAG_ALREADY_LOGGED; |
245 | 265 | int rc; |
246 | 266 | |
247 | - if (nvram_error_log_index == -1) | |
267 | + if (rtas_log_partition.index == -1) | |
248 | 268 | return -1; |
249 | 269 | |
250 | - tmp_index = nvram_error_log_index; | |
270 | + tmp_index = rtas_log_partition.index; | |
251 | 271 | |
252 | 272 | rc = ppc_md.nvram_write((char *)&clear_word, sizeof(int), &tmp_index); |
253 | 273 | if (rc <= 0) { |
254 | 274 | |
255 | 275 | |
256 | 276 | |
... | ... | @@ -258,23 +278,25 @@ |
258 | 278 | return 0; |
259 | 279 | } |
260 | 280 | |
261 | -/* pseries_nvram_init_log_partition | |
281 | +/* pseries_nvram_init_os_partition | |
262 | 282 | * |
263 | - * This will setup the partition we need for buffering the | |
264 | - * error logs and cleanup partitions if needed. | |
283 | + * This sets up a partition with an "OS" signature. | |
265 | 284 | * |
266 | 285 | * The general strategy is the following: |
267 | - * 1.) If there is log partition large enough then use it. | |
268 | - * 2.) If there is none large enough, search | |
269 | - * for a free partition that is large enough. | |
270 | - * 3.) If there is not a free partition large enough remove | |
271 | - * _all_ OS partitions and consolidate the space. | |
272 | - * 4.) Will first try getting a chunk that will satisfy the maximum | |
273 | - * error log size (NVRAM_MAX_REQ). | |
274 | - * 5.) If the max chunk cannot be allocated then try finding a chunk | |
275 | - * that will satisfy the minum needed (NVRAM_MIN_REQ). | |
286 | + * 1.) If a partition with the indicated name already exists... | |
287 | + * - If it's large enough, use it. | |
288 | + * - Otherwise, recycle it and keep going. | |
289 | + * 2.) Search for a free partition that is large enough. | |
290 | + * 3.) If there's not a free partition large enough, recycle any obsolete | |
291 | + * OS partitions and try again. | |
292 | + * 4.) Will first try getting a chunk that will satisfy the requested size. | |
293 | + * 5.) If a chunk of the requested size cannot be allocated, then try finding | |
294 | + * a chunk that will satisfy the minum needed. | |
295 | + * | |
296 | + * Returns 0 on success, else -1. | |
276 | 297 | */ |
277 | -static int __init pseries_nvram_init_log_partition(void) | |
298 | +static int __init pseries_nvram_init_os_partition(struct nvram_os_partition | |
299 | + *part) | |
278 | 300 | { |
279 | 301 | loff_t p; |
280 | 302 | int size; |
281 | 303 | |
282 | 304 | |
283 | 305 | |
284 | 306 | |
285 | 307 | |
286 | 308 | |
... | ... | @@ -282,47 +304,50 @@ |
282 | 304 | /* Scan nvram for partitions */ |
283 | 305 | nvram_scan_partitions(); |
284 | 306 | |
285 | - /* Lookg for ours */ | |
286 | - p = nvram_find_partition(NVRAM_LOG_PART_NAME, NVRAM_SIG_OS, &size); | |
307 | + /* Look for ours */ | |
308 | + p = nvram_find_partition(part->name, NVRAM_SIG_OS, &size); | |
287 | 309 | |
288 | 310 | /* Found one but too small, remove it */ |
289 | - if (p && size < NVRAM_MIN_REQ) { | |
290 | - pr_info("nvram: Found too small "NVRAM_LOG_PART_NAME" partition" | |
291 | - ",removing it..."); | |
292 | - nvram_remove_partition(NVRAM_LOG_PART_NAME, NVRAM_SIG_OS); | |
311 | + if (p && size < part->min_size) { | |
312 | + pr_info("nvram: Found too small %s partition," | |
313 | + " removing it...\n", part->name); | |
314 | + nvram_remove_partition(part->name, NVRAM_SIG_OS, NULL); | |
293 | 315 | p = 0; |
294 | 316 | } |
295 | 317 | |
296 | 318 | /* Create one if we didn't find */ |
297 | 319 | if (!p) { |
298 | - p = nvram_create_partition(NVRAM_LOG_PART_NAME, NVRAM_SIG_OS, | |
299 | - NVRAM_MAX_REQ, NVRAM_MIN_REQ); | |
300 | - /* No room for it, try to get rid of any OS partition | |
301 | - * and try again | |
302 | - */ | |
320 | + p = nvram_create_partition(part->name, NVRAM_SIG_OS, | |
321 | + part->req_size, part->min_size); | |
303 | 322 | if (p == -ENOSPC) { |
304 | - pr_info("nvram: No room to create "NVRAM_LOG_PART_NAME | |
305 | - " partition, deleting all OS partitions..."); | |
306 | - nvram_remove_partition(NULL, NVRAM_SIG_OS); | |
307 | - p = nvram_create_partition(NVRAM_LOG_PART_NAME, | |
308 | - NVRAM_SIG_OS, NVRAM_MAX_REQ, | |
309 | - NVRAM_MIN_REQ); | |
323 | + pr_info("nvram: No room to create %s partition, " | |
324 | + "deleting any obsolete OS partitions...\n", | |
325 | + part->name); | |
326 | + nvram_remove_partition(NULL, NVRAM_SIG_OS, | |
327 | + pseries_nvram_os_partitions); | |
328 | + p = nvram_create_partition(part->name, NVRAM_SIG_OS, | |
329 | + part->req_size, part->min_size); | |
310 | 330 | } |
311 | 331 | } |
312 | 332 | |
313 | 333 | if (p <= 0) { |
314 | - pr_err("nvram: Failed to find or create "NVRAM_LOG_PART_NAME | |
315 | - " partition, err %d\n", (int)p); | |
316 | - return 0; | |
334 | + pr_err("nvram: Failed to find or create %s" | |
335 | + " partition, err %d\n", part->name, (int)p); | |
336 | + return -1; | |
317 | 337 | } |
318 | 338 | |
319 | - nvram_error_log_index = p; | |
320 | - nvram_error_log_size = nvram_get_partition_size(p) - | |
321 | - sizeof(struct err_log_info); | |
339 | + part->index = p; | |
340 | + part->size = nvram_get_partition_size(p) - sizeof(struct err_log_info); | |
322 | 341 | |
323 | 342 | return 0; |
324 | 343 | } |
325 | -machine_arch_initcall(pseries, pseries_nvram_init_log_partition); | |
344 | + | |
345 | +static int __init pseries_nvram_init_log_partitions(void) | |
346 | +{ | |
347 | + (void) pseries_nvram_init_os_partition(&rtas_log_partition); | |
348 | + return 0; | |
349 | +} | |
350 | +machine_arch_initcall(pseries, pseries_nvram_init_log_partitions); | |
326 | 351 | |
327 | 352 | int __init pSeries_nvram_init(void) |
328 | 353 | { |