diff options
-rw-r--r-- | arch/parisc/kernel/setup.c | 5 | ||||
-rw-r--r-- | drivers/parisc/pdc_stable.c | 219 |
2 files changed, 210 insertions, 14 deletions
diff --git a/arch/parisc/kernel/setup.c b/arch/parisc/kernel/setup.c index 4a36ec3f6ac1..8471486a7565 100644 --- a/arch/parisc/kernel/setup.c +++ b/arch/parisc/kernel/setup.c | |||
@@ -303,6 +303,8 @@ extern void eisa_init(void); | |||
303 | 303 | ||
304 | static int __init parisc_init(void) | 304 | static int __init parisc_init(void) |
305 | { | 305 | { |
306 | u32 osid = (0x0006 << 16); | ||
307 | |||
306 | parisc_proc_mkdir(); | 308 | parisc_proc_mkdir(); |
307 | parisc_init_resources(); | 309 | parisc_init_resources(); |
308 | do_device_inventory(); /* probe for hardware */ | 310 | do_device_inventory(); /* probe for hardware */ |
@@ -311,6 +313,9 @@ static int __init parisc_init(void) | |||
311 | 313 | ||
312 | /* set up a new led state on systems shipped LED State panel */ | 314 | /* set up a new led state on systems shipped LED State panel */ |
313 | pdc_chassis_send_status(PDC_CHASSIS_DIRECT_BSTART); | 315 | pdc_chassis_send_status(PDC_CHASSIS_DIRECT_BSTART); |
316 | |||
317 | /* tell PDC we're Linux. Nevermind failure. */ | ||
318 | pdc_stable_write(0x40, &osid, sizeof(osid)); | ||
314 | 319 | ||
315 | processor_init(); | 320 | processor_init(); |
316 | printk(KERN_INFO "CPU(s): %d x %s at %d.%06d MHz\n", | 321 | printk(KERN_INFO "CPU(s): %d x %s at %d.%06d MHz\n", |
diff --git a/drivers/parisc/pdc_stable.c b/drivers/parisc/pdc_stable.c index bbeabe3fc4c6..4b991d50e578 100644 --- a/drivers/parisc/pdc_stable.c +++ b/drivers/parisc/pdc_stable.c | |||
@@ -28,8 +28,15 @@ | |||
28 | * following code can deal with just 96 bytes of Stable Storage, and all | 28 | * following code can deal with just 96 bytes of Stable Storage, and all |
29 | * sizes between 96 and 192 bytes (provided they are multiple of struct | 29 | * sizes between 96 and 192 bytes (provided they are multiple of struct |
30 | * device_path size, eg: 128, 160 and 192) to provide full information. | 30 | * device_path size, eg: 128, 160 and 192) to provide full information. |
31 | * The code makes no use of data above 192 bytes. One last word: there's one | 31 | * One last word: there's one path we can always count on: the primary path. |
32 | * path we can always count on: the primary path. | 32 | * Anything above 224 bytes is used for 'osdep2' OS-dependent storage area. |
33 | * | ||
34 | * The first OS-dependent area should always be available. Obviously, this is | ||
35 | * not true for the other one. Also bear in mind that reading/writing from/to | ||
36 | * osdep2 is much more expensive than from/to osdep1. | ||
37 | * NOTE: We do not handle the 2 bytes OS-dep area at 0x5D, nor the first | ||
38 | * 2 bytes of storage available right after OSID. That's a total of 4 bytes | ||
39 | * sacrificed: -ETOOLAZY :P | ||
33 | * | 40 | * |
34 | * The current policy wrt file permissions is: | 41 | * The current policy wrt file permissions is: |
35 | * - write: root only | 42 | * - write: root only |
@@ -64,15 +71,18 @@ | |||
64 | #include <asm/uaccess.h> | 71 | #include <asm/uaccess.h> |
65 | #include <asm/hardware.h> | 72 | #include <asm/hardware.h> |
66 | 73 | ||
67 | #define PDCS_VERSION "0.22" | 74 | #define PDCS_VERSION "0.30" |
68 | #define PDCS_PREFIX "PDC Stable Storage" | 75 | #define PDCS_PREFIX "PDC Stable Storage" |
69 | 76 | ||
70 | #define PDCS_ADDR_PPRI 0x00 | 77 | #define PDCS_ADDR_PPRI 0x00 |
71 | #define PDCS_ADDR_OSID 0x40 | 78 | #define PDCS_ADDR_OSID 0x40 |
79 | #define PDCS_ADDR_OSD1 0x48 | ||
80 | #define PDCS_ADDR_DIAG 0x58 | ||
72 | #define PDCS_ADDR_FSIZ 0x5C | 81 | #define PDCS_ADDR_FSIZ 0x5C |
73 | #define PDCS_ADDR_PCON 0x60 | 82 | #define PDCS_ADDR_PCON 0x60 |
74 | #define PDCS_ADDR_PALT 0x80 | 83 | #define PDCS_ADDR_PALT 0x80 |
75 | #define PDCS_ADDR_PKBD 0xA0 | 84 | #define PDCS_ADDR_PKBD 0xA0 |
85 | #define PDCS_ADDR_OSD2 0xE0 | ||
76 | 86 | ||
77 | MODULE_AUTHOR("Thibaut VARENE <varenet@parisc-linux.org>"); | 87 | MODULE_AUTHOR("Thibaut VARENE <varenet@parisc-linux.org>"); |
78 | MODULE_DESCRIPTION("sysfs interface to HP PDC Stable Storage data"); | 88 | MODULE_DESCRIPTION("sysfs interface to HP PDC Stable Storage data"); |
@@ -82,6 +92,9 @@ MODULE_VERSION(PDCS_VERSION); | |||
82 | /* holds Stable Storage size. Initialized once and for all, no lock needed */ | 92 | /* holds Stable Storage size. Initialized once and for all, no lock needed */ |
83 | static unsigned long pdcs_size __read_mostly; | 93 | static unsigned long pdcs_size __read_mostly; |
84 | 94 | ||
95 | /* holds OS ID. Initialized once and for all, hopefully to 0x0006 */ | ||
96 | static u16 pdcs_osid __read_mostly; | ||
97 | |||
85 | /* This struct defines what we need to deal with a parisc pdc path entry */ | 98 | /* This struct defines what we need to deal with a parisc pdc path entry */ |
86 | struct pdcspath_entry { | 99 | struct pdcspath_entry { |
87 | rwlock_t rw_lock; /* to protect path entry access */ | 100 | rwlock_t rw_lock; /* to protect path entry access */ |
@@ -609,27 +622,74 @@ static ssize_t | |||
609 | pdcs_osid_read(struct subsystem *entry, char *buf) | 622 | pdcs_osid_read(struct subsystem *entry, char *buf) |
610 | { | 623 | { |
611 | char *out = buf; | 624 | char *out = buf; |
612 | __u32 result; | ||
613 | char *tmpstr = NULL; | 625 | char *tmpstr = NULL; |
614 | 626 | ||
615 | if (!entry || !buf) | 627 | if (!entry || !buf) |
616 | return -EINVAL; | 628 | return -EINVAL; |
617 | 629 | ||
618 | /* get OSID */ | 630 | switch (pdcs_osid) { |
619 | if (pdc_stable_read(PDCS_ADDR_OSID, &result, sizeof(result)) != PDC_OK) | ||
620 | return -EIO; | ||
621 | |||
622 | /* the actual result is 16 bits away */ | ||
623 | switch (result >> 16) { | ||
624 | case 0x0000: tmpstr = "No OS-dependent data"; break; | 631 | case 0x0000: tmpstr = "No OS-dependent data"; break; |
625 | case 0x0001: tmpstr = "HP-UX dependent data"; break; | 632 | case 0x0001: tmpstr = "HP-UX dependent data"; break; |
626 | case 0x0002: tmpstr = "MPE-iX dependent data"; break; | 633 | case 0x0002: tmpstr = "MPE-iX dependent data"; break; |
627 | case 0x0003: tmpstr = "OSF dependent data"; break; | 634 | case 0x0003: tmpstr = "OSF dependent data"; break; |
628 | case 0x0004: tmpstr = "HP-RT dependent data"; break; | 635 | case 0x0004: tmpstr = "HP-RT dependent data"; break; |
629 | case 0x0005: tmpstr = "Novell Netware dependent data"; break; | 636 | case 0x0005: tmpstr = "Novell Netware dependent data"; break; |
637 | case 0x0006: tmpstr = "Linux dependent data"; break; | ||
630 | default: tmpstr = "Unknown"; break; | 638 | default: tmpstr = "Unknown"; break; |
631 | } | 639 | } |
632 | out += sprintf(out, "%s (0x%.4x)\n", tmpstr, (result >> 16)); | 640 | out += sprintf(out, "%s (0x%.4x)\n", tmpstr, pdcs_osid); |
641 | |||
642 | return out - buf; | ||
643 | } | ||
644 | |||
645 | /** | ||
646 | * pdcs_osdep1_read - Stable Storage OS-Dependent data area 1 output. | ||
647 | * @entry: An allocated and populated subsytem struct. We don't use it tho. | ||
648 | * @buf: The output buffer to write to. | ||
649 | * | ||
650 | * This can hold 16 bytes of OS-Dependent data. | ||
651 | */ | ||
652 | static ssize_t | ||
653 | pdcs_osdep1_read(struct subsystem *entry, char *buf) | ||
654 | { | ||
655 | char *out = buf; | ||
656 | u32 result[4]; | ||
657 | |||
658 | if (!entry || !buf) | ||
659 | return -EINVAL; | ||
660 | |||
661 | if (pdc_stable_read(PDCS_ADDR_OSD1, &result, sizeof(result)) != PDC_OK) | ||
662 | return -EIO; | ||
663 | |||
664 | out += sprintf(out, "0x%.8x\n", result[0]); | ||
665 | out += sprintf(out, "0x%.8x\n", result[1]); | ||
666 | out += sprintf(out, "0x%.8x\n", result[2]); | ||
667 | out += sprintf(out, "0x%.8x\n", result[3]); | ||
668 | |||
669 | return out - buf; | ||
670 | } | ||
671 | |||
672 | /** | ||
673 | * pdcs_diagnostic_read - Stable Storage Diagnostic register output. | ||
674 | * @entry: An allocated and populated subsytem struct. We don't use it tho. | ||
675 | * @buf: The output buffer to write to. | ||
676 | * | ||
677 | * I have NFC how to interpret the content of that register ;-). | ||
678 | */ | ||
679 | static ssize_t | ||
680 | pdcs_diagnostic_read(struct subsystem *entry, char *buf) | ||
681 | { | ||
682 | char *out = buf; | ||
683 | u32 result; | ||
684 | |||
685 | if (!entry || !buf) | ||
686 | return -EINVAL; | ||
687 | |||
688 | /* get diagnostic */ | ||
689 | if (pdc_stable_read(PDCS_ADDR_DIAG, &result, sizeof(result)) != PDC_OK) | ||
690 | return -EIO; | ||
691 | |||
692 | out += sprintf(out, "0x%.4x\n", (result >> 16)); | ||
633 | 693 | ||
634 | return out - buf; | 694 | return out - buf; |
635 | } | 695 | } |
@@ -645,7 +705,7 @@ static ssize_t | |||
645 | pdcs_fastsize_read(struct subsystem *entry, char *buf) | 705 | pdcs_fastsize_read(struct subsystem *entry, char *buf) |
646 | { | 706 | { |
647 | char *out = buf; | 707 | char *out = buf; |
648 | __u32 result; | 708 | u32 result; |
649 | 709 | ||
650 | if (!entry || !buf) | 710 | if (!entry || !buf) |
651 | return -EINVAL; | 711 | return -EINVAL; |
@@ -664,6 +724,39 @@ pdcs_fastsize_read(struct subsystem *entry, char *buf) | |||
664 | } | 724 | } |
665 | 725 | ||
666 | /** | 726 | /** |
727 | * pdcs_osdep2_read - Stable Storage OS-Dependent data area 2 output. | ||
728 | * @entry: An allocated and populated subsytem struct. We don't use it tho. | ||
729 | * @buf: The output buffer to write to. | ||
730 | * | ||
731 | * This can hold pdcs_size - 224 bytes of OS-Dependent data, when available. | ||
732 | */ | ||
733 | static ssize_t | ||
734 | pdcs_osdep2_read(struct subsystem *entry, char *buf) | ||
735 | { | ||
736 | char *out = buf; | ||
737 | unsigned long size; | ||
738 | unsigned short i; | ||
739 | u32 result; | ||
740 | |||
741 | if (unlikely(pdcs_size <= 224)) | ||
742 | return -ENODATA; | ||
743 | |||
744 | size = pdcs_size - 224; | ||
745 | |||
746 | if (!entry || !buf) | ||
747 | return -EINVAL; | ||
748 | |||
749 | for (i=0; i<size; i+=4) { | ||
750 | if (unlikely(pdc_stable_read(PDCS_ADDR_OSD2 + i, &result, | ||
751 | sizeof(result)) != PDC_OK)) | ||
752 | return -EIO; | ||
753 | out += sprintf(out, "0x%.8x\n", result); | ||
754 | } | ||
755 | |||
756 | return out - buf; | ||
757 | } | ||
758 | |||
759 | /** | ||
667 | * pdcs_auto_write - This function handles autoboot/search flag modifying. | 760 | * pdcs_auto_write - This function handles autoboot/search flag modifying. |
668 | * @entry: An allocated and populated subsytem struct. We don't use it tho. | 761 | * @entry: An allocated and populated subsytem struct. We don't use it tho. |
669 | * @buf: The input buffer to read from. | 762 | * @buf: The input buffer to read from. |
@@ -770,13 +863,100 @@ pdcs_autosearch_write(struct subsystem *entry, const char *buf, size_t count) | |||
770 | return pdcs_auto_write(entry, buf, count, PF_AUTOSEARCH); | 863 | return pdcs_auto_write(entry, buf, count, PF_AUTOSEARCH); |
771 | } | 864 | } |
772 | 865 | ||
866 | /** | ||
867 | * pdcs_osdep1_write - Stable Storage OS-Dependent data area 1 input. | ||
868 | * @entry: An allocated and populated subsytem struct. We don't use it tho. | ||
869 | * @buf: The input buffer to read from. | ||
870 | * @count: The number of bytes to be read. | ||
871 | * | ||
872 | * This can store 16 bytes of OS-Dependent data. We use a byte-by-byte | ||
873 | * write approach. It's up to userspace to deal with it when constructing | ||
874 | * its input buffer. | ||
875 | */ | ||
876 | static ssize_t | ||
877 | pdcs_osdep1_write(struct subsystem *entry, const char *buf, size_t count) | ||
878 | { | ||
879 | u8 in[16]; | ||
880 | |||
881 | if (!capable(CAP_SYS_ADMIN)) | ||
882 | return -EACCES; | ||
883 | |||
884 | if (!entry || !buf || !count) | ||
885 | return -EINVAL; | ||
886 | |||
887 | if (unlikely(pdcs_osid != 0x0006)) | ||
888 | return -EPERM; | ||
889 | |||
890 | if (count > 16) | ||
891 | return -EMSGSIZE; | ||
892 | |||
893 | /* We'll use a local copy of buf */ | ||
894 | memset(in, 0, 16); | ||
895 | memcpy(in, buf, count); | ||
896 | |||
897 | if (pdc_stable_write(PDCS_ADDR_OSD1, &in, sizeof(in)) != PDC_OK) | ||
898 | return -EIO; | ||
899 | |||
900 | return count; | ||
901 | } | ||
902 | |||
903 | /** | ||
904 | * pdcs_osdep2_write - Stable Storage OS-Dependent data area 2 input. | ||
905 | * @entry: An allocated and populated subsytem struct. We don't use it tho. | ||
906 | * @buf: The input buffer to read from. | ||
907 | * @count: The number of bytes to be read. | ||
908 | * | ||
909 | * This can store pdcs_size - 224 bytes of OS-Dependent data. We use a | ||
910 | * byte-by-byte write approach. It's up to userspace to deal with it when | ||
911 | * constructing its input buffer. | ||
912 | */ | ||
913 | static ssize_t | ||
914 | pdcs_osdep2_write(struct subsystem *entry, const char *buf, size_t count) | ||
915 | { | ||
916 | unsigned long size; | ||
917 | unsigned short i; | ||
918 | u8 in[4]; | ||
919 | |||
920 | if (!capable(CAP_SYS_ADMIN)) | ||
921 | return -EACCES; | ||
922 | |||
923 | if (!entry || !buf || !count) | ||
924 | return -EINVAL; | ||
925 | |||
926 | if (unlikely(pdcs_size <= 224)) | ||
927 | return -ENOSYS; | ||
928 | |||
929 | if (unlikely(pdcs_osid != 0x0006)) | ||
930 | return -EPERM; | ||
931 | |||
932 | size = pdcs_size - 224; | ||
933 | |||
934 | if (count > size) | ||
935 | return -EMSGSIZE; | ||
936 | |||
937 | /* We'll use a local copy of buf */ | ||
938 | |||
939 | for (i=0; i<count; i+=4) { | ||
940 | memset(in, 0, 4); | ||
941 | memcpy(in, buf+i, (count-i < 4) ? count-i : 4); | ||
942 | if (unlikely(pdc_stable_write(PDCS_ADDR_OSD2 + i, &in, | ||
943 | sizeof(in)) != PDC_OK)) | ||
944 | return -EIO; | ||
945 | } | ||
946 | |||
947 | return count; | ||
948 | } | ||
949 | |||
773 | /* The remaining attributes. */ | 950 | /* The remaining attributes. */ |
774 | static PDCS_ATTR(size, 0444, pdcs_size_read, NULL); | 951 | static PDCS_ATTR(size, 0444, pdcs_size_read, NULL); |
775 | static PDCS_ATTR(autoboot, 0644, pdcs_autoboot_read, pdcs_autoboot_write); | 952 | static PDCS_ATTR(autoboot, 0644, pdcs_autoboot_read, pdcs_autoboot_write); |
776 | static PDCS_ATTR(autosearch, 0644, pdcs_autosearch_read, pdcs_autosearch_write); | 953 | static PDCS_ATTR(autosearch, 0644, pdcs_autosearch_read, pdcs_autosearch_write); |
777 | static PDCS_ATTR(timer, 0444, pdcs_timer_read, NULL); | 954 | static PDCS_ATTR(timer, 0444, pdcs_timer_read, NULL); |
778 | static PDCS_ATTR(osid, 0400, pdcs_osid_read, NULL); | 955 | static PDCS_ATTR(osid, 0444, pdcs_osid_read, NULL); |
956 | static PDCS_ATTR(osdep1, 0600, pdcs_osdep1_read, pdcs_osdep1_write); | ||
957 | static PDCS_ATTR(diagnostic, 0400, pdcs_diagnostic_read, NULL); | ||
779 | static PDCS_ATTR(fastsize, 0400, pdcs_fastsize_read, NULL); | 958 | static PDCS_ATTR(fastsize, 0400, pdcs_fastsize_read, NULL); |
959 | static PDCS_ATTR(osdep2, 0600, pdcs_osdep2_read, pdcs_osdep2_write); | ||
780 | 960 | ||
781 | static struct subsys_attribute *pdcs_subsys_attrs[] = { | 961 | static struct subsys_attribute *pdcs_subsys_attrs[] = { |
782 | &pdcs_attr_size, | 962 | &pdcs_attr_size, |
@@ -784,7 +964,10 @@ static struct subsys_attribute *pdcs_subsys_attrs[] = { | |||
784 | &pdcs_attr_autosearch, | 964 | &pdcs_attr_autosearch, |
785 | &pdcs_attr_timer, | 965 | &pdcs_attr_timer, |
786 | &pdcs_attr_osid, | 966 | &pdcs_attr_osid, |
967 | &pdcs_attr_osdep1, | ||
968 | &pdcs_attr_diagnostic, | ||
787 | &pdcs_attr_fastsize, | 969 | &pdcs_attr_fastsize, |
970 | &pdcs_attr_osdep2, | ||
788 | NULL, | 971 | NULL, |
789 | }; | 972 | }; |
790 | 973 | ||
@@ -865,6 +1048,7 @@ pdc_stable_init(void) | |||
865 | { | 1048 | { |
866 | struct subsys_attribute *attr; | 1049 | struct subsys_attribute *attr; |
867 | int i, rc = 0, error = 0; | 1050 | int i, rc = 0, error = 0; |
1051 | u32 result; | ||
868 | 1052 | ||
869 | /* find the size of the stable storage */ | 1053 | /* find the size of the stable storage */ |
870 | if (pdc_stable_get_size(&pdcs_size) != PDC_OK) | 1054 | if (pdc_stable_get_size(&pdcs_size) != PDC_OK) |
@@ -876,6 +1060,13 @@ pdc_stable_init(void) | |||
876 | 1060 | ||
877 | printk(KERN_INFO PDCS_PREFIX " facility v%s\n", PDCS_VERSION); | 1061 | printk(KERN_INFO PDCS_PREFIX " facility v%s\n", PDCS_VERSION); |
878 | 1062 | ||
1063 | /* get OSID */ | ||
1064 | if (pdc_stable_read(PDCS_ADDR_OSID, &result, sizeof(result)) != PDC_OK) | ||
1065 | return -EIO; | ||
1066 | |||
1067 | /* the actual result is 16 bits away */ | ||
1068 | pdcs_osid = (u16)(result >> 16); | ||
1069 | |||
879 | /* For now we'll register the stable subsys within this driver */ | 1070 | /* For now we'll register the stable subsys within this driver */ |
880 | if ((rc = firmware_register(&stable_subsys))) | 1071 | if ((rc = firmware_register(&stable_subsys))) |
881 | goto fail_firmreg; | 1072 | goto fail_firmreg; |
@@ -887,7 +1078,7 @@ pdc_stable_init(void) | |||
887 | 1078 | ||
888 | /* register the paths subsys as a subsystem of stable subsys */ | 1079 | /* register the paths subsys as a subsystem of stable subsys */ |
889 | kset_set_kset_s(&paths_subsys, stable_subsys); | 1080 | kset_set_kset_s(&paths_subsys, stable_subsys); |
890 | if ((rc= subsystem_register(&paths_subsys))) | 1081 | if ((rc = subsystem_register(&paths_subsys))) |
891 | goto fail_subsysreg; | 1082 | goto fail_subsysreg; |
892 | 1083 | ||
893 | /* now we create all "files" for the paths subsys */ | 1084 | /* now we create all "files" for the paths subsys */ |