diff options
Diffstat (limited to 'arch')
-rw-r--r-- | arch/powerpc/include/asm/nvram.h | 52 | ||||
-rw-r--r-- | arch/powerpc/kernel/nvram_64.c | 481 | ||||
-rw-r--r-- | arch/powerpc/mm/pgtable.c | 2 | ||||
-rw-r--r-- | arch/powerpc/platforms/chrp/time.c | 4 | ||||
-rw-r--r-- | arch/powerpc/platforms/pseries/nvram.c | 205 |
5 files changed, 381 insertions, 363 deletions
diff --git a/arch/powerpc/include/asm/nvram.h b/arch/powerpc/include/asm/nvram.h index 850b72f27445..92efe67d1c57 100644 --- a/arch/powerpc/include/asm/nvram.h +++ b/arch/powerpc/include/asm/nvram.h | |||
@@ -10,31 +10,7 @@ | |||
10 | #ifndef _ASM_POWERPC_NVRAM_H | 10 | #ifndef _ASM_POWERPC_NVRAM_H |
11 | #define _ASM_POWERPC_NVRAM_H | 11 | #define _ASM_POWERPC_NVRAM_H |
12 | 12 | ||
13 | #include <linux/errno.h> | 13 | /* Signatures for nvram partitions */ |
14 | |||
15 | #define NVRW_CNT 0x20 | ||
16 | #define NVRAM_HEADER_LEN 16 /* sizeof(struct nvram_header) */ | ||
17 | #define NVRAM_BLOCK_LEN 16 | ||
18 | #define NVRAM_MAX_REQ (2080/NVRAM_BLOCK_LEN) | ||
19 | #define NVRAM_MIN_REQ (1056/NVRAM_BLOCK_LEN) | ||
20 | |||
21 | #define NVRAM_AS0 0x74 | ||
22 | #define NVRAM_AS1 0x75 | ||
23 | #define NVRAM_DATA 0x77 | ||
24 | |||
25 | |||
26 | /* RTC Offsets */ | ||
27 | |||
28 | #define MOTO_RTC_SECONDS 0x1FF9 | ||
29 | #define MOTO_RTC_MINUTES 0x1FFA | ||
30 | #define MOTO_RTC_HOURS 0x1FFB | ||
31 | #define MOTO_RTC_DAY_OF_WEEK 0x1FFC | ||
32 | #define MOTO_RTC_DAY_OF_MONTH 0x1FFD | ||
33 | #define MOTO_RTC_MONTH 0x1FFE | ||
34 | #define MOTO_RTC_YEAR 0x1FFF | ||
35 | #define MOTO_RTC_CONTROLA 0x1FF8 | ||
36 | #define MOTO_RTC_CONTROLB 0x1FF9 | ||
37 | |||
38 | #define NVRAM_SIG_SP 0x02 /* support processor */ | 14 | #define NVRAM_SIG_SP 0x02 /* support processor */ |
39 | #define NVRAM_SIG_OF 0x50 /* open firmware config */ | 15 | #define NVRAM_SIG_OF 0x50 /* open firmware config */ |
40 | #define NVRAM_SIG_FW 0x51 /* general firmware */ | 16 | #define NVRAM_SIG_FW 0x51 /* general firmware */ |
@@ -49,32 +25,19 @@ | |||
49 | #define NVRAM_SIG_OS 0xa0 /* OS defined */ | 25 | #define NVRAM_SIG_OS 0xa0 /* OS defined */ |
50 | #define NVRAM_SIG_PANIC 0xa1 /* Apple OSX "panic" */ | 26 | #define NVRAM_SIG_PANIC 0xa1 /* Apple OSX "panic" */ |
51 | 27 | ||
52 | /* If change this size, then change the size of NVNAME_LEN */ | ||
53 | struct nvram_header { | ||
54 | unsigned char signature; | ||
55 | unsigned char checksum; | ||
56 | unsigned short length; | ||
57 | char name[12]; | ||
58 | }; | ||
59 | |||
60 | #ifdef __KERNEL__ | 28 | #ifdef __KERNEL__ |
61 | 29 | ||
30 | #include <linux/errno.h> | ||
62 | #include <linux/list.h> | 31 | #include <linux/list.h> |
63 | 32 | ||
64 | struct nvram_partition { | 33 | #ifdef CONFIG_PPC_PSERIES |
65 | struct list_head partition; | ||
66 | struct nvram_header header; | ||
67 | unsigned int index; | ||
68 | }; | ||
69 | |||
70 | |||
71 | extern int nvram_write_error_log(char * buff, int length, | 34 | extern int nvram_write_error_log(char * buff, int length, |
72 | unsigned int err_type, unsigned int err_seq); | 35 | unsigned int err_type, unsigned int err_seq); |
73 | extern int nvram_read_error_log(char * buff, int length, | 36 | extern int nvram_read_error_log(char * buff, int length, |
74 | unsigned int * err_type, unsigned int *err_seq); | 37 | unsigned int * err_type, unsigned int *err_seq); |
75 | extern int nvram_clear_error_log(void); | 38 | extern int nvram_clear_error_log(void); |
76 | |||
77 | extern int pSeries_nvram_init(void); | 39 | extern int pSeries_nvram_init(void); |
40 | #endif /* CONFIG_PPC_PSERIES */ | ||
78 | 41 | ||
79 | #ifdef CONFIG_MMIO_NVRAM | 42 | #ifdef CONFIG_MMIO_NVRAM |
80 | extern int mmio_nvram_init(void); | 43 | extern int mmio_nvram_init(void); |
@@ -85,6 +48,13 @@ static inline int mmio_nvram_init(void) | |||
85 | } | 48 | } |
86 | #endif | 49 | #endif |
87 | 50 | ||
51 | extern int __init nvram_scan_partitions(void); | ||
52 | extern loff_t nvram_create_partition(const char *name, int sig, | ||
53 | int req_size, int min_size); | ||
54 | extern int nvram_remove_partition(const char *name, int sig); | ||
55 | extern int nvram_get_partition_size(loff_t data_index); | ||
56 | extern loff_t nvram_find_partition(const char *name, int sig, int *out_size); | ||
57 | |||
88 | #endif /* __KERNEL__ */ | 58 | #endif /* __KERNEL__ */ |
89 | 59 | ||
90 | /* PowerMac specific nvram stuffs */ | 60 | /* PowerMac specific nvram stuffs */ |
diff --git a/arch/powerpc/kernel/nvram_64.c b/arch/powerpc/kernel/nvram_64.c index 9cf197f01e94..bb12b3248f13 100644 --- a/arch/powerpc/kernel/nvram_64.c +++ b/arch/powerpc/kernel/nvram_64.c | |||
@@ -34,15 +34,26 @@ | |||
34 | 34 | ||
35 | #undef DEBUG_NVRAM | 35 | #undef DEBUG_NVRAM |
36 | 36 | ||
37 | static struct nvram_partition * nvram_part; | 37 | #define NVRAM_HEADER_LEN sizeof(struct nvram_header) |
38 | static long nvram_error_log_index = -1; | 38 | #define NVRAM_BLOCK_LEN NVRAM_HEADER_LEN |
39 | static long nvram_error_log_size = 0; | 39 | |
40 | /* If change this size, then change the size of NVNAME_LEN */ | ||
41 | struct nvram_header { | ||
42 | unsigned char signature; | ||
43 | unsigned char checksum; | ||
44 | unsigned short length; | ||
45 | /* Terminating null required only for names < 12 chars. */ | ||
46 | char name[12]; | ||
47 | }; | ||
40 | 48 | ||
41 | struct err_log_info { | 49 | struct nvram_partition { |
42 | int error_type; | 50 | struct list_head partition; |
43 | unsigned int seq_num; | 51 | struct nvram_header header; |
52 | unsigned int index; | ||
44 | }; | 53 | }; |
45 | 54 | ||
55 | static LIST_HEAD(nvram_partitions); | ||
56 | |||
46 | static loff_t dev_nvram_llseek(struct file *file, loff_t offset, int origin) | 57 | static loff_t dev_nvram_llseek(struct file *file, loff_t offset, int origin) |
47 | { | 58 | { |
48 | int size; | 59 | int size; |
@@ -186,14 +197,12 @@ static struct miscdevice nvram_dev = { | |||
186 | #ifdef DEBUG_NVRAM | 197 | #ifdef DEBUG_NVRAM |
187 | static void __init nvram_print_partitions(char * label) | 198 | static void __init nvram_print_partitions(char * label) |
188 | { | 199 | { |
189 | struct list_head * p; | ||
190 | struct nvram_partition * tmp_part; | 200 | struct nvram_partition * tmp_part; |
191 | 201 | ||
192 | printk(KERN_WARNING "--------%s---------\n", label); | 202 | printk(KERN_WARNING "--------%s---------\n", label); |
193 | printk(KERN_WARNING "indx\t\tsig\tchks\tlen\tname\n"); | 203 | printk(KERN_WARNING "indx\t\tsig\tchks\tlen\tname\n"); |
194 | list_for_each(p, &nvram_part->partition) { | 204 | list_for_each_entry(tmp_part, &nvram_partitions, partition) { |
195 | tmp_part = list_entry(p, struct nvram_partition, partition); | 205 | printk(KERN_WARNING "%4d \t%02x\t%02x\t%d\t%12s\n", |
196 | printk(KERN_WARNING "%4d \t%02x\t%02x\t%d\t%s\n", | ||
197 | tmp_part->index, tmp_part->header.signature, | 206 | tmp_part->index, tmp_part->header.signature, |
198 | tmp_part->header.checksum, tmp_part->header.length, | 207 | tmp_part->header.checksum, tmp_part->header.length, |
199 | tmp_part->header.name); | 208 | tmp_part->header.name); |
@@ -228,95 +237,113 @@ static unsigned char __init nvram_checksum(struct nvram_header *p) | |||
228 | return c_sum; | 237 | return c_sum; |
229 | } | 238 | } |
230 | 239 | ||
231 | static int __init nvram_remove_os_partition(void) | 240 | /** |
241 | * nvram_remove_partition - Remove one or more partitions in nvram | ||
242 | * @name: name of the partition to remove, or NULL for a | ||
243 | * signature only match | ||
244 | * @sig: signature of the partition(s) to remove | ||
245 | */ | ||
246 | |||
247 | int __init nvram_remove_partition(const char *name, int sig) | ||
232 | { | 248 | { |
233 | struct list_head *i; | 249 | struct nvram_partition *part, *prev, *tmp; |
234 | struct list_head *j; | ||
235 | struct nvram_partition * part; | ||
236 | struct nvram_partition * cur_part; | ||
237 | int rc; | 250 | int rc; |
238 | 251 | ||
239 | list_for_each(i, &nvram_part->partition) { | 252 | list_for_each_entry(part, &nvram_partitions, partition) { |
240 | part = list_entry(i, struct nvram_partition, partition); | 253 | if (part->header.signature != sig) |
241 | if (part->header.signature != NVRAM_SIG_OS) | ||
242 | continue; | 254 | continue; |
243 | 255 | if (name && strncmp(name, part->header.name, 12)) | |
244 | /* Make os partition a free partition */ | 256 | continue; |
257 | |||
258 | /* Make partition a free partition */ | ||
245 | part->header.signature = NVRAM_SIG_FREE; | 259 | part->header.signature = NVRAM_SIG_FREE; |
246 | sprintf(part->header.name, "wwwwwwwwwwww"); | 260 | strncpy(part->header.name, "wwwwwwwwwwww", 12); |
247 | part->header.checksum = nvram_checksum(&part->header); | 261 | part->header.checksum = nvram_checksum(&part->header); |
248 | |||
249 | /* Merge contiguous free partitions backwards */ | ||
250 | list_for_each_prev(j, &part->partition) { | ||
251 | cur_part = list_entry(j, struct nvram_partition, partition); | ||
252 | if (cur_part == nvram_part || cur_part->header.signature != NVRAM_SIG_FREE) { | ||
253 | break; | ||
254 | } | ||
255 | |||
256 | part->header.length += cur_part->header.length; | ||
257 | part->header.checksum = nvram_checksum(&part->header); | ||
258 | part->index = cur_part->index; | ||
259 | |||
260 | list_del(&cur_part->partition); | ||
261 | kfree(cur_part); | ||
262 | j = &part->partition; /* fixup our loop */ | ||
263 | } | ||
264 | |||
265 | /* Merge contiguous free partitions forwards */ | ||
266 | list_for_each(j, &part->partition) { | ||
267 | cur_part = list_entry(j, struct nvram_partition, partition); | ||
268 | if (cur_part == nvram_part || cur_part->header.signature != NVRAM_SIG_FREE) { | ||
269 | break; | ||
270 | } | ||
271 | |||
272 | part->header.length += cur_part->header.length; | ||
273 | part->header.checksum = nvram_checksum(&part->header); | ||
274 | |||
275 | list_del(&cur_part->partition); | ||
276 | kfree(cur_part); | ||
277 | j = &part->partition; /* fixup our loop */ | ||
278 | } | ||
279 | |||
280 | rc = nvram_write_header(part); | 262 | rc = nvram_write_header(part); |
281 | if (rc <= 0) { | 263 | if (rc <= 0) { |
282 | printk(KERN_ERR "nvram_remove_os_partition: nvram_write failed (%d)\n", rc); | 264 | printk(KERN_ERR "nvram_remove_partition: nvram_write failed (%d)\n", rc); |
283 | return rc; | 265 | return rc; |
284 | } | 266 | } |
267 | } | ||
285 | 268 | ||
269 | /* Merge contiguous ones */ | ||
270 | prev = NULL; | ||
271 | list_for_each_entry_safe(part, tmp, &nvram_partitions, partition) { | ||
272 | if (part->header.signature != NVRAM_SIG_FREE) { | ||
273 | prev = NULL; | ||
274 | continue; | ||
275 | } | ||
276 | if (prev) { | ||
277 | prev->header.length += part->header.length; | ||
278 | prev->header.checksum = nvram_checksum(&part->header); | ||
279 | rc = nvram_write_header(part); | ||
280 | if (rc <= 0) { | ||
281 | printk(KERN_ERR "nvram_remove_partition: nvram_write failed (%d)\n", rc); | ||
282 | return rc; | ||
283 | } | ||
284 | list_del(&part->partition); | ||
285 | kfree(part); | ||
286 | } else | ||
287 | prev = part; | ||
286 | } | 288 | } |
287 | 289 | ||
288 | return 0; | 290 | return 0; |
289 | } | 291 | } |
290 | 292 | ||
291 | /* nvram_create_os_partition | 293 | /** |
294 | * nvram_create_partition - Create a partition in nvram | ||
295 | * @name: name of the partition to create | ||
296 | * @sig: signature of the partition to create | ||
297 | * @req_size: size of data to allocate in bytes | ||
298 | * @min_size: minimum acceptable size (0 means req_size) | ||
292 | * | 299 | * |
293 | * Create a OS linux partition to buffer error logs. | 300 | * Returns a negative error code or a positive nvram index |
294 | * Will create a partition starting at the first free | 301 | * of the beginning of the data area of the newly created |
295 | * space found if space has enough room. | 302 | * partition. If you provided a min_size smaller than req_size |
303 | * you need to query for the actual size yourself after the | ||
304 | * call using nvram_partition_get_size(). | ||
296 | */ | 305 | */ |
297 | static int __init nvram_create_os_partition(void) | 306 | loff_t __init nvram_create_partition(const char *name, int sig, |
307 | int req_size, int min_size) | ||
298 | { | 308 | { |
299 | struct nvram_partition *part; | 309 | struct nvram_partition *part; |
300 | struct nvram_partition *new_part; | 310 | struct nvram_partition *new_part; |
301 | struct nvram_partition *free_part = NULL; | 311 | struct nvram_partition *free_part = NULL; |
302 | int seq_init[2] = { 0, 0 }; | 312 | static char nv_init_vals[16]; |
303 | loff_t tmp_index; | 313 | loff_t tmp_index; |
304 | long size = 0; | 314 | long size = 0; |
305 | int rc; | 315 | int rc; |
306 | 316 | ||
317 | /* Convert sizes from bytes to blocks */ | ||
318 | req_size = _ALIGN_UP(req_size, NVRAM_BLOCK_LEN) / NVRAM_BLOCK_LEN; | ||
319 | min_size = _ALIGN_UP(min_size, NVRAM_BLOCK_LEN) / NVRAM_BLOCK_LEN; | ||
320 | |||
321 | /* If no minimum size specified, make it the same as the | ||
322 | * requested size | ||
323 | */ | ||
324 | if (min_size == 0) | ||
325 | min_size = req_size; | ||
326 | if (min_size > req_size) | ||
327 | return -EINVAL; | ||
328 | |||
329 | /* Now add one block to each for the header */ | ||
330 | req_size += 1; | ||
331 | min_size += 1; | ||
332 | |||
307 | /* Find a free partition that will give us the maximum needed size | 333 | /* Find a free partition that will give us the maximum needed size |
308 | If can't find one that will give us the minimum size needed */ | 334 | If can't find one that will give us the minimum size needed */ |
309 | list_for_each_entry(part, &nvram_part->partition, partition) { | 335 | list_for_each_entry(part, &nvram_partitions, partition) { |
310 | if (part->header.signature != NVRAM_SIG_FREE) | 336 | if (part->header.signature != NVRAM_SIG_FREE) |
311 | continue; | 337 | continue; |
312 | 338 | ||
313 | if (part->header.length >= NVRAM_MAX_REQ) { | 339 | if (part->header.length >= req_size) { |
314 | size = NVRAM_MAX_REQ; | 340 | size = req_size; |
315 | free_part = part; | 341 | free_part = part; |
316 | break; | 342 | break; |
317 | } | 343 | } |
318 | if (!size && part->header.length >= NVRAM_MIN_REQ) { | 344 | if (part->header.length > size && |
319 | size = NVRAM_MIN_REQ; | 345 | part->header.length >= min_size) { |
346 | size = part->header.length; | ||
320 | free_part = part; | 347 | free_part = part; |
321 | } | 348 | } |
322 | } | 349 | } |
@@ -326,136 +353,95 @@ static int __init nvram_create_os_partition(void) | |||
326 | /* Create our OS partition */ | 353 | /* Create our OS partition */ |
327 | new_part = kmalloc(sizeof(*new_part), GFP_KERNEL); | 354 | new_part = kmalloc(sizeof(*new_part), GFP_KERNEL); |
328 | if (!new_part) { | 355 | if (!new_part) { |
329 | printk(KERN_ERR "nvram_create_os_partition: kmalloc failed\n"); | 356 | pr_err("nvram_create_os_partition: kmalloc failed\n"); |
330 | return -ENOMEM; | 357 | return -ENOMEM; |
331 | } | 358 | } |
332 | 359 | ||
333 | new_part->index = free_part->index; | 360 | new_part->index = free_part->index; |
334 | new_part->header.signature = NVRAM_SIG_OS; | 361 | new_part->header.signature = sig; |
335 | new_part->header.length = size; | 362 | new_part->header.length = size; |
336 | strcpy(new_part->header.name, "ppc64,linux"); | 363 | strncpy(new_part->header.name, name, 12); |
337 | new_part->header.checksum = nvram_checksum(&new_part->header); | 364 | new_part->header.checksum = nvram_checksum(&new_part->header); |
338 | 365 | ||
339 | rc = nvram_write_header(new_part); | 366 | rc = nvram_write_header(new_part); |
340 | if (rc <= 0) { | 367 | if (rc <= 0) { |
341 | printk(KERN_ERR "nvram_create_os_partition: nvram_write_header " | 368 | pr_err("nvram_create_os_partition: nvram_write_header " |
342 | "failed (%d)\n", rc); | ||
343 | return rc; | ||
344 | } | ||
345 | |||
346 | /* make sure and initialize to zero the sequence number and the error | ||
347 | type logged */ | ||
348 | tmp_index = new_part->index + NVRAM_HEADER_LEN; | ||
349 | rc = ppc_md.nvram_write((char *)&seq_init, sizeof(seq_init), &tmp_index); | ||
350 | if (rc <= 0) { | ||
351 | printk(KERN_ERR "nvram_create_os_partition: nvram_write " | ||
352 | "failed (%d)\n", rc); | 369 | "failed (%d)\n", rc); |
353 | return rc; | 370 | return rc; |
354 | } | 371 | } |
355 | |||
356 | nvram_error_log_index = new_part->index + NVRAM_HEADER_LEN; | ||
357 | nvram_error_log_size = ((part->header.length - 1) * | ||
358 | NVRAM_BLOCK_LEN) - sizeof(struct err_log_info); | ||
359 | |||
360 | list_add_tail(&new_part->partition, &free_part->partition); | 372 | list_add_tail(&new_part->partition, &free_part->partition); |
361 | 373 | ||
362 | if (free_part->header.length <= size) { | 374 | /* Adjust or remove the partition we stole the space from */ |
375 | if (free_part->header.length > size) { | ||
376 | free_part->index += size * NVRAM_BLOCK_LEN; | ||
377 | free_part->header.length -= size; | ||
378 | free_part->header.checksum = nvram_checksum(&free_part->header); | ||
379 | rc = nvram_write_header(free_part); | ||
380 | if (rc <= 0) { | ||
381 | pr_err("nvram_create_os_partition: nvram_write_header " | ||
382 | "failed (%d)\n", rc); | ||
383 | return rc; | ||
384 | } | ||
385 | } else { | ||
363 | list_del(&free_part->partition); | 386 | list_del(&free_part->partition); |
364 | kfree(free_part); | 387 | kfree(free_part); |
365 | return 0; | ||
366 | } | 388 | } |
367 | 389 | ||
368 | /* Adjust the partition we stole the space from */ | 390 | /* Clear the new partition */ |
369 | free_part->index += size * NVRAM_BLOCK_LEN; | 391 | for (tmp_index = new_part->index + NVRAM_HEADER_LEN; |
370 | free_part->header.length -= size; | 392 | tmp_index < ((size - 1) * NVRAM_BLOCK_LEN); |
371 | free_part->header.checksum = nvram_checksum(&free_part->header); | 393 | tmp_index += NVRAM_BLOCK_LEN) { |
372 | 394 | rc = ppc_md.nvram_write(nv_init_vals, NVRAM_BLOCK_LEN, &tmp_index); | |
373 | rc = nvram_write_header(free_part); | 395 | if (rc <= 0) { |
374 | if (rc <= 0) { | 396 | pr_err("nvram_create_partition: nvram_write failed (%d)\n", rc); |
375 | printk(KERN_ERR "nvram_create_os_partition: nvram_write_header " | 397 | return rc; |
376 | "failed (%d)\n", rc); | 398 | } |
377 | return rc; | ||
378 | } | 399 | } |
379 | 400 | ||
380 | return 0; | 401 | return new_part->index + NVRAM_HEADER_LEN; |
381 | } | 402 | } |
382 | 403 | ||
383 | 404 | /** | |
384 | /* nvram_setup_partition | 405 | * nvram_get_partition_size - Get the data size of an nvram partition |
385 | * | 406 | * @data_index: This is the offset of the start of the data of |
386 | * This will setup the partition we need for buffering the | 407 | * the partition. The same value that is returned by |
387 | * error logs and cleanup partitions if needed. | 408 | * nvram_create_partition(). |
388 | * | ||
389 | * The general strategy is the following: | ||
390 | * 1.) If there is ppc64,linux partition large enough then use it. | ||
391 | * 2.) If there is not a ppc64,linux partition large enough, search | ||
392 | * for a free partition that is large enough. | ||
393 | * 3.) If there is not a free partition large enough remove | ||
394 | * _all_ OS partitions and consolidate the space. | ||
395 | * 4.) Will first try getting a chunk that will satisfy the maximum | ||
396 | * error log size (NVRAM_MAX_REQ). | ||
397 | * 5.) If the max chunk cannot be allocated then try finding a chunk | ||
398 | * that will satisfy the minum needed (NVRAM_MIN_REQ). | ||
399 | */ | 409 | */ |
400 | static int __init nvram_setup_partition(void) | 410 | int nvram_get_partition_size(loff_t data_index) |
401 | { | 411 | { |
402 | struct list_head * p; | 412 | struct nvram_partition *part; |
403 | struct nvram_partition * part; | 413 | |
404 | int rc; | 414 | list_for_each_entry(part, &nvram_partitions, partition) { |
405 | 415 | if (part->index + NVRAM_HEADER_LEN == data_index) | |
406 | /* For now, we don't do any of this on pmac, until I | 416 | return (part->header.length - 1) * NVRAM_BLOCK_LEN; |
407 | * have figured out if it's worth killing some unused stuffs | 417 | } |
408 | * in our nvram, as Apple defined partitions use pretty much | 418 | return -1; |
409 | * all of the space | 419 | } |
410 | */ | ||
411 | if (machine_is(powermac)) | ||
412 | return -ENOSPC; | ||
413 | |||
414 | /* see if we have an OS partition that meets our needs. | ||
415 | will try getting the max we need. If not we'll delete | ||
416 | partitions and try again. */ | ||
417 | list_for_each(p, &nvram_part->partition) { | ||
418 | part = list_entry(p, struct nvram_partition, partition); | ||
419 | if (part->header.signature != NVRAM_SIG_OS) | ||
420 | continue; | ||
421 | 420 | ||
422 | if (strcmp(part->header.name, "ppc64,linux")) | ||
423 | continue; | ||
424 | 421 | ||
425 | if (part->header.length >= NVRAM_MIN_REQ) { | 422 | /** |
426 | /* found our partition */ | 423 | * nvram_find_partition - Find an nvram partition by signature and name |
427 | nvram_error_log_index = part->index + NVRAM_HEADER_LEN; | 424 | * @name: Name of the partition or NULL for any name |
428 | nvram_error_log_size = ((part->header.length - 1) * | 425 | * @sig: Signature to test against |
429 | NVRAM_BLOCK_LEN) - sizeof(struct err_log_info); | 426 | * @out_size: if non-NULL, returns the size of the data part of the partition |
430 | return 0; | 427 | */ |
428 | loff_t nvram_find_partition(const char *name, int sig, int *out_size) | ||
429 | { | ||
430 | struct nvram_partition *p; | ||
431 | |||
432 | list_for_each_entry(p, &nvram_partitions, partition) { | ||
433 | if (p->header.signature == sig && | ||
434 | (!name || !strncmp(p->header.name, name, 12))) { | ||
435 | if (out_size) | ||
436 | *out_size = (p->header.length - 1) * | ||
437 | NVRAM_BLOCK_LEN; | ||
438 | return p->index + NVRAM_HEADER_LEN; | ||
431 | } | 439 | } |
432 | } | 440 | } |
433 | |||
434 | /* try creating a partition with the free space we have */ | ||
435 | rc = nvram_create_os_partition(); | ||
436 | if (!rc) { | ||
437 | return 0; | ||
438 | } | ||
439 | |||
440 | /* need to free up some space */ | ||
441 | rc = nvram_remove_os_partition(); | ||
442 | if (rc) { | ||
443 | return rc; | ||
444 | } | ||
445 | |||
446 | /* create a partition in this new space */ | ||
447 | rc = nvram_create_os_partition(); | ||
448 | if (rc) { | ||
449 | printk(KERN_ERR "nvram_create_os_partition: Could not find a " | ||
450 | "NVRAM partition large enough\n"); | ||
451 | return rc; | ||
452 | } | ||
453 | |||
454 | return 0; | 441 | return 0; |
455 | } | 442 | } |
456 | 443 | ||
457 | 444 | int __init nvram_scan_partitions(void) | |
458 | static int __init nvram_scan_partitions(void) | ||
459 | { | 445 | { |
460 | loff_t cur_index = 0; | 446 | loff_t cur_index = 0; |
461 | struct nvram_header phead; | 447 | struct nvram_header phead; |
@@ -465,7 +451,7 @@ static int __init nvram_scan_partitions(void) | |||
465 | int total_size; | 451 | int total_size; |
466 | int err; | 452 | int err; |
467 | 453 | ||
468 | if (ppc_md.nvram_size == NULL) | 454 | if (ppc_md.nvram_size == NULL || ppc_md.nvram_size() <= 0) |
469 | return -ENODEV; | 455 | return -ENODEV; |
470 | total_size = ppc_md.nvram_size(); | 456 | total_size = ppc_md.nvram_size(); |
471 | 457 | ||
@@ -512,12 +498,16 @@ static int __init nvram_scan_partitions(void) | |||
512 | 498 | ||
513 | memcpy(&tmp_part->header, &phead, NVRAM_HEADER_LEN); | 499 | memcpy(&tmp_part->header, &phead, NVRAM_HEADER_LEN); |
514 | tmp_part->index = cur_index; | 500 | tmp_part->index = cur_index; |
515 | list_add_tail(&tmp_part->partition, &nvram_part->partition); | 501 | list_add_tail(&tmp_part->partition, &nvram_partitions); |
516 | 502 | ||
517 | cur_index += phead.length * NVRAM_BLOCK_LEN; | 503 | cur_index += phead.length * NVRAM_BLOCK_LEN; |
518 | } | 504 | } |
519 | err = 0; | 505 | err = 0; |
520 | 506 | ||
507 | #ifdef DEBUG_NVRAM | ||
508 | nvram_print_partitions("NVRAM Partitions"); | ||
509 | #endif | ||
510 | |||
521 | out: | 511 | out: |
522 | kfree(header); | 512 | kfree(header); |
523 | return err; | 513 | return err; |
@@ -525,9 +515,10 @@ static int __init nvram_scan_partitions(void) | |||
525 | 515 | ||
526 | static int __init nvram_init(void) | 516 | static int __init nvram_init(void) |
527 | { | 517 | { |
528 | int error; | ||
529 | int rc; | 518 | int rc; |
530 | 519 | ||
520 | BUILD_BUG_ON(NVRAM_BLOCK_LEN != 16); | ||
521 | |||
531 | if (ppc_md.nvram_size == NULL || ppc_md.nvram_size() <= 0) | 522 | if (ppc_md.nvram_size == NULL || ppc_md.nvram_size() <= 0) |
532 | return -ENODEV; | 523 | return -ENODEV; |
533 | 524 | ||
@@ -537,29 +528,6 @@ static int __init nvram_init(void) | |||
537 | return rc; | 528 | return rc; |
538 | } | 529 | } |
539 | 530 | ||
540 | /* initialize our anchor for the nvram partition list */ | ||
541 | nvram_part = kmalloc(sizeof(struct nvram_partition), GFP_KERNEL); | ||
542 | if (!nvram_part) { | ||
543 | printk(KERN_ERR "nvram_init: Failed kmalloc\n"); | ||
544 | return -ENOMEM; | ||
545 | } | ||
546 | INIT_LIST_HEAD(&nvram_part->partition); | ||
547 | |||
548 | /* Get all the NVRAM partitions */ | ||
549 | error = nvram_scan_partitions(); | ||
550 | if (error) { | ||
551 | printk(KERN_ERR "nvram_init: Failed nvram_scan_partitions\n"); | ||
552 | return error; | ||
553 | } | ||
554 | |||
555 | if(nvram_setup_partition()) | ||
556 | printk(KERN_WARNING "nvram_init: Could not find nvram partition" | ||
557 | " for nvram buffered error logging.\n"); | ||
558 | |||
559 | #ifdef DEBUG_NVRAM | ||
560 | nvram_print_partitions("NVRAM Partitions"); | ||
561 | #endif | ||
562 | |||
563 | return rc; | 531 | return rc; |
564 | } | 532 | } |
565 | 533 | ||
@@ -568,135 +536,6 @@ void __exit nvram_cleanup(void) | |||
568 | misc_deregister( &nvram_dev ); | 536 | misc_deregister( &nvram_dev ); |
569 | } | 537 | } |
570 | 538 | ||
571 | |||
572 | #ifdef CONFIG_PPC_PSERIES | ||
573 | |||
574 | /* nvram_write_error_log | ||
575 | * | ||
576 | * We need to buffer the error logs into nvram to ensure that we have | ||
577 | * the failure information to decode. If we have a severe error there | ||
578 | * is no way to guarantee that the OS or the machine is in a state to | ||
579 | * get back to user land and write the error to disk. For example if | ||
580 | * the SCSI device driver causes a Machine Check by writing to a bad | ||
581 | * IO address, there is no way of guaranteeing that the device driver | ||
582 | * is in any state that is would also be able to write the error data | ||
583 | * captured to disk, thus we buffer it in NVRAM for analysis on the | ||
584 | * next boot. | ||
585 | * | ||
586 | * In NVRAM the partition containing the error log buffer will looks like: | ||
587 | * Header (in bytes): | ||
588 | * +-----------+----------+--------+------------+------------------+ | ||
589 | * | signature | checksum | length | name | data | | ||
590 | * |0 |1 |2 3|4 15|16 length-1| | ||
591 | * +-----------+----------+--------+------------+------------------+ | ||
592 | * | ||
593 | * The 'data' section would look like (in bytes): | ||
594 | * +--------------+------------+-----------------------------------+ | ||
595 | * | event_logged | sequence # | error log | | ||
596 | * |0 3|4 7|8 nvram_error_log_size-1| | ||
597 | * +--------------+------------+-----------------------------------+ | ||
598 | * | ||
599 | * event_logged: 0 if event has not been logged to syslog, 1 if it has | ||
600 | * sequence #: The unique sequence # for each event. (until it wraps) | ||
601 | * error log: The error log from event_scan | ||
602 | */ | ||
603 | int nvram_write_error_log(char * buff, int length, | ||
604 | unsigned int err_type, unsigned int error_log_cnt) | ||
605 | { | ||
606 | int rc; | ||
607 | loff_t tmp_index; | ||
608 | struct err_log_info info; | ||
609 | |||
610 | if (nvram_error_log_index == -1) { | ||
611 | return -ESPIPE; | ||
612 | } | ||
613 | |||
614 | if (length > nvram_error_log_size) { | ||
615 | length = nvram_error_log_size; | ||
616 | } | ||
617 | |||
618 | info.error_type = err_type; | ||
619 | info.seq_num = error_log_cnt; | ||
620 | |||
621 | tmp_index = nvram_error_log_index; | ||
622 | |||
623 | rc = ppc_md.nvram_write((char *)&info, sizeof(struct err_log_info), &tmp_index); | ||
624 | if (rc <= 0) { | ||
625 | printk(KERN_ERR "nvram_write_error_log: Failed nvram_write (%d)\n", rc); | ||
626 | return rc; | ||
627 | } | ||
628 | |||
629 | rc = ppc_md.nvram_write(buff, length, &tmp_index); | ||
630 | if (rc <= 0) { | ||
631 | printk(KERN_ERR "nvram_write_error_log: Failed nvram_write (%d)\n", rc); | ||
632 | return rc; | ||
633 | } | ||
634 | |||
635 | return 0; | ||
636 | } | ||
637 | |||
638 | /* nvram_read_error_log | ||
639 | * | ||
640 | * Reads nvram for error log for at most 'length' | ||
641 | */ | ||
642 | int nvram_read_error_log(char * buff, int length, | ||
643 | unsigned int * err_type, unsigned int * error_log_cnt) | ||
644 | { | ||
645 | int rc; | ||
646 | loff_t tmp_index; | ||
647 | struct err_log_info info; | ||
648 | |||
649 | if (nvram_error_log_index == -1) | ||
650 | return -1; | ||
651 | |||
652 | if (length > nvram_error_log_size) | ||
653 | length = nvram_error_log_size; | ||
654 | |||
655 | tmp_index = nvram_error_log_index; | ||
656 | |||
657 | rc = ppc_md.nvram_read((char *)&info, sizeof(struct err_log_info), &tmp_index); | ||
658 | if (rc <= 0) { | ||
659 | printk(KERN_ERR "nvram_read_error_log: Failed nvram_read (%d)\n", rc); | ||
660 | return rc; | ||
661 | } | ||
662 | |||
663 | rc = ppc_md.nvram_read(buff, length, &tmp_index); | ||
664 | if (rc <= 0) { | ||
665 | printk(KERN_ERR "nvram_read_error_log: Failed nvram_read (%d)\n", rc); | ||
666 | return rc; | ||
667 | } | ||
668 | |||
669 | *error_log_cnt = info.seq_num; | ||
670 | *err_type = info.error_type; | ||
671 | |||
672 | return 0; | ||
673 | } | ||
674 | |||
675 | /* This doesn't actually zero anything, but it sets the event_logged | ||
676 | * word to tell that this event is safely in syslog. | ||
677 | */ | ||
678 | int nvram_clear_error_log(void) | ||
679 | { | ||
680 | loff_t tmp_index; | ||
681 | int clear_word = ERR_FLAG_ALREADY_LOGGED; | ||
682 | int rc; | ||
683 | |||
684 | if (nvram_error_log_index == -1) | ||
685 | return -1; | ||
686 | |||
687 | tmp_index = nvram_error_log_index; | ||
688 | |||
689 | rc = ppc_md.nvram_write((char *)&clear_word, sizeof(int), &tmp_index); | ||
690 | if (rc <= 0) { | ||
691 | printk(KERN_ERR "nvram_clear_error_log: Failed nvram_write (%d)\n", rc); | ||
692 | return rc; | ||
693 | } | ||
694 | |||
695 | return 0; | ||
696 | } | ||
697 | |||
698 | #endif /* CONFIG_PPC_PSERIES */ | ||
699 | |||
700 | module_init(nvram_init); | 539 | module_init(nvram_init); |
701 | module_exit(nvram_cleanup); | 540 | module_exit(nvram_cleanup); |
702 | MODULE_LICENSE("GPL"); | 541 | MODULE_LICENSE("GPL"); |
diff --git a/arch/powerpc/mm/pgtable.c b/arch/powerpc/mm/pgtable.c index 2c7e801ab20b..6a3997f98dfb 100644 --- a/arch/powerpc/mm/pgtable.c +++ b/arch/powerpc/mm/pgtable.c | |||
@@ -92,7 +92,7 @@ static void pte_free_rcu_callback(struct rcu_head *head) | |||
92 | 92 | ||
93 | static void pte_free_submit(struct pte_freelist_batch *batch) | 93 | static void pte_free_submit(struct pte_freelist_batch *batch) |
94 | { | 94 | { |
95 | call_rcu(&batch->rcu, pte_free_rcu_callback); | 95 | call_rcu_sched(&batch->rcu, pte_free_rcu_callback); |
96 | } | 96 | } |
97 | 97 | ||
98 | void pgtable_free_tlb(struct mmu_gather *tlb, void *table, unsigned shift) | 98 | void pgtable_free_tlb(struct mmu_gather *tlb, void *table, unsigned shift) |
diff --git a/arch/powerpc/platforms/chrp/time.c b/arch/powerpc/platforms/chrp/time.c index 054dfe5b8e77..f803f4b8ab6f 100644 --- a/arch/powerpc/platforms/chrp/time.c +++ b/arch/powerpc/platforms/chrp/time.c | |||
@@ -29,6 +29,10 @@ | |||
29 | 29 | ||
30 | extern spinlock_t rtc_lock; | 30 | extern spinlock_t rtc_lock; |
31 | 31 | ||
32 | #define NVRAM_AS0 0x74 | ||
33 | #define NVRAM_AS1 0x75 | ||
34 | #define NVRAM_DATA 0x77 | ||
35 | |||
32 | static int nvram_as1 = NVRAM_AS1; | 36 | static int nvram_as1 = NVRAM_AS1; |
33 | static int nvram_as0 = NVRAM_AS0; | 37 | static int nvram_as0 = NVRAM_AS0; |
34 | static int nvram_data = NVRAM_DATA; | 38 | static int nvram_data = NVRAM_DATA; |
diff --git a/arch/powerpc/platforms/pseries/nvram.c b/arch/powerpc/platforms/pseries/nvram.c index bc3c7f2abd79..7e828ba29bc3 100644 --- a/arch/powerpc/platforms/pseries/nvram.c +++ b/arch/powerpc/platforms/pseries/nvram.c | |||
@@ -22,11 +22,25 @@ | |||
22 | #include <asm/prom.h> | 22 | #include <asm/prom.h> |
23 | #include <asm/machdep.h> | 23 | #include <asm/machdep.h> |
24 | 24 | ||
25 | /* Max bytes to read/write in one go */ | ||
26 | #define NVRW_CNT 0x20 | ||
27 | |||
25 | static unsigned int nvram_size; | 28 | static unsigned int nvram_size; |
26 | static int nvram_fetch, nvram_store; | 29 | static int nvram_fetch, nvram_store; |
27 | static char nvram_buf[NVRW_CNT]; /* assume this is in the first 4GB */ | 30 | static char nvram_buf[NVRW_CNT]; /* assume this is in the first 4GB */ |
28 | static DEFINE_SPINLOCK(nvram_lock); | 31 | static DEFINE_SPINLOCK(nvram_lock); |
29 | 32 | ||
33 | static long nvram_error_log_index = -1; | ||
34 | static long nvram_error_log_size = 0; | ||
35 | |||
36 | struct err_log_info { | ||
37 | int error_type; | ||
38 | unsigned int seq_num; | ||
39 | }; | ||
40 | #define NVRAM_MAX_REQ 2079 | ||
41 | #define NVRAM_MIN_REQ 1055 | ||
42 | |||
43 | #define NVRAM_LOG_PART_NAME "ibm,rtas-log" | ||
30 | 44 | ||
31 | static ssize_t pSeries_nvram_read(char *buf, size_t count, loff_t *index) | 45 | static ssize_t pSeries_nvram_read(char *buf, size_t count, loff_t *index) |
32 | { | 46 | { |
@@ -119,6 +133,197 @@ static ssize_t pSeries_nvram_get_size(void) | |||
119 | return nvram_size ? nvram_size : -ENODEV; | 133 | return nvram_size ? nvram_size : -ENODEV; |
120 | } | 134 | } |
121 | 135 | ||
136 | |||
137 | /* nvram_write_error_log | ||
138 | * | ||
139 | * We need to buffer the error logs into nvram to ensure that we have | ||
140 | * the failure information to decode. If we have a severe error there | ||
141 | * is no way to guarantee that the OS or the machine is in a state to | ||
142 | * get back to user land and write the error to disk. For example if | ||
143 | * the SCSI device driver causes a Machine Check by writing to a bad | ||
144 | * IO address, there is no way of guaranteeing that the device driver | ||
145 | * is in any state that is would also be able to write the error data | ||
146 | * captured to disk, thus we buffer it in NVRAM for analysis on the | ||
147 | * next boot. | ||
148 | * | ||
149 | * In NVRAM the partition containing the error log buffer will looks like: | ||
150 | * Header (in bytes): | ||
151 | * +-----------+----------+--------+------------+------------------+ | ||
152 | * | signature | checksum | length | name | data | | ||
153 | * |0 |1 |2 3|4 15|16 length-1| | ||
154 | * +-----------+----------+--------+------------+------------------+ | ||
155 | * | ||
156 | * The 'data' section would look like (in bytes): | ||
157 | * +--------------+------------+-----------------------------------+ | ||
158 | * | event_logged | sequence # | error log | | ||
159 | * |0 3|4 7|8 nvram_error_log_size-1| | ||
160 | * +--------------+------------+-----------------------------------+ | ||
161 | * | ||
162 | * event_logged: 0 if event has not been logged to syslog, 1 if it has | ||
163 | * sequence #: The unique sequence # for each event. (until it wraps) | ||
164 | * error log: The error log from event_scan | ||
165 | */ | ||
166 | int nvram_write_error_log(char * buff, int length, | ||
167 | unsigned int err_type, unsigned int error_log_cnt) | ||
168 | { | ||
169 | int rc; | ||
170 | loff_t tmp_index; | ||
171 | struct err_log_info info; | ||
172 | |||
173 | if (nvram_error_log_index == -1) { | ||
174 | return -ESPIPE; | ||
175 | } | ||
176 | |||
177 | if (length > nvram_error_log_size) { | ||
178 | length = nvram_error_log_size; | ||
179 | } | ||
180 | |||
181 | info.error_type = err_type; | ||
182 | info.seq_num = error_log_cnt; | ||
183 | |||
184 | tmp_index = nvram_error_log_index; | ||
185 | |||
186 | rc = ppc_md.nvram_write((char *)&info, sizeof(struct err_log_info), &tmp_index); | ||
187 | if (rc <= 0) { | ||
188 | printk(KERN_ERR "nvram_write_error_log: Failed nvram_write (%d)\n", rc); | ||
189 | return rc; | ||
190 | } | ||
191 | |||
192 | rc = ppc_md.nvram_write(buff, length, &tmp_index); | ||
193 | if (rc <= 0) { | ||
194 | printk(KERN_ERR "nvram_write_error_log: Failed nvram_write (%d)\n", rc); | ||
195 | return rc; | ||
196 | } | ||
197 | |||
198 | return 0; | ||
199 | } | ||
200 | |||
201 | /* nvram_read_error_log | ||
202 | * | ||
203 | * Reads nvram for error log for at most 'length' | ||
204 | */ | ||
205 | int nvram_read_error_log(char * buff, int length, | ||
206 | unsigned int * err_type, unsigned int * error_log_cnt) | ||
207 | { | ||
208 | int rc; | ||
209 | loff_t tmp_index; | ||
210 | struct err_log_info info; | ||
211 | |||
212 | if (nvram_error_log_index == -1) | ||
213 | return -1; | ||
214 | |||
215 | if (length > nvram_error_log_size) | ||
216 | length = nvram_error_log_size; | ||
217 | |||
218 | tmp_index = nvram_error_log_index; | ||
219 | |||
220 | rc = ppc_md.nvram_read((char *)&info, sizeof(struct err_log_info), &tmp_index); | ||
221 | if (rc <= 0) { | ||
222 | printk(KERN_ERR "nvram_read_error_log: Failed nvram_read (%d)\n", rc); | ||
223 | return rc; | ||
224 | } | ||
225 | |||
226 | rc = ppc_md.nvram_read(buff, length, &tmp_index); | ||
227 | if (rc <= 0) { | ||
228 | printk(KERN_ERR "nvram_read_error_log: Failed nvram_read (%d)\n", rc); | ||
229 | return rc; | ||
230 | } | ||
231 | |||
232 | *error_log_cnt = info.seq_num; | ||
233 | *err_type = info.error_type; | ||
234 | |||
235 | return 0; | ||
236 | } | ||
237 | |||
238 | /* This doesn't actually zero anything, but it sets the event_logged | ||
239 | * word to tell that this event is safely in syslog. | ||
240 | */ | ||
241 | int nvram_clear_error_log(void) | ||
242 | { | ||
243 | loff_t tmp_index; | ||
244 | int clear_word = ERR_FLAG_ALREADY_LOGGED; | ||
245 | int rc; | ||
246 | |||
247 | if (nvram_error_log_index == -1) | ||
248 | return -1; | ||
249 | |||
250 | tmp_index = nvram_error_log_index; | ||
251 | |||
252 | rc = ppc_md.nvram_write((char *)&clear_word, sizeof(int), &tmp_index); | ||
253 | if (rc <= 0) { | ||
254 | printk(KERN_ERR "nvram_clear_error_log: Failed nvram_write (%d)\n", rc); | ||
255 | return rc; | ||
256 | } | ||
257 | |||
258 | return 0; | ||
259 | } | ||
260 | |||
261 | /* pseries_nvram_init_log_partition | ||
262 | * | ||
263 | * This will setup the partition we need for buffering the | ||
264 | * error logs and cleanup partitions if needed. | ||
265 | * | ||
266 | * 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). | ||
276 | */ | ||
277 | static int __init pseries_nvram_init_log_partition(void) | ||
278 | { | ||
279 | loff_t p; | ||
280 | int size; | ||
281 | |||
282 | /* Scan nvram for partitions */ | ||
283 | nvram_scan_partitions(); | ||
284 | |||
285 | /* Lookg for ours */ | ||
286 | p = nvram_find_partition(NVRAM_LOG_PART_NAME, NVRAM_SIG_OS, &size); | ||
287 | |||
288 | /* 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); | ||
293 | p = 0; | ||
294 | } | ||
295 | |||
296 | /* Create one if we didn't find */ | ||
297 | 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 | */ | ||
303 | 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); | ||
310 | } | ||
311 | } | ||
312 | |||
313 | 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; | ||
317 | } | ||
318 | |||
319 | nvram_error_log_index = p; | ||
320 | nvram_error_log_size = nvram_get_partition_size(p) - | ||
321 | sizeof(struct err_log_info); | ||
322 | |||
323 | return 0; | ||
324 | } | ||
325 | machine_arch_initcall(pseries, pseries_nvram_init_log_partition); | ||
326 | |||
122 | int __init pSeries_nvram_init(void) | 327 | int __init pSeries_nvram_init(void) |
123 | { | 328 | { |
124 | struct device_node *nvram; | 329 | struct device_node *nvram; |