1 /*
2 * c 2001 PPC 64 Team, IBM Corp
3 *
4 * This program is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU General Public License
6 * as published by the Free Software Foundation; either version
7 * 2 of the License, or (at your option) any later version.
8 *
9 * /dev/nvram driver for PPC64
10 *
11 * This perhaps should live in drivers/char
12 */
13
14 #include <linux/module.h>
15
16 #include <linux/types.h>
17 #include <linux/errno.h>
18 #include <linux/fs.h>
19 #include <linux/miscdevice.h>
20 #include <linux/fcntl.h>
21 #include <linux/nvram.h>
22 #include <linux/init.h>
23 #include <linux/slab.h>
24 #include <linux/spinlock.h>
25 #include <asm/uaccess.h>
26 #include <asm/nvram.h>
27 #include <asm/rtas.h>
28 #include <asm/prom.h>
29
30 #include <linux/string.h>
31
32 /*#define DEBUG_NVRAM*/
33
34 static int scan_nvram_partitions(void);
35 static int setup_nvram_partition(void);
36 static int create_os_nvram_partition(void);
37 static int remove_os_nvram_partition(void);
38 static unsigned char nvram_checksum(struct nvram_header *p);
39 static int write_nvram_header(struct nvram_partition * part);
40 static ssize_t __read_nvram(char *buf, size_t count, loff_t *index);
41 static ssize_t __write_nvram(char *buf, size_t count, loff_t *index);
42
43 static unsigned int rtas_nvram_size = 0;
44 static unsigned int nvram_fetch, nvram_store;
45 static char nvram_buf[NVRW_CNT]; /* assume this is in the first 4GB */
46 static struct nvram_partition * nvram_part;
47 static long error_log_nvram_index = -1;
48 static long error_log_nvram_size = 0;
49 static spinlock_t nvram_lock = SPIN_LOCK_UNLOCKED;
50
51 volatile int no_more_logging = 1;
52
53 extern volatile int error_log_cnt;
54
55 struct err_log_info {
56 int error_type;
57 unsigned int seq_num;
58 };
59
dev_ppc64_nvram_llseek(struct file * file,loff_t offset,int origin)60 static loff_t dev_ppc64_nvram_llseek(struct file *file, loff_t offset, int origin)
61 {
62 switch (origin) {
63 case 1:
64 offset += file->f_pos;
65 break;
66 case 2:
67 offset += rtas_nvram_size;
68 break;
69 }
70 if (offset < 0)
71 return -EINVAL;
72 file->f_pos = offset;
73 return file->f_pos;
74 }
75
76
dev_ppc64_read_nvram(struct file * file,char * buf,size_t count,loff_t * ppos)77 static ssize_t dev_ppc64_read_nvram(struct file *file, char *buf,
78 size_t count, loff_t *ppos)
79 {
80 unsigned long len;
81 char *tmp_buffer;
82 loff_t pos = *ppos;
83
84 if (verify_area(VERIFY_WRITE, buf, count))
85 return -EFAULT;
86 if ((unsigned)pos != pos || pos >= rtas_nvram_size)
87 return 0;
88 if (count > rtas_nvram_size)
89 count = rtas_nvram_size;
90
91 tmp_buffer = kmalloc(count, GFP_KERNEL);
92 if (!tmp_buffer) {
93 printk(KERN_ERR "dev_ppc64_read_nvram: kmalloc failed\n");
94 return 0;
95 }
96
97 len = read_nvram(tmp_buffer, count, &pos);
98 if ((long)len <= 0) {
99 kfree(tmp_buffer);
100 return len;
101 }
102
103 if (copy_to_user(buf, tmp_buffer, len)) {
104 kfree(tmp_buffer);
105 return -EFAULT;
106 }
107
108 kfree(tmp_buffer);
109 *ppos = pos;
110 return len;
111
112 }
113
dev_ppc64_write_nvram(struct file * file,const char * buf,size_t count,loff_t * ppos)114 static ssize_t dev_ppc64_write_nvram(struct file *file, const char *buf,
115 size_t count, loff_t *ppos)
116 {
117 unsigned long len;
118 char * tmp_buffer;
119 loff_t pos = *ppos;
120
121 if (verify_area(VERIFY_READ, buf, count))
122 return -EFAULT;
123 if (pos != (unsigned) pos || pos >= rtas_nvram_size)
124 return 0;
125 if (count > rtas_nvram_size)
126 count = rtas_nvram_size;
127
128 tmp_buffer = kmalloc(count, GFP_KERNEL);
129 if (!tmp_buffer) {
130 printk(KERN_ERR "dev_ppc64_write_nvram: kmalloc failed\n");
131 return 0;
132 }
133
134 if (copy_from_user(tmp_buffer, buf, count)) {
135 kfree(tmp_buffer);
136 return -EFAULT;
137 }
138
139 len = write_nvram(tmp_buffer, count, &pos);
140 *ppos = pos;
141
142 kfree(tmp_buffer);
143 return len;
144 }
145
dev_ppc64_nvram_ioctl(struct inode * inode,struct file * file,unsigned int cmd,unsigned long arg)146 static int dev_ppc64_nvram_ioctl(struct inode *inode, struct file *file,
147 unsigned int cmd, unsigned long arg)
148 {
149 return -EINVAL;
150 }
151
152 struct file_operations nvram_fops = {
153 .owner = THIS_MODULE,
154 .llseek = dev_ppc64_nvram_llseek,
155 .read = dev_ppc64_read_nvram,
156 .write = dev_ppc64_write_nvram,
157 .ioctl = dev_ppc64_nvram_ioctl
158 };
159
160 static struct miscdevice nvram_dev = {
161 NVRAM_MINOR,
162 "nvram",
163 &nvram_fops
164 };
165
read_nvram(char * buf,size_t count,loff_t * index)166 ssize_t read_nvram(char *buf, size_t count, loff_t *index)
167 {
168 unsigned long s;
169 ssize_t rc;
170
171 spin_lock_irqsave(&nvram_lock, s);
172 rc = __read_nvram(buf, count, index);
173 spin_unlock_irqrestore(&nvram_lock, s);
174
175 return rc;
176 }
__read_nvram(char * buf,size_t count,loff_t * index)177 static ssize_t __read_nvram(char *buf, size_t count, loff_t *index)
178 {
179 unsigned int i;
180 unsigned long len;
181 unsigned long remainder;
182 char *p = buf;
183
184 if (((*index + count) > rtas_nvram_size) || (count < 0))
185 return 0;
186
187 if (count <= NVRW_CNT) {
188 remainder = count;
189 } else {
190 remainder = count % NVRW_CNT;
191 }
192
193 if (remainder) {
194 if((rtas_call(nvram_fetch, 3, 2, &len, *index, __pa(nvram_buf),
195 remainder) != 0) || len != remainder) {
196 return -EIO;
197 }
198
199 count -= remainder;
200 memcpy(p, nvram_buf, remainder);
201 p += remainder;
202 }
203
204 for (i = *index + remainder; count > 0 && i < rtas_nvram_size;
205 count -= NVRW_CNT) {
206 if ((rtas_call(nvram_fetch, 3, 2, &len, i, __pa(nvram_buf),
207 NVRW_CNT) != 0) || len != NVRW_CNT) {
208 return -EIO;
209 }
210
211 memcpy(p, nvram_buf, NVRW_CNT);
212
213 p += NVRW_CNT;
214 i += NVRW_CNT;
215 }
216
217 *index = i;
218 return p - buf;
219 }
220
write_nvram(char * buf,size_t count,loff_t * index)221 ssize_t write_nvram(char *buf, size_t count, loff_t *index)
222 {
223 unsigned long s;
224 ssize_t rc;
225
226 spin_lock_irqsave(&nvram_lock, s);
227 rc = __write_nvram(buf, count, index);
228 spin_unlock_irqrestore(&nvram_lock, s);
229
230 return rc;
231 }
__write_nvram(char * buf,size_t count,loff_t * index)232 static ssize_t __write_nvram(char *buf, size_t count, loff_t *index)
233 {
234 unsigned int i;
235 unsigned long len;
236 const char *p = buf;
237 unsigned long remainder;
238
239 if (((*index + count) > rtas_nvram_size) || (count < 0))
240 return 0;
241
242 if (count <= NVRW_CNT) {
243 remainder = count;
244 } else {
245 remainder = count % NVRW_CNT;
246 }
247
248 if (remainder) {
249 memcpy(nvram_buf, p, remainder);
250
251 if((rtas_call(nvram_store, 3, 2, &len, *index, __pa(nvram_buf),
252 remainder) != 0) || len != remainder) {
253 return -EIO;
254 }
255
256 count -= remainder;
257 p += remainder;
258 }
259
260 for (i = *index + remainder; count > 0 && i < rtas_nvram_size;
261 count -= NVRW_CNT) {
262
263 memcpy(nvram_buf, p, NVRW_CNT);
264
265 if ((rtas_call(nvram_store, 3, 2, &len, i, __pa(nvram_buf),
266 NVRW_CNT) != 0) || len != NVRW_CNT) {
267 return -EIO;
268 }
269
270 p += NVRW_CNT;
271 i += NVRW_CNT;
272 }
273
274 *index = i;
275 return p - buf;
276 }
277
nvram_init(void)278 int __init nvram_init(void)
279 {
280 struct device_node *nvram;
281 unsigned int *nbytes_p, proplen;
282 int error;
283 int rc;
284
285 if ((nvram = find_type_devices("nvram")) != NULL) {
286 nbytes_p = (unsigned int *)get_property(nvram, "#bytes", &proplen);
287 if (nbytes_p && proplen == sizeof(unsigned int)) {
288 rtas_nvram_size = *nbytes_p;
289 } else {
290 return -EIO;
291 }
292 } else {
293 /* If we don't know how big NVRAM is then we shouldn't touch
294 the nvram partitions */
295 return -EIO;
296 }
297
298 nvram_fetch = rtas_token("nvram-fetch");
299 if (nvram_fetch == RTAS_UNKNOWN_SERVICE) {
300 printk("nvram_init: Does not support nvram-fetch\n");
301 return -EIO;
302 }
303
304 nvram_store = rtas_token("nvram-store");
305 if (nvram_store == RTAS_UNKNOWN_SERVICE) {
306 printk("nvram_init: Does not support nvram-store\n");
307 return -EIO;
308 }
309 printk(KERN_INFO "PPC64 nvram contains %d bytes\n", rtas_nvram_size);
310
311 rc = misc_register(&nvram_dev);
312 if (rc) {
313 printk(KERN_ERR "nvram_init: Failed misc_register (%d)\n", rc);
314 /* Going to continue to setup nvram for internal
315 * kernel services */
316 }
317
318
319 /* initialize our anchor for the nvram partition list */
320 nvram_part = kmalloc(sizeof(struct nvram_partition), GFP_KERNEL);
321 if (!nvram_part) {
322 printk(KERN_ERR "nvram_init: Failed kmalloc\n");
323 return -ENOMEM;
324 }
325 INIT_LIST_HEAD(&nvram_part->partition);
326
327 /* Get all the NVRAM partitions */
328 error = scan_nvram_partitions();
329 if (error) {
330 printk(KERN_ERR "nvram_init: Failed scan_nvram_partitions\n");
331 return error;
332 }
333
334 error = setup_nvram_partition();
335 if (error) {
336 printk(KERN_WARNING "nvram_init: Could not find nvram partition"
337 " for nvram buffered error logging.\n");
338 return error;
339 }
340
341 #ifdef DEBUG_NVRAM
342 print_nvram_partitions("NVRAM Partitions");
343 #endif
344
345 return rc;
346 }
347
nvram_cleanup(void)348 void __exit nvram_cleanup(void)
349 {
350 misc_deregister( &nvram_dev );
351 }
352
scan_nvram_partitions(void)353 static int scan_nvram_partitions(void)
354 {
355 loff_t cur_index = 0;
356 struct nvram_header phead;
357 struct nvram_partition * tmp_part;
358 unsigned char c_sum;
359 long size;
360
361 while (cur_index < rtas_nvram_size) {
362
363 size = read_nvram((char *)&phead, NVRAM_HEADER_LEN, &cur_index);
364 if (size != NVRAM_HEADER_LEN) {
365 printk(KERN_ERR "scan_nvram_partitions: Error parsing "
366 "nvram partitions\n");
367 return size;
368 }
369
370 cur_index -= NVRAM_HEADER_LEN; /* read_nvram will advance us */
371
372 c_sum = nvram_checksum(&phead);
373 if (c_sum != phead.checksum)
374 printk(KERN_WARNING "WARNING: nvram partition checksum "
375 "was %02x, should be %02x!\n", phead.checksum, c_sum);
376
377 tmp_part = kmalloc(sizeof(struct nvram_partition), GFP_KERNEL);
378 if (!tmp_part) {
379 printk(KERN_ERR "scan_nvram_partitions: kmalloc failed\n");
380 return -ENOMEM;
381 }
382
383 memcpy(&tmp_part->header, &phead, NVRAM_HEADER_LEN);
384 tmp_part->index = cur_index;
385 list_add_tail(&tmp_part->partition, &nvram_part->partition);
386
387 cur_index += phead.length * NVRAM_BLOCK_LEN;
388 }
389
390 return 0;
391 }
392
393 /* setup_nvram_partition
394 *
395 * This will setup the partition we need for buffering the
396 * error logs and cleanup partitions if needed.
397 *
398 * The general strategy is the following:
399 * 1.) If there is ppc64,linux partition large enough then use it.
400 * 2.) If there is not a ppc64,linux partition large enough, search
401 * for a free partition that is large enough.
402 * 3.) If there is not a free partition large enough remove
403 * _all_ OS partitions and consolidate the space.
404 * 4.) Will first try getting a chunk that will satisfy the maximum
405 * error log size (NVRAM_MAX_REQ).
406 * 5.) If the max chunk cannot be allocated then try finding a chunk
407 * that will satisfy the minum needed (NVRAM_MIN_REQ).
408 */
setup_nvram_partition(void)409 static int setup_nvram_partition(void)
410 {
411 struct list_head * p;
412 struct nvram_partition * part;
413 int rc;
414
415 /* see if we have an OS partition that meets our needs.
416 will try getting the max we need. If not we'll delete
417 partitions and try again. */
418 list_for_each(p, &nvram_part->partition) {
419 part = list_entry(p, struct nvram_partition, partition);
420 if (part->header.signature != NVRAM_SIG_OS)
421 continue;
422
423 if (strcmp(part->header.name, "ppc64,linux"))
424 continue;
425
426 if (part->header.length >= NVRAM_MIN_REQ) {
427 /* found our partition */
428 error_log_nvram_index = part->index + NVRAM_HEADER_LEN;
429 error_log_nvram_size = (part->header.length * NVRAM_BLOCK_LEN) -
430 NVRAM_HEADER_LEN - sizeof(struct err_log_info);
431 return 0;
432 }
433 }
434
435 /* try creating a partition with the free space we have */
436 rc = create_os_nvram_partition();
437 if (!rc) {
438 return 0;
439 }
440
441 /* need to free up some space */
442 rc = remove_os_nvram_partition();
443 if (rc) {
444 return rc;
445 }
446
447 /* create a partition in this new space */
448 rc = create_os_nvram_partition();
449 if (rc) {
450 printk(KERN_ERR "create_os_nvram_partition: Could not find a "
451 "NVRAM partition large enough (%d)\n", rc);
452 return rc;
453 }
454
455 return 0;
456 }
457
remove_os_nvram_partition(void)458 static int remove_os_nvram_partition(void)
459 {
460 struct list_head *i;
461 struct list_head *j;
462 struct nvram_partition * part;
463 struct nvram_partition * cur_part;
464 int rc;
465
466 list_for_each(i, &nvram_part->partition) {
467 part = list_entry(i, struct nvram_partition, partition);
468 if (part->header.signature != NVRAM_SIG_OS)
469 continue;
470
471 /* Make os partition a free partition */
472 part->header.signature = NVRAM_SIG_FREE;
473 sprintf(part->header.name, "wwwwwwwwwwww");
474 part->header.checksum = nvram_checksum(&part->header);
475
476 /* Merge contiguous free partitions backwards */
477 list_for_each_prev(j, &part->partition) {
478 cur_part = list_entry(j, struct nvram_partition, partition);
479 if (cur_part == nvram_part || cur_part->header.signature != NVRAM_SIG_FREE) {
480 break;
481 }
482
483 part->header.length += cur_part->header.length;
484 part->header.checksum = nvram_checksum(&part->header);
485 part->index = cur_part->index;
486
487 list_del(&cur_part->partition);
488 kfree(cur_part);
489 j = &part->partition; /* fixup our loop */
490 }
491
492 /* Merge contiguous free partitions forwards */
493 list_for_each(j, &part->partition) {
494 cur_part = list_entry(j, struct nvram_partition, partition);
495 if (cur_part == nvram_part || cur_part->header.signature != NVRAM_SIG_FREE) {
496 break;
497 }
498
499 part->header.length += cur_part->header.length;
500 part->header.checksum = nvram_checksum(&part->header);
501
502 list_del(&cur_part->partition);
503 kfree(cur_part);
504 j = &part->partition; /* fixup our loop */
505 }
506
507 rc = write_nvram_header(part);
508 if (rc <= 0) {
509 printk(KERN_ERR "remove_os_nvram_partition: write_nvram failed (%d)\n", rc);
510 return rc;
511 }
512
513 }
514
515 return 0;
516 }
517
518 /* create_os_nvram_partition
519 *
520 * Create a OS linux partition to buffer error logs.
521 * Will create a partition starting at the first free
522 * space found if space has enough room.
523 */
create_os_nvram_partition(void)524 static int create_os_nvram_partition(void)
525 {
526 struct list_head * p;
527 struct nvram_partition * part;
528 struct nvram_partition * new_part = NULL;
529 struct nvram_partition * free_part;
530 struct err_log_info seq_init = { 0, 0 };
531 loff_t tmp_index;
532 long size = 0;
533 int rc;
534
535 /* Find a free partition that will give us the maximum needed size
536 If can't find one that will give us the minimum size needed */
537 list_for_each(p, &nvram_part->partition) {
538 part = list_entry(p, struct nvram_partition, partition);
539 if (part->header.signature != NVRAM_SIG_FREE)
540 continue;
541
542 if (part->header.length >= NVRAM_MAX_REQ) {
543 size = NVRAM_MAX_REQ;
544 free_part = part;
545 break;
546 }
547 if (!size && part->header.length >= NVRAM_MIN_REQ) {
548 size = NVRAM_MIN_REQ;
549 free_part = part;
550 }
551 }
552 if (!size) {
553 return -ENOSPC;
554 }
555
556 /* Create our OS partition */
557 new_part = kmalloc(sizeof(struct nvram_partition), GFP_KERNEL);
558 if (!new_part) {
559 printk(KERN_ERR "create_os_nvram_partition: kmalloc failed\n");
560 return -ENOMEM;
561 }
562
563 new_part->index = free_part->index;
564 new_part->header.signature = NVRAM_SIG_OS;
565 new_part->header.length = size;
566 sprintf(new_part->header.name, "ppc64,linux");
567 new_part->header.checksum = nvram_checksum(&new_part->header);
568
569 rc = write_nvram_header(new_part);
570 if (rc <= 0) {
571 printk(KERN_ERR "create_os_nvram_partition: write_nvram_header \
572 failed (%d)\n", rc);
573 kfree(new_part);
574 return rc;
575 }
576
577 /* make sure and initialize to zero the sequence number and the error
578 type logged */
579 tmp_index = new_part->index + NVRAM_HEADER_LEN;
580 rc = write_nvram((char *)&seq_init, sizeof(seq_init), &tmp_index);
581 if (rc <= 0) {
582 printk(KERN_ERR "create_os_nvram_partition: write_nvram failed (%d)\n", rc);
583 kfree(new_part);
584 return rc;
585 }
586
587 error_log_nvram_index = new_part->index + NVRAM_HEADER_LEN;
588 error_log_nvram_size = (new_part->header.length * NVRAM_BLOCK_LEN) -
589 NVRAM_HEADER_LEN - sizeof(struct err_log_info);
590
591 list_add_tail(&new_part->partition, &free_part->partition);
592
593 if (free_part->header.length <= size) {
594 list_del(&free_part->partition);
595 kfree(free_part);
596 return 0;
597 }
598
599 /* Adjust the partition we stole the space from */
600 free_part->index += size * NVRAM_BLOCK_LEN;
601 free_part->header.length -= size;
602 free_part->header.checksum = nvram_checksum(&free_part->header);
603
604 rc = write_nvram_header(free_part);
605 if (rc <= 0) {
606 printk(KERN_ERR "create_os_nvram_partition: write_nvram_header "
607 "failed (%d)\n", rc);
608 error_log_nvram_index = -1;
609 error_log_nvram_size = 0;
610 return rc;
611 }
612
613 return 0;
614 }
615
616
print_nvram_partitions(char * label)617 void print_nvram_partitions(char * label)
618 {
619 struct list_head * p;
620 struct nvram_partition * tmp_part;
621
622 printk(KERN_WARNING "--------%s---------\n", label);
623 printk(KERN_WARNING "indx\t\tsig\tchks\tlen\tname\n");
624 list_for_each(p, &nvram_part->partition) {
625 tmp_part = list_entry(p, struct nvram_partition, partition);
626 printk(KERN_WARNING "%d \t%02x\t%02x\t%d\t%s\n",
627 tmp_part->index, tmp_part->header.signature,
628 tmp_part->header.checksum, tmp_part->header.length,
629 tmp_part->header.name);
630 }
631 }
632
633 /* write_error_log_nvram
634 * In NVRAM the partition containing the error log buffer will looks like:
635 * Header (in bytes):
636 * +-----------+----------+--------+------------+------------------+
637 * | signature | checksum | length | name | data |
638 * |0 |1 |2 3|4 15|16 length-1|
639 * +-----------+----------+--------+------------+------------------+
640 * NOTE: length is in NVRAM_BLOCK_LEN
641 *
642 * The 'data' section would look like (in bytes):
643 * +--------------+------------+-----------------------------------+
644 * | event_logged | sequence # | error log |
645 * |0 3|4 7|8 error_log_nvram_size-1|
646 * +--------------+------------+-----------------------------------+
647 *
648 * event_logged: 0 if event has not been logged to syslog, 1 if it has
649 * sequence #: The unique sequence # for each event. (until it wraps)
650 * error log: The error log from event_scan
651 */
write_error_log_nvram(char * buff,int num_bytes,unsigned int err_type)652 int write_error_log_nvram(char * buff, int num_bytes, unsigned int err_type)
653 {
654 int rc;
655 loff_t tmp_index;
656 struct err_log_info info;
657
658 if (no_more_logging) {
659 return -EPERM;
660 }
661
662 if (error_log_nvram_index == -1) {
663 return -ESPIPE;
664 }
665
666 if (num_bytes > error_log_nvram_size) {
667 num_bytes = error_log_nvram_size;
668 }
669
670 info.error_type = err_type;
671 info.seq_num = error_log_cnt;
672
673 tmp_index = error_log_nvram_index;
674
675 rc = write_nvram((char *)&info, sizeof(struct err_log_info), &tmp_index);
676 if (rc <= 0) {
677 printk(KERN_ERR "write_error_log_nvram: Failed write_nvram (%d)\n", rc);
678 return rc;
679 }
680
681 rc = write_nvram(buff, num_bytes, &tmp_index);
682 if (rc <= 0) {
683 printk(KERN_ERR "write_error_log_nvram: Failed write_nvram (%d)\n", rc);
684 return rc;
685 }
686
687 return 0;
688 }
689
690 /* read_error_log_nvram
691 *
692 * Reads nvram for error log for at most 'num_bytes'
693 */
read_error_log_nvram(char * buff,int num_bytes,unsigned int * err_type)694 int read_error_log_nvram(char * buff, int num_bytes, unsigned int * err_type)
695 {
696 int rc;
697 loff_t tmp_index;
698 struct err_log_info info;
699
700 if (error_log_nvram_index == -1)
701 return -1;
702
703 if (num_bytes > error_log_nvram_size)
704 num_bytes = error_log_nvram_size;
705
706 tmp_index = error_log_nvram_index;
707
708 rc = read_nvram((char *)&info, sizeof(struct err_log_info), &tmp_index);
709 if (rc <= 0) {
710 printk(KERN_ERR "read_error_log_nvram: Failed read_nvram (%d)\n", rc);
711 return rc;
712 }
713
714 rc = read_nvram(buff, num_bytes, &tmp_index);
715 if (rc <= 0) {
716 printk(KERN_ERR "read_error_log_nvram: Failed read_nvram (%d)\n", rc);
717 return rc;
718 }
719
720 error_log_cnt = info.seq_num;
721 *err_type = info.error_type;
722
723 return 0;
724 }
725
726 /* This doesn't actually zero anything, but it sets the event_logged
727 * word to tell that this event is safely in syslog.
728 */
clear_error_log_nvram()729 int clear_error_log_nvram()
730 {
731 loff_t tmp_index;
732 int clear_word = ERR_FLAG_ALREADY_LOGGED;
733 int rc;
734
735 if (error_log_nvram_index == -1) {
736 return -ESPIPE;
737 }
738
739 tmp_index = error_log_nvram_index;
740
741 rc = write_nvram((char *)&clear_word, sizeof(int), &tmp_index);
742 if (rc <= 0) {
743 printk(KERN_ERR "clear_error_log_nvram: Failed write_nvram (%d)\n", rc);
744 return rc;
745 }
746
747 return 0;
748 }
749
write_nvram_header(struct nvram_partition * part)750 static int write_nvram_header(struct nvram_partition * part)
751 {
752 loff_t tmp_index;
753 int rc;
754
755 tmp_index = part->index;
756 rc = write_nvram((char *)&part->header, NVRAM_HEADER_LEN, &tmp_index);
757
758 return rc;
759 }
760
nvram_checksum(struct nvram_header * p)761 static unsigned char nvram_checksum(struct nvram_header *p)
762 {
763 unsigned int c_sum, c_sum2;
764 unsigned short *sp = (unsigned short *)p->name; /* assume 6 shorts */
765 c_sum = p->signature + p->length + sp[0] + sp[1] + sp[2] + sp[3] + sp[4] + sp[5];
766
767 /* The sum may have spilled into the 3rd byte. Fold it back. */
768 c_sum = ((c_sum & 0xffff) + (c_sum >> 16)) & 0xffff;
769 /* The sum cannot exceed 2 bytes. Fold it into a checksum */
770 c_sum2 = (c_sum >> 8) + (c_sum << 8);
771 c_sum = ((c_sum + c_sum2) >> 8) & 0xff;
772 return c_sum;
773 }
774
775 module_init(nvram_init);
776 module_exit(nvram_cleanup);
777 MODULE_LICENSE("GPL");
778