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