| .. | .. |
|---|
| 1 | +// SPDX-License-Identifier: GPL-2.0-or-later |
|---|
| 1 | 2 | /* |
|---|
| 2 | 3 | * c 2001 PPC 64 Team, IBM Corp |
|---|
| 3 | 4 | * |
|---|
| 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 | 5 | * /dev/nvram driver for PPC64 |
|---|
| 10 | | - * |
|---|
| 11 | | - * This perhaps should live in drivers/char |
|---|
| 12 | | - * |
|---|
| 13 | | - * TODO: Split the /dev/nvram part (that one can use |
|---|
| 14 | | - * drivers/char/generic_nvram.c) from the arch & partition |
|---|
| 15 | | - * parsing code. |
|---|
| 16 | 6 | */ |
|---|
| 17 | 7 | |
|---|
| 18 | 8 | #include <linux/types.h> |
|---|
| .. | .. |
|---|
| 665 | 655 | int rc = -1; |
|---|
| 666 | 656 | |
|---|
| 667 | 657 | switch (reason) { |
|---|
| 668 | | - case KMSG_DUMP_RESTART: |
|---|
| 669 | | - case KMSG_DUMP_HALT: |
|---|
| 670 | | - case KMSG_DUMP_POWEROFF: |
|---|
| 658 | + case KMSG_DUMP_SHUTDOWN: |
|---|
| 671 | 659 | /* These are almost always orderly shutdowns. */ |
|---|
| 672 | 660 | return; |
|---|
| 673 | 661 | case KMSG_DUMP_OOPS: |
|---|
| .. | .. |
|---|
| 713 | 701 | |
|---|
| 714 | 702 | spin_unlock_irqrestore(&lock, flags); |
|---|
| 715 | 703 | } |
|---|
| 716 | | - |
|---|
| 717 | | -static loff_t dev_nvram_llseek(struct file *file, loff_t offset, int origin) |
|---|
| 718 | | -{ |
|---|
| 719 | | - if (ppc_md.nvram_size == NULL) |
|---|
| 720 | | - return -ENODEV; |
|---|
| 721 | | - return generic_file_llseek_size(file, offset, origin, MAX_LFS_FILESIZE, |
|---|
| 722 | | - ppc_md.nvram_size()); |
|---|
| 723 | | -} |
|---|
| 724 | | - |
|---|
| 725 | | - |
|---|
| 726 | | -static ssize_t dev_nvram_read(struct file *file, char __user *buf, |
|---|
| 727 | | - size_t count, loff_t *ppos) |
|---|
| 728 | | -{ |
|---|
| 729 | | - ssize_t ret; |
|---|
| 730 | | - char *tmp = NULL; |
|---|
| 731 | | - ssize_t size; |
|---|
| 732 | | - |
|---|
| 733 | | - if (!ppc_md.nvram_size) { |
|---|
| 734 | | - ret = -ENODEV; |
|---|
| 735 | | - goto out; |
|---|
| 736 | | - } |
|---|
| 737 | | - |
|---|
| 738 | | - size = ppc_md.nvram_size(); |
|---|
| 739 | | - if (size < 0) { |
|---|
| 740 | | - ret = size; |
|---|
| 741 | | - goto out; |
|---|
| 742 | | - } |
|---|
| 743 | | - |
|---|
| 744 | | - if (*ppos >= size) { |
|---|
| 745 | | - ret = 0; |
|---|
| 746 | | - goto out; |
|---|
| 747 | | - } |
|---|
| 748 | | - |
|---|
| 749 | | - count = min_t(size_t, count, size - *ppos); |
|---|
| 750 | | - count = min(count, PAGE_SIZE); |
|---|
| 751 | | - |
|---|
| 752 | | - tmp = kmalloc(count, GFP_KERNEL); |
|---|
| 753 | | - if (!tmp) { |
|---|
| 754 | | - ret = -ENOMEM; |
|---|
| 755 | | - goto out; |
|---|
| 756 | | - } |
|---|
| 757 | | - |
|---|
| 758 | | - ret = ppc_md.nvram_read(tmp, count, ppos); |
|---|
| 759 | | - if (ret <= 0) |
|---|
| 760 | | - goto out; |
|---|
| 761 | | - |
|---|
| 762 | | - if (copy_to_user(buf, tmp, ret)) |
|---|
| 763 | | - ret = -EFAULT; |
|---|
| 764 | | - |
|---|
| 765 | | -out: |
|---|
| 766 | | - kfree(tmp); |
|---|
| 767 | | - return ret; |
|---|
| 768 | | - |
|---|
| 769 | | -} |
|---|
| 770 | | - |
|---|
| 771 | | -static ssize_t dev_nvram_write(struct file *file, const char __user *buf, |
|---|
| 772 | | - size_t count, loff_t *ppos) |
|---|
| 773 | | -{ |
|---|
| 774 | | - ssize_t ret; |
|---|
| 775 | | - char *tmp = NULL; |
|---|
| 776 | | - ssize_t size; |
|---|
| 777 | | - |
|---|
| 778 | | - ret = -ENODEV; |
|---|
| 779 | | - if (!ppc_md.nvram_size) |
|---|
| 780 | | - goto out; |
|---|
| 781 | | - |
|---|
| 782 | | - ret = 0; |
|---|
| 783 | | - size = ppc_md.nvram_size(); |
|---|
| 784 | | - if (*ppos >= size || size < 0) |
|---|
| 785 | | - goto out; |
|---|
| 786 | | - |
|---|
| 787 | | - count = min_t(size_t, count, size - *ppos); |
|---|
| 788 | | - count = min(count, PAGE_SIZE); |
|---|
| 789 | | - |
|---|
| 790 | | - tmp = memdup_user(buf, count); |
|---|
| 791 | | - if (IS_ERR(tmp)) { |
|---|
| 792 | | - ret = PTR_ERR(tmp); |
|---|
| 793 | | - goto out; |
|---|
| 794 | | - } |
|---|
| 795 | | - |
|---|
| 796 | | - ret = ppc_md.nvram_write(tmp, count, ppos); |
|---|
| 797 | | - |
|---|
| 798 | | - kfree(tmp); |
|---|
| 799 | | -out: |
|---|
| 800 | | - return ret; |
|---|
| 801 | | -} |
|---|
| 802 | | - |
|---|
| 803 | | -static long dev_nvram_ioctl(struct file *file, unsigned int cmd, |
|---|
| 804 | | - unsigned long arg) |
|---|
| 805 | | -{ |
|---|
| 806 | | - switch(cmd) { |
|---|
| 807 | | -#ifdef CONFIG_PPC_PMAC |
|---|
| 808 | | - case OBSOLETE_PMAC_NVRAM_GET_OFFSET: |
|---|
| 809 | | - printk(KERN_WARNING "nvram: Using obsolete PMAC_NVRAM_GET_OFFSET ioctl\n"); |
|---|
| 810 | | - case IOC_NVRAM_GET_OFFSET: { |
|---|
| 811 | | - int part, offset; |
|---|
| 812 | | - |
|---|
| 813 | | - if (!machine_is(powermac)) |
|---|
| 814 | | - return -EINVAL; |
|---|
| 815 | | - if (copy_from_user(&part, (void __user*)arg, sizeof(part)) != 0) |
|---|
| 816 | | - return -EFAULT; |
|---|
| 817 | | - if (part < pmac_nvram_OF || part > pmac_nvram_NR) |
|---|
| 818 | | - return -EINVAL; |
|---|
| 819 | | - offset = pmac_get_partition(part); |
|---|
| 820 | | - if (offset < 0) |
|---|
| 821 | | - return offset; |
|---|
| 822 | | - if (copy_to_user((void __user*)arg, &offset, sizeof(offset)) != 0) |
|---|
| 823 | | - return -EFAULT; |
|---|
| 824 | | - return 0; |
|---|
| 825 | | - } |
|---|
| 826 | | -#endif /* CONFIG_PPC_PMAC */ |
|---|
| 827 | | - default: |
|---|
| 828 | | - return -EINVAL; |
|---|
| 829 | | - } |
|---|
| 830 | | -} |
|---|
| 831 | | - |
|---|
| 832 | | -static const struct file_operations nvram_fops = { |
|---|
| 833 | | - .owner = THIS_MODULE, |
|---|
| 834 | | - .llseek = dev_nvram_llseek, |
|---|
| 835 | | - .read = dev_nvram_read, |
|---|
| 836 | | - .write = dev_nvram_write, |
|---|
| 837 | | - .unlocked_ioctl = dev_nvram_ioctl, |
|---|
| 838 | | -}; |
|---|
| 839 | | - |
|---|
| 840 | | -static struct miscdevice nvram_dev = { |
|---|
| 841 | | - NVRAM_MINOR, |
|---|
| 842 | | - "nvram", |
|---|
| 843 | | - &nvram_fops |
|---|
| 844 | | -}; |
|---|
| 845 | | - |
|---|
| 846 | 704 | |
|---|
| 847 | 705 | #ifdef DEBUG_NVRAM |
|---|
| 848 | 706 | static void __init nvram_print_partitions(char * label) |
|---|
| .. | .. |
|---|
| 991 | 849 | long size = 0; |
|---|
| 992 | 850 | int rc; |
|---|
| 993 | 851 | |
|---|
| 852 | + BUILD_BUG_ON(NVRAM_BLOCK_LEN != 16); |
|---|
| 853 | + |
|---|
| 994 | 854 | /* Convert sizes from bytes to blocks */ |
|---|
| 995 | | - req_size = _ALIGN_UP(req_size, NVRAM_BLOCK_LEN) / NVRAM_BLOCK_LEN; |
|---|
| 996 | | - min_size = _ALIGN_UP(min_size, NVRAM_BLOCK_LEN) / NVRAM_BLOCK_LEN; |
|---|
| 855 | + req_size = ALIGN(req_size, NVRAM_BLOCK_LEN) / NVRAM_BLOCK_LEN; |
|---|
| 856 | + min_size = ALIGN(min_size, NVRAM_BLOCK_LEN) / NVRAM_BLOCK_LEN; |
|---|
| 997 | 857 | |
|---|
| 998 | 858 | /* If no minimum size specified, make it the same as the |
|---|
| 999 | 859 | * requested size |
|---|
| .. | .. |
|---|
| 1191 | 1051 | kfree(header); |
|---|
| 1192 | 1052 | return err; |
|---|
| 1193 | 1053 | } |
|---|
| 1194 | | - |
|---|
| 1195 | | -static int __init nvram_init(void) |
|---|
| 1196 | | -{ |
|---|
| 1197 | | - int rc; |
|---|
| 1198 | | - |
|---|
| 1199 | | - BUILD_BUG_ON(NVRAM_BLOCK_LEN != 16); |
|---|
| 1200 | | - |
|---|
| 1201 | | - if (ppc_md.nvram_size == NULL || ppc_md.nvram_size() <= 0) |
|---|
| 1202 | | - return -ENODEV; |
|---|
| 1203 | | - |
|---|
| 1204 | | - rc = misc_register(&nvram_dev); |
|---|
| 1205 | | - if (rc != 0) { |
|---|
| 1206 | | - printk(KERN_ERR "nvram_init: failed to register device\n"); |
|---|
| 1207 | | - return rc; |
|---|
| 1208 | | - } |
|---|
| 1209 | | - |
|---|
| 1210 | | - return rc; |
|---|
| 1211 | | -} |
|---|
| 1212 | | -device_initcall(nvram_init); |
|---|