diff options
Diffstat (limited to 'arch/s390')
-rw-r--r-- | arch/s390/kernel/head.S | 72 | ||||
-rw-r--r-- | arch/s390/kernel/head64.S | 66 | ||||
-rw-r--r-- | arch/s390/kernel/setup.c | 186 |
3 files changed, 317 insertions, 7 deletions
diff --git a/arch/s390/kernel/head.S b/arch/s390/kernel/head.S index 55654b6e16dc..039354d72348 100644 --- a/arch/s390/kernel/head.S +++ b/arch/s390/kernel/head.S | |||
@@ -485,7 +485,9 @@ start: | |||
485 | # | 485 | # |
486 | .org 0x10000 | 486 | .org 0x10000 |
487 | startup:basr %r13,0 # get base | 487 | startup:basr %r13,0 # get base |
488 | .LPG1: lctl %c0,%c15,.Lctl-.LPG1(%r13) # load control registers | 488 | .LPG1: l %r1, .Lget_ipl_device_addr-.LPG1(%r13) |
489 | basr %r14, %r1 | ||
490 | lctl %c0,%c15,.Lctl-.LPG1(%r13) # load control registers | ||
489 | la %r12,_pstart-.LPG1(%r13) # pointer to parameter area | 491 | la %r12,_pstart-.LPG1(%r13) # pointer to parameter area |
490 | # move IPL device to lowcore | 492 | # move IPL device to lowcore |
491 | mvc __LC_IPLDEV(4),IPL_DEVICE-PARMAREA(%r12) | 493 | mvc __LC_IPLDEV(4),IPL_DEVICE-PARMAREA(%r12) |
@@ -560,6 +562,9 @@ startup:basr %r13,0 # get base | |||
560 | mr %r2,%r1 # mem size in bytes in %r3 | 562 | mr %r2,%r1 # mem size in bytes in %r3 |
561 | b .Lfchunk-.LPG1(%r13) | 563 | b .Lfchunk-.LPG1(%r13) |
562 | 564 | ||
565 | .align 4 | ||
566 | .Lget_ipl_device_addr: | ||
567 | .long .Lget_ipl_device | ||
563 | .Lpmask: | 568 | .Lpmask: |
564 | .byte 0 | 569 | .byte 0 |
565 | .align 8 | 570 | .align 8 |
@@ -755,6 +760,63 @@ _pstart: | |||
755 | .global _pend | 760 | .global _pend |
756 | _pend: | 761 | _pend: |
757 | 762 | ||
763 | .Lget_ipl_device: | ||
764 | basr %r12,0 | ||
765 | .LPG2: l %r1,0xb8 # get sid | ||
766 | sll %r1,15 # test if subchannel is enabled | ||
767 | srl %r1,31 | ||
768 | ltr %r1,%r1 | ||
769 | bz 0(%r14) # subchannel disabled | ||
770 | l %r1,0xb8 | ||
771 | la %r5,.Lipl_schib-.LPG2(%r12) | ||
772 | stsch 0(%r5) # get schib of subchannel | ||
773 | bnz 0(%r14) # schib not available | ||
774 | tm 5(%r5),0x01 # devno valid? | ||
775 | bno 0(%r14) | ||
776 | la %r6,ipl_parameter_flags-.LPG2(%r12) | ||
777 | oi 3(%r6),0x01 # set flag | ||
778 | la %r2,ipl_devno-.LPG2(%r12) | ||
779 | mvc 0(2,%r2),6(%r5) # store devno | ||
780 | tm 4(%r5),0x80 # qdio capable device? | ||
781 | bno 0(%r14) | ||
782 | oi 3(%r6),0x02 # set flag | ||
783 | |||
784 | # copy ipl parameters | ||
785 | |||
786 | lhi %r0,4096 | ||
787 | l %r2,20(%r0) # get address of parameter list | ||
788 | lhi %r3,IPL_PARMBLOCK_ORIGIN | ||
789 | st %r3,20(%r0) | ||
790 | lhi %r4,1 | ||
791 | cr %r2,%r3 # start parameters < destination ? | ||
792 | jl 0f | ||
793 | lhi %r1,1 # copy direction is upwards | ||
794 | j 1f | ||
795 | 0: lhi %r1,-1 # copy direction is downwards | ||
796 | ar %r2,%r0 | ||
797 | ar %r3,%r0 | ||
798 | ar %r2,%r1 | ||
799 | ar %r3,%r1 | ||
800 | 1: mvc 0(1,%r3),0(%r2) # finally copy ipl parameters | ||
801 | ar %r3,%r1 | ||
802 | ar %r2,%r1 | ||
803 | sr %r0,%r4 | ||
804 | jne 1b | ||
805 | b 0(%r14) | ||
806 | |||
807 | .align 4 | ||
808 | .Lipl_schib: | ||
809 | .rept 13 | ||
810 | .long 0 | ||
811 | .endr | ||
812 | |||
813 | .globl ipl_parameter_flags | ||
814 | ipl_parameter_flags: | ||
815 | .long 0 | ||
816 | .globl ipl_devno | ||
817 | ipl_devno: | ||
818 | .word 0 | ||
819 | |||
758 | #ifdef CONFIG_SHARED_KERNEL | 820 | #ifdef CONFIG_SHARED_KERNEL |
759 | .org 0x100000 | 821 | .org 0x100000 |
760 | #endif | 822 | #endif |
@@ -764,11 +826,11 @@ _pend: | |||
764 | # | 826 | # |
765 | .globl _stext | 827 | .globl _stext |
766 | _stext: basr %r13,0 # get base | 828 | _stext: basr %r13,0 # get base |
767 | .LPG2: | 829 | .LPG3: |
768 | # | 830 | # |
769 | # Setup stack | 831 | # Setup stack |
770 | # | 832 | # |
771 | l %r15,.Linittu-.LPG2(%r13) | 833 | l %r15,.Linittu-.LPG3(%r13) |
772 | mvc __LC_CURRENT(4),__TI_task(%r15) | 834 | mvc __LC_CURRENT(4),__TI_task(%r15) |
773 | ahi %r15,1<<(PAGE_SHIFT+THREAD_ORDER) # init_task_union + THREAD_SIZE | 835 | ahi %r15,1<<(PAGE_SHIFT+THREAD_ORDER) # init_task_union + THREAD_SIZE |
774 | st %r15,__LC_KERNEL_STACK # set end of kernel stack | 836 | st %r15,__LC_KERNEL_STACK # set end of kernel stack |
@@ -782,8 +844,8 @@ _stext: basr %r13,0 # get base | |||
782 | lctl %c0,%c15,0(%r15) | 844 | lctl %c0,%c15,0(%r15) |
783 | 845 | ||
784 | # | 846 | # |
785 | lam 0,15,.Laregs-.LPG2(%r13) # load access regs needed by uaccess | 847 | lam 0,15,.Laregs-.LPG3(%r13) # load access regs needed by uaccess |
786 | l %r14,.Lstart-.LPG2(%r13) | 848 | l %r14,.Lstart-.LPG3(%r13) |
787 | basr %r14,%r14 # call start_kernel | 849 | basr %r14,%r14 # call start_kernel |
788 | # | 850 | # |
789 | # We returned from start_kernel ?!? PANIK | 851 | # We returned from start_kernel ?!? PANIK |
diff --git a/arch/s390/kernel/head64.S b/arch/s390/kernel/head64.S index c9ff0404c875..193aafa72f54 100644 --- a/arch/s390/kernel/head64.S +++ b/arch/s390/kernel/head64.S | |||
@@ -484,6 +484,8 @@ start: | |||
484 | startup:basr %r13,0 # get base | 484 | startup:basr %r13,0 # get base |
485 | .LPG1: sll %r13,1 # remove high order bit | 485 | .LPG1: sll %r13,1 # remove high order bit |
486 | srl %r13,1 | 486 | srl %r13,1 |
487 | l %r1,.Lget_ipl_device_addr-.LPG1(%r13) | ||
488 | basr %r14,%r1 | ||
487 | lhi %r1,1 # mode 1 = esame | 489 | lhi %r1,1 # mode 1 = esame |
488 | slr %r0,%r0 # set cpuid to zero | 490 | slr %r0,%r0 # set cpuid to zero |
489 | sigp %r1,%r0,0x12 # switch to esame mode | 491 | sigp %r1,%r0,0x12 # switch to esame mode |
@@ -556,6 +558,9 @@ startup:basr %r13,0 # get base | |||
556 | mlgr %r2,%r1 # mem size in bytes in %r3 | 558 | mlgr %r2,%r1 # mem size in bytes in %r3 |
557 | b .Lfchunk-.LPG1(%r13) | 559 | b .Lfchunk-.LPG1(%r13) |
558 | 560 | ||
561 | .align 4 | ||
562 | .Lget_ipl_device_addr: | ||
563 | .long .Lget_ipl_device | ||
559 | .Lpmask: | 564 | .Lpmask: |
560 | .byte 0 | 565 | .byte 0 |
561 | .align 8 | 566 | .align 8 |
@@ -746,6 +751,63 @@ _pstart: | |||
746 | .global _pend | 751 | .global _pend |
747 | _pend: | 752 | _pend: |
748 | 753 | ||
754 | .Lget_ipl_device: | ||
755 | basr %r12,0 | ||
756 | .LPG2: l %r1,0xb8 # get sid | ||
757 | sll %r1,15 # test if subchannel is enabled | ||
758 | srl %r1,31 | ||
759 | ltr %r1,%r1 | ||
760 | bz 0(%r14) # subchannel disabled | ||
761 | l %r1,0xb8 | ||
762 | la %r5,.Lipl_schib-.LPG2(%r12) | ||
763 | stsch 0(%r5) # get schib of subchannel | ||
764 | bnz 0(%r14) # schib not available | ||
765 | tm 5(%r5),0x01 # devno valid? | ||
766 | bno 0(%r14) | ||
767 | la %r6,ipl_parameter_flags-.LPG2(%r12) | ||
768 | oi 3(%r6),0x01 # set flag | ||
769 | la %r2,ipl_devno-.LPG2(%r12) | ||
770 | mvc 0(2,%r2),6(%r5) # store devno | ||
771 | tm 4(%r5),0x80 # qdio capable device? | ||
772 | bno 0(%r14) | ||
773 | oi 3(%r6),0x02 # set flag | ||
774 | |||
775 | # copy ipl parameters | ||
776 | |||
777 | lhi %r0,4096 | ||
778 | l %r2,20(%r0) # get address of parameter list | ||
779 | lhi %r3,IPL_PARMBLOCK_ORIGIN | ||
780 | st %r3,20(%r0) | ||
781 | lhi %r4,1 | ||
782 | cr %r2,%r3 # start parameters < destination ? | ||
783 | jl 0f | ||
784 | lhi %r1,1 # copy direction is upwards | ||
785 | j 1f | ||
786 | 0: lhi %r1,-1 # copy direction is downwards | ||
787 | ar %r2,%r0 | ||
788 | ar %r3,%r0 | ||
789 | ar %r2,%r1 | ||
790 | ar %r3,%r1 | ||
791 | 1: mvc 0(1,%r3),0(%r2) # finally copy ipl parameters | ||
792 | ar %r3,%r1 | ||
793 | ar %r2,%r1 | ||
794 | sr %r0,%r4 | ||
795 | jne 1b | ||
796 | b 0(%r14) | ||
797 | |||
798 | .align 4 | ||
799 | .Lipl_schib: | ||
800 | .rept 13 | ||
801 | .long 0 | ||
802 | .endr | ||
803 | |||
804 | .globl ipl_parameter_flags | ||
805 | ipl_parameter_flags: | ||
806 | .long 0 | ||
807 | .globl ipl_devno | ||
808 | ipl_devno: | ||
809 | .word 0 | ||
810 | |||
749 | #ifdef CONFIG_SHARED_KERNEL | 811 | #ifdef CONFIG_SHARED_KERNEL |
750 | .org 0x100000 | 812 | .org 0x100000 |
751 | #endif | 813 | #endif |
@@ -755,7 +817,7 @@ _pend: | |||
755 | # | 817 | # |
756 | .globl _stext | 818 | .globl _stext |
757 | _stext: basr %r13,0 # get base | 819 | _stext: basr %r13,0 # get base |
758 | .LPG2: | 820 | .LPG3: |
759 | # | 821 | # |
760 | # Setup stack | 822 | # Setup stack |
761 | # | 823 | # |
@@ -774,7 +836,7 @@ _stext: basr %r13,0 # get base | |||
774 | lctlg %c0,%c15,0(%r15) | 836 | lctlg %c0,%c15,0(%r15) |
775 | 837 | ||
776 | # | 838 | # |
777 | lam 0,15,.Laregs-.LPG2(%r13) # load access regs needed by uaccess | 839 | lam 0,15,.Laregs-.LPG3(%r13) # load access regs needed by uaccess |
778 | brasl %r14,start_kernel # go to C code | 840 | brasl %r14,start_kernel # go to C code |
779 | # | 841 | # |
780 | # We returned from start_kernel ?!? PANIK | 842 | # We returned from start_kernel ?!? PANIK |
diff --git a/arch/s390/kernel/setup.c b/arch/s390/kernel/setup.c index 5204778b8e5e..31e7b19348b7 100644 --- a/arch/s390/kernel/setup.c +++ b/arch/s390/kernel/setup.c | |||
@@ -36,6 +36,7 @@ | |||
36 | #include <linux/console.h> | 36 | #include <linux/console.h> |
37 | #include <linux/seq_file.h> | 37 | #include <linux/seq_file.h> |
38 | #include <linux/kernel_stat.h> | 38 | #include <linux/kernel_stat.h> |
39 | #include <linux/device.h> | ||
39 | 40 | ||
40 | #include <asm/uaccess.h> | 41 | #include <asm/uaccess.h> |
41 | #include <asm/system.h> | 42 | #include <asm/system.h> |
@@ -685,3 +686,188 @@ struct seq_operations cpuinfo_op = { | |||
685 | .show = show_cpuinfo, | 686 | .show = show_cpuinfo, |
686 | }; | 687 | }; |
687 | 688 | ||
689 | #define DEFINE_IPL_ATTR(_name, _format, _value) \ | ||
690 | static ssize_t ipl_##_name##_show(struct subsystem *subsys, \ | ||
691 | char *page) \ | ||
692 | { \ | ||
693 | return sprintf(page, _format, _value); \ | ||
694 | } \ | ||
695 | static struct subsys_attribute ipl_##_name##_attr = \ | ||
696 | __ATTR(_name, S_IRUGO, ipl_##_name##_show, NULL); | ||
697 | |||
698 | DEFINE_IPL_ATTR(wwpn, "0x%016llx\n", (unsigned long long) | ||
699 | IPL_PARMBLOCK_START->fcp.wwpn); | ||
700 | DEFINE_IPL_ATTR(lun, "0x%016llx\n", (unsigned long long) | ||
701 | IPL_PARMBLOCK_START->fcp.lun); | ||
702 | DEFINE_IPL_ATTR(bootprog, "%lld\n", (unsigned long long) | ||
703 | IPL_PARMBLOCK_START->fcp.bootprog); | ||
704 | DEFINE_IPL_ATTR(br_lba, "%lld\n", (unsigned long long) | ||
705 | IPL_PARMBLOCK_START->fcp.br_lba); | ||
706 | |||
707 | enum ipl_type_type { | ||
708 | ipl_type_unknown, | ||
709 | ipl_type_ccw, | ||
710 | ipl_type_fcp, | ||
711 | }; | ||
712 | |||
713 | static enum ipl_type_type | ||
714 | get_ipl_type(void) | ||
715 | { | ||
716 | struct ipl_parameter_block *ipl = IPL_PARMBLOCK_START; | ||
717 | |||
718 | if (!IPL_DEVNO_VALID) | ||
719 | return ipl_type_unknown; | ||
720 | if (!IPL_PARMBLOCK_VALID) | ||
721 | return ipl_type_ccw; | ||
722 | if (ipl->hdr.header.version > IPL_MAX_SUPPORTED_VERSION) | ||
723 | return ipl_type_unknown; | ||
724 | if (ipl->fcp.pbt != IPL_TYPE_FCP) | ||
725 | return ipl_type_unknown; | ||
726 | return ipl_type_fcp; | ||
727 | } | ||
728 | |||
729 | static ssize_t | ||
730 | ipl_type_show(struct subsystem *subsys, char *page) | ||
731 | { | ||
732 | switch (get_ipl_type()) { | ||
733 | case ipl_type_ccw: | ||
734 | return sprintf(page, "ccw\n"); | ||
735 | case ipl_type_fcp: | ||
736 | return sprintf(page, "fcp\n"); | ||
737 | default: | ||
738 | return sprintf(page, "unknown\n"); | ||
739 | } | ||
740 | } | ||
741 | |||
742 | static struct subsys_attribute ipl_type_attr = __ATTR_RO(ipl_type); | ||
743 | |||
744 | static ssize_t | ||
745 | ipl_device_show(struct subsystem *subsys, char *page) | ||
746 | { | ||
747 | struct ipl_parameter_block *ipl = IPL_PARMBLOCK_START; | ||
748 | |||
749 | switch (get_ipl_type()) { | ||
750 | case ipl_type_ccw: | ||
751 | return sprintf(page, "0.0.%04x\n", ipl_devno); | ||
752 | case ipl_type_fcp: | ||
753 | return sprintf(page, "0.0.%04x\n", ipl->fcp.devno); | ||
754 | default: | ||
755 | return 0; | ||
756 | } | ||
757 | } | ||
758 | |||
759 | static struct subsys_attribute ipl_device_attr = | ||
760 | __ATTR(device, S_IRUGO, ipl_device_show, NULL); | ||
761 | |||
762 | static struct attribute *ipl_fcp_attrs[] = { | ||
763 | &ipl_type_attr.attr, | ||
764 | &ipl_device_attr.attr, | ||
765 | &ipl_wwpn_attr.attr, | ||
766 | &ipl_lun_attr.attr, | ||
767 | &ipl_bootprog_attr.attr, | ||
768 | &ipl_br_lba_attr.attr, | ||
769 | NULL, | ||
770 | }; | ||
771 | |||
772 | static struct attribute_group ipl_fcp_attr_group = { | ||
773 | .attrs = ipl_fcp_attrs, | ||
774 | }; | ||
775 | |||
776 | static struct attribute *ipl_ccw_attrs[] = { | ||
777 | &ipl_type_attr.attr, | ||
778 | &ipl_device_attr.attr, | ||
779 | NULL, | ||
780 | }; | ||
781 | |||
782 | static struct attribute_group ipl_ccw_attr_group = { | ||
783 | .attrs = ipl_ccw_attrs, | ||
784 | }; | ||
785 | |||
786 | static struct attribute *ipl_unknown_attrs[] = { | ||
787 | &ipl_type_attr.attr, | ||
788 | NULL, | ||
789 | }; | ||
790 | |||
791 | static struct attribute_group ipl_unknown_attr_group = { | ||
792 | .attrs = ipl_unknown_attrs, | ||
793 | }; | ||
794 | |||
795 | static ssize_t | ||
796 | ipl_parameter_read(struct kobject *kobj, char *buf, loff_t off, size_t count) | ||
797 | { | ||
798 | unsigned int size = IPL_PARMBLOCK_SIZE; | ||
799 | |||
800 | if (off > size) | ||
801 | return 0; | ||
802 | if (off + count > size) | ||
803 | count = size - off; | ||
804 | |||
805 | memcpy(buf, (void *) IPL_PARMBLOCK_START + off, count); | ||
806 | return count; | ||
807 | } | ||
808 | |||
809 | static struct bin_attribute ipl_parameter_attr = { | ||
810 | .attr = { | ||
811 | .name = "binary_parameter", | ||
812 | .mode = S_IRUGO, | ||
813 | .owner = THIS_MODULE, | ||
814 | }, | ||
815 | .size = PAGE_SIZE, | ||
816 | .read = &ipl_parameter_read, | ||
817 | }; | ||
818 | |||
819 | static ssize_t | ||
820 | ipl_scp_data_read(struct kobject *kobj, char *buf, loff_t off, size_t count) | ||
821 | { | ||
822 | unsigned int size = IPL_PARMBLOCK_START->fcp.scp_data_len; | ||
823 | void *scp_data = &IPL_PARMBLOCK_START->fcp.scp_data; | ||
824 | |||
825 | if (off > size) | ||
826 | return 0; | ||
827 | if (off + count > size) | ||
828 | count = size - off; | ||
829 | |||
830 | memcpy(buf, scp_data + off, count); | ||
831 | return count; | ||
832 | } | ||
833 | |||
834 | static struct bin_attribute ipl_scp_data_attr = { | ||
835 | .attr = { | ||
836 | .name = "scp_data", | ||
837 | .mode = S_IRUGO, | ||
838 | .owner = THIS_MODULE, | ||
839 | }, | ||
840 | .size = PAGE_SIZE, | ||
841 | .read = &ipl_scp_data_read, | ||
842 | }; | ||
843 | |||
844 | static decl_subsys(ipl, NULL, NULL); | ||
845 | |||
846 | static int __init | ||
847 | ipl_device_sysfs_register(void) { | ||
848 | int rc; | ||
849 | |||
850 | rc = firmware_register(&ipl_subsys); | ||
851 | if (rc) | ||
852 | return rc; | ||
853 | |||
854 | switch (get_ipl_type()) { | ||
855 | case ipl_type_ccw: | ||
856 | sysfs_create_group(&ipl_subsys.kset.kobj, &ipl_ccw_attr_group); | ||
857 | break; | ||
858 | case ipl_type_fcp: | ||
859 | sysfs_create_group(&ipl_subsys.kset.kobj, &ipl_fcp_attr_group); | ||
860 | sysfs_create_bin_file(&ipl_subsys.kset.kobj, | ||
861 | &ipl_parameter_attr); | ||
862 | sysfs_create_bin_file(&ipl_subsys.kset.kobj, | ||
863 | &ipl_scp_data_attr); | ||
864 | break; | ||
865 | default: | ||
866 | sysfs_create_group(&ipl_subsys.kset.kobj, | ||
867 | &ipl_unknown_attr_group); | ||
868 | break; | ||
869 | } | ||
870 | return 0; | ||
871 | } | ||
872 | |||
873 | __initcall(ipl_device_sysfs_register); | ||