diff options
Diffstat (limited to 'arch/powerpc/kernel')
-rw-r--r-- | arch/powerpc/kernel/asm-offsets.c | 4 | ||||
-rw-r--r-- | arch/powerpc/kernel/entry_64.S | 30 | ||||
-rw-r--r-- | arch/powerpc/kernel/exceptions-64s.S | 4 | ||||
-rw-r--r-- | arch/powerpc/kernel/head_44x.S | 8 | ||||
-rw-r--r-- | arch/powerpc/kernel/head_fsl_booke.S | 8 | ||||
-rw-r--r-- | arch/powerpc/kernel/irq.c | 2 | ||||
-rw-r--r-- | arch/powerpc/kernel/misc_32.S | 203 | ||||
-rw-r--r-- | arch/powerpc/kernel/paca.c | 3 | ||||
-rw-r--r-- | arch/powerpc/kernel/process.c | 2 | ||||
-rw-r--r-- | arch/powerpc/kernel/prom_init.c | 17 | ||||
-rw-r--r-- | arch/powerpc/kernel/ptrace.c | 42 | ||||
-rw-r--r-- | arch/powerpc/kernel/ptrace32.c | 32 | ||||
-rw-r--r-- | arch/powerpc/kernel/vector.S | 10 | ||||
-rw-r--r-- | arch/powerpc/kernel/vio.c | 273 |
14 files changed, 468 insertions, 170 deletions
diff --git a/arch/powerpc/kernel/asm-offsets.c b/arch/powerpc/kernel/asm-offsets.c index 34b8afe94a50..4554dc2fe857 100644 --- a/arch/powerpc/kernel/asm-offsets.c +++ b/arch/powerpc/kernel/asm-offsets.c | |||
@@ -188,10 +188,6 @@ int main(void) | |||
188 | DEFINE(SLBSHADOW_STACKESID, | 188 | DEFINE(SLBSHADOW_STACKESID, |
189 | offsetof(struct slb_shadow, save_area[SLB_NUM_BOLTED - 1].esid)); | 189 | offsetof(struct slb_shadow, save_area[SLB_NUM_BOLTED - 1].esid)); |
190 | DEFINE(SLBSHADOW_SAVEAREA, offsetof(struct slb_shadow, save_area)); | 190 | DEFINE(SLBSHADOW_SAVEAREA, offsetof(struct slb_shadow, save_area)); |
191 | DEFINE(LPPACASRR0, offsetof(struct lppaca, saved_srr0)); | ||
192 | DEFINE(LPPACASRR1, offsetof(struct lppaca, saved_srr1)); | ||
193 | DEFINE(LPPACAANYINT, offsetof(struct lppaca, int_dword.any_int)); | ||
194 | DEFINE(LPPACADECRINT, offsetof(struct lppaca, int_dword.fields.decr_int)); | ||
195 | DEFINE(LPPACA_PMCINUSE, offsetof(struct lppaca, pmcregs_in_use)); | 191 | DEFINE(LPPACA_PMCINUSE, offsetof(struct lppaca, pmcregs_in_use)); |
196 | DEFINE(LPPACA_DTLIDX, offsetof(struct lppaca, dtl_idx)); | 192 | DEFINE(LPPACA_DTLIDX, offsetof(struct lppaca, dtl_idx)); |
197 | DEFINE(LPPACA_YIELDCOUNT, offsetof(struct lppaca, yield_count)); | 193 | DEFINE(LPPACA_YIELDCOUNT, offsetof(struct lppaca, yield_count)); |
diff --git a/arch/powerpc/kernel/entry_64.S b/arch/powerpc/kernel/entry_64.S index ef2074c3e906..ed1718feb9d9 100644 --- a/arch/powerpc/kernel/entry_64.S +++ b/arch/powerpc/kernel/entry_64.S | |||
@@ -63,15 +63,9 @@ system_call_common: | |||
63 | std r0,GPR0(r1) | 63 | std r0,GPR0(r1) |
64 | std r10,GPR1(r1) | 64 | std r10,GPR1(r1) |
65 | ACCOUNT_CPU_USER_ENTRY(r10, r11) | 65 | ACCOUNT_CPU_USER_ENTRY(r10, r11) |
66 | /* | ||
67 | * This "crclr so" clears CR0.SO, which is the error indication on | ||
68 | * return from this system call. There must be no cmp instruction | ||
69 | * between it and the "mfcr r9" below, otherwise if XER.SO is set, | ||
70 | * CR0.SO will get set, causing all system calls to appear to fail. | ||
71 | */ | ||
72 | crclr so | ||
73 | std r2,GPR2(r1) | 66 | std r2,GPR2(r1) |
74 | std r3,GPR3(r1) | 67 | std r3,GPR3(r1) |
68 | mfcr r2 | ||
75 | std r4,GPR4(r1) | 69 | std r4,GPR4(r1) |
76 | std r5,GPR5(r1) | 70 | std r5,GPR5(r1) |
77 | std r6,GPR6(r1) | 71 | std r6,GPR6(r1) |
@@ -82,18 +76,20 @@ system_call_common: | |||
82 | std r11,GPR10(r1) | 76 | std r11,GPR10(r1) |
83 | std r11,GPR11(r1) | 77 | std r11,GPR11(r1) |
84 | std r11,GPR12(r1) | 78 | std r11,GPR12(r1) |
79 | std r11,_XER(r1) | ||
80 | std r11,_CTR(r1) | ||
85 | std r9,GPR13(r1) | 81 | std r9,GPR13(r1) |
86 | mfcr r9 | ||
87 | mflr r10 | 82 | mflr r10 |
83 | /* | ||
84 | * This clears CR0.SO (bit 28), which is the error indication on | ||
85 | * return from this system call. | ||
86 | */ | ||
87 | rldimi r2,r11,28,(63-28) | ||
88 | li r11,0xc01 | 88 | li r11,0xc01 |
89 | std r9,_CCR(r1) | ||
90 | std r10,_LINK(r1) | 89 | std r10,_LINK(r1) |
91 | std r11,_TRAP(r1) | 90 | std r11,_TRAP(r1) |
92 | mfxer r9 | ||
93 | mfctr r10 | ||
94 | std r9,_XER(r1) | ||
95 | std r10,_CTR(r1) | ||
96 | std r3,ORIG_GPR3(r1) | 91 | std r3,ORIG_GPR3(r1) |
92 | std r2,_CCR(r1) | ||
97 | ld r2,PACATOC(r13) | 93 | ld r2,PACATOC(r13) |
98 | addi r9,r1,STACK_FRAME_OVERHEAD | 94 | addi r9,r1,STACK_FRAME_OVERHEAD |
99 | ld r11,exception_marker@toc(r2) | 95 | ld r11,exception_marker@toc(r2) |
@@ -154,7 +150,7 @@ END_FW_FTR_SECTION_IFSET(FW_FEATURE_SPLPAR) | |||
154 | ld r10,TI_FLAGS(r11) | 150 | ld r10,TI_FLAGS(r11) |
155 | andi. r11,r10,_TIF_SYSCALL_T_OR_A | 151 | andi. r11,r10,_TIF_SYSCALL_T_OR_A |
156 | bne- syscall_dotrace | 152 | bne- syscall_dotrace |
157 | syscall_dotrace_cont: | 153 | .Lsyscall_dotrace_cont: |
158 | cmpldi 0,r0,NR_syscalls | 154 | cmpldi 0,r0,NR_syscalls |
159 | bge- syscall_enosys | 155 | bge- syscall_enosys |
160 | 156 | ||
@@ -211,7 +207,7 @@ syscall_exit: | |||
211 | cmpld r3,r11 | 207 | cmpld r3,r11 |
212 | ld r5,_CCR(r1) | 208 | ld r5,_CCR(r1) |
213 | bge- syscall_error | 209 | bge- syscall_error |
214 | syscall_error_cont: | 210 | .Lsyscall_error_cont: |
215 | ld r7,_NIP(r1) | 211 | ld r7,_NIP(r1) |
216 | BEGIN_FTR_SECTION | 212 | BEGIN_FTR_SECTION |
217 | stdcx. r0,0,r1 /* to clear the reservation */ | 213 | stdcx. r0,0,r1 /* to clear the reservation */ |
@@ -246,7 +242,7 @@ syscall_error: | |||
246 | oris r5,r5,0x1000 /* Set SO bit in CR */ | 242 | oris r5,r5,0x1000 /* Set SO bit in CR */ |
247 | neg r3,r3 | 243 | neg r3,r3 |
248 | std r5,_CCR(r1) | 244 | std r5,_CCR(r1) |
249 | b syscall_error_cont | 245 | b .Lsyscall_error_cont |
250 | 246 | ||
251 | /* Traced system call support */ | 247 | /* Traced system call support */ |
252 | syscall_dotrace: | 248 | syscall_dotrace: |
@@ -268,7 +264,7 @@ syscall_dotrace: | |||
268 | addi r9,r1,STACK_FRAME_OVERHEAD | 264 | addi r9,r1,STACK_FRAME_OVERHEAD |
269 | clrrdi r10,r1,THREAD_SHIFT | 265 | clrrdi r10,r1,THREAD_SHIFT |
270 | ld r10,TI_FLAGS(r10) | 266 | ld r10,TI_FLAGS(r10) |
271 | b syscall_dotrace_cont | 267 | b .Lsyscall_dotrace_cont |
272 | 268 | ||
273 | syscall_enosys: | 269 | syscall_enosys: |
274 | li r3,-ENOSYS | 270 | li r3,-ENOSYS |
diff --git a/arch/powerpc/kernel/exceptions-64s.S b/arch/powerpc/kernel/exceptions-64s.S index 8f880bc77c56..f7bed44ee165 100644 --- a/arch/powerpc/kernel/exceptions-64s.S +++ b/arch/powerpc/kernel/exceptions-64s.S | |||
@@ -94,12 +94,10 @@ machine_check_pSeries_1: | |||
94 | data_access_pSeries: | 94 | data_access_pSeries: |
95 | HMT_MEDIUM | 95 | HMT_MEDIUM |
96 | SET_SCRATCH0(r13) | 96 | SET_SCRATCH0(r13) |
97 | #ifndef CONFIG_POWER4_ONLY | ||
98 | BEGIN_FTR_SECTION | 97 | BEGIN_FTR_SECTION |
99 | b data_access_check_stab | 98 | b data_access_check_stab |
100 | data_access_not_stab: | 99 | data_access_not_stab: |
101 | END_MMU_FTR_SECTION_IFCLR(MMU_FTR_SLB) | 100 | END_MMU_FTR_SECTION_IFCLR(MMU_FTR_SLB) |
102 | #endif | ||
103 | EXCEPTION_PROLOG_PSERIES(PACA_EXGEN, data_access_common, EXC_STD, | 101 | EXCEPTION_PROLOG_PSERIES(PACA_EXGEN, data_access_common, EXC_STD, |
104 | KVMTEST, 0x300) | 102 | KVMTEST, 0x300) |
105 | 103 | ||
@@ -301,7 +299,6 @@ machine_check_fwnmi: | |||
301 | EXC_STD, KVMTEST, 0x200) | 299 | EXC_STD, KVMTEST, 0x200) |
302 | KVM_HANDLER_SKIP(PACA_EXMC, EXC_STD, 0x200) | 300 | KVM_HANDLER_SKIP(PACA_EXMC, EXC_STD, 0x200) |
303 | 301 | ||
304 | #ifndef CONFIG_POWER4_ONLY | ||
305 | /* moved from 0x300 */ | 302 | /* moved from 0x300 */ |
306 | data_access_check_stab: | 303 | data_access_check_stab: |
307 | GET_PACA(r13) | 304 | GET_PACA(r13) |
@@ -328,7 +325,6 @@ do_stab_bolted_pSeries: | |||
328 | GET_SCRATCH0(r10) | 325 | GET_SCRATCH0(r10) |
329 | std r10,PACA_EXSLB+EX_R13(r13) | 326 | std r10,PACA_EXSLB+EX_R13(r13) |
330 | EXCEPTION_PROLOG_PSERIES_1(.do_stab_bolted, EXC_STD) | 327 | EXCEPTION_PROLOG_PSERIES_1(.do_stab_bolted, EXC_STD) |
331 | #endif /* CONFIG_POWER4_ONLY */ | ||
332 | 328 | ||
333 | KVM_HANDLER_SKIP(PACA_EXGEN, EXC_STD, 0x300) | 329 | KVM_HANDLER_SKIP(PACA_EXGEN, EXC_STD, 0x300) |
334 | KVM_HANDLER_SKIP(PACA_EXSLB, EXC_STD, 0x380) | 330 | KVM_HANDLER_SKIP(PACA_EXSLB, EXC_STD, 0x380) |
diff --git a/arch/powerpc/kernel/head_44x.S b/arch/powerpc/kernel/head_44x.S index 7dd2981bcc50..22d608e8bb7d 100644 --- a/arch/powerpc/kernel/head_44x.S +++ b/arch/powerpc/kernel/head_44x.S | |||
@@ -778,14 +778,6 @@ _GLOBAL(__fixup_440A_mcheck) | |||
778 | blr | 778 | blr |
779 | 779 | ||
780 | /* | 780 | /* |
781 | * extern void giveup_altivec(struct task_struct *prev) | ||
782 | * | ||
783 | * The 44x core does not have an AltiVec unit. | ||
784 | */ | ||
785 | _GLOBAL(giveup_altivec) | ||
786 | blr | ||
787 | |||
788 | /* | ||
789 | * extern void giveup_fpu(struct task_struct *prev) | 781 | * extern void giveup_fpu(struct task_struct *prev) |
790 | * | 782 | * |
791 | * The 44x core does not have an FPU. | 783 | * The 44x core does not have an FPU. |
diff --git a/arch/powerpc/kernel/head_fsl_booke.S b/arch/powerpc/kernel/head_fsl_booke.S index 28e62598d0e8..de80e0f9a2bd 100644 --- a/arch/powerpc/kernel/head_fsl_booke.S +++ b/arch/powerpc/kernel/head_fsl_booke.S | |||
@@ -874,14 +874,6 @@ _GLOBAL(__setup_e500mc_ivors) | |||
874 | sync | 874 | sync |
875 | blr | 875 | blr |
876 | 876 | ||
877 | /* | ||
878 | * extern void giveup_altivec(struct task_struct *prev) | ||
879 | * | ||
880 | * The e500 core does not have an AltiVec unit. | ||
881 | */ | ||
882 | _GLOBAL(giveup_altivec) | ||
883 | blr | ||
884 | |||
885 | #ifdef CONFIG_SPE | 877 | #ifdef CONFIG_SPE |
886 | /* | 878 | /* |
887 | * extern void giveup_spe(struct task_struct *prev) | 879 | * extern void giveup_spe(struct task_struct *prev) |
diff --git a/arch/powerpc/kernel/irq.c b/arch/powerpc/kernel/irq.c index 641da9e868ce..7835a5e1ea5f 100644 --- a/arch/powerpc/kernel/irq.c +++ b/arch/powerpc/kernel/irq.c | |||
@@ -587,7 +587,7 @@ int irq_choose_cpu(const struct cpumask *mask) | |||
587 | { | 587 | { |
588 | int cpuid; | 588 | int cpuid; |
589 | 589 | ||
590 | if (cpumask_equal(mask, cpu_all_mask)) { | 590 | if (cpumask_equal(mask, cpu_online_mask)) { |
591 | static int irq_rover; | 591 | static int irq_rover; |
592 | static DEFINE_RAW_SPINLOCK(irq_rover_lock); | 592 | static DEFINE_RAW_SPINLOCK(irq_rover_lock); |
593 | unsigned long flags; | 593 | unsigned long flags; |
diff --git a/arch/powerpc/kernel/misc_32.S b/arch/powerpc/kernel/misc_32.S index 7cd07b42ca1a..386d57f66f28 100644 --- a/arch/powerpc/kernel/misc_32.S +++ b/arch/powerpc/kernel/misc_32.S | |||
@@ -738,8 +738,23 @@ relocate_new_kernel: | |||
738 | mr r5, r31 | 738 | mr r5, r31 |
739 | 739 | ||
740 | li r0, 0 | 740 | li r0, 0 |
741 | #elif defined(CONFIG_44x) && !defined(CONFIG_PPC_47x) | 741 | #elif defined(CONFIG_44x) |
742 | 742 | ||
743 | /* Save our parameters */ | ||
744 | mr r29, r3 | ||
745 | mr r30, r4 | ||
746 | mr r31, r5 | ||
747 | |||
748 | #ifdef CONFIG_PPC_47x | ||
749 | /* Check for 47x cores */ | ||
750 | mfspr r3,SPRN_PVR | ||
751 | srwi r3,r3,16 | ||
752 | cmplwi cr0,r3,PVR_476@h | ||
753 | beq setup_map_47x | ||
754 | cmplwi cr0,r3,PVR_476_ISS@h | ||
755 | beq setup_map_47x | ||
756 | #endif /* CONFIG_PPC_47x */ | ||
757 | |||
743 | /* | 758 | /* |
744 | * Code for setting up 1:1 mapping for PPC440x for KEXEC | 759 | * Code for setting up 1:1 mapping for PPC440x for KEXEC |
745 | * | 760 | * |
@@ -753,16 +768,15 @@ relocate_new_kernel: | |||
753 | * 5) Invalidate the tmp mapping. | 768 | * 5) Invalidate the tmp mapping. |
754 | * | 769 | * |
755 | * - Based on the kexec support code for FSL BookE | 770 | * - Based on the kexec support code for FSL BookE |
756 | * - Doesn't support 47x yet. | ||
757 | * | 771 | * |
758 | */ | 772 | */ |
759 | /* Save our parameters */ | ||
760 | mr r29, r3 | ||
761 | mr r30, r4 | ||
762 | mr r31, r5 | ||
763 | 773 | ||
764 | /* Load our MSR_IS and TID to MMUCR for TLB search */ | 774 | /* |
765 | mfspr r3,SPRN_PID | 775 | * Load the PID with kernel PID (0). |
776 | * Also load our MSR_IS and TID to MMUCR for TLB search. | ||
777 | */ | ||
778 | li r3, 0 | ||
779 | mtspr SPRN_PID, r3 | ||
766 | mfmsr r4 | 780 | mfmsr r4 |
767 | andi. r4,r4,MSR_IS@l | 781 | andi. r4,r4,MSR_IS@l |
768 | beq wmmucr | 782 | beq wmmucr |
@@ -900,6 +914,179 @@ next_tlb: | |||
900 | li r3, 0 | 914 | li r3, 0 |
901 | tlbwe r3, r24, PPC44x_TLB_PAGEID | 915 | tlbwe r3, r24, PPC44x_TLB_PAGEID |
902 | sync | 916 | sync |
917 | b ppc44x_map_done | ||
918 | |||
919 | #ifdef CONFIG_PPC_47x | ||
920 | |||
921 | /* 1:1 mapping for 47x */ | ||
922 | |||
923 | setup_map_47x: | ||
924 | |||
925 | /* | ||
926 | * Load the kernel pid (0) to PID and also to MMUCR[TID]. | ||
927 | * Also set the MSR IS->MMUCR STS | ||
928 | */ | ||
929 | li r3, 0 | ||
930 | mtspr SPRN_PID, r3 /* Set PID */ | ||
931 | mfmsr r4 /* Get MSR */ | ||
932 | andi. r4, r4, MSR_IS@l /* TS=1? */ | ||
933 | beq 1f /* If not, leave STS=0 */ | ||
934 | oris r3, r3, PPC47x_MMUCR_STS@h /* Set STS=1 */ | ||
935 | 1: mtspr SPRN_MMUCR, r3 /* Put MMUCR */ | ||
936 | sync | ||
937 | |||
938 | /* Find the entry we are running from */ | ||
939 | bl 2f | ||
940 | 2: mflr r23 | ||
941 | tlbsx r23, 0, r23 | ||
942 | tlbre r24, r23, 0 /* TLB Word 0 */ | ||
943 | tlbre r25, r23, 1 /* TLB Word 1 */ | ||
944 | tlbre r26, r23, 2 /* TLB Word 2 */ | ||
945 | |||
946 | |||
947 | /* | ||
948 | * Invalidates all the tlb entries by writing to 256 RPNs(r4) | ||
949 | * of 4k page size in all 4 ways (0-3 in r3). | ||
950 | * This would invalidate the entire UTLB including the one we are | ||
951 | * running from. However the shadow TLB entries would help us | ||
952 | * to continue the execution, until we flush them (rfi/isync). | ||
953 | */ | ||
954 | addis r3, 0, 0x8000 /* specify the way */ | ||
955 | addi r4, 0, 0 /* TLB Word0 = (EPN=0, VALID = 0) */ | ||
956 | addi r5, 0, 0 | ||
957 | b clear_utlb_entry | ||
958 | |||
959 | /* Align the loop to speed things up. from head_44x.S */ | ||
960 | .align 6 | ||
961 | |||
962 | clear_utlb_entry: | ||
963 | |||
964 | tlbwe r4, r3, 0 | ||
965 | tlbwe r5, r3, 1 | ||
966 | tlbwe r5, r3, 2 | ||
967 | addis r3, r3, 0x2000 /* Increment the way */ | ||
968 | cmpwi r3, 0 | ||
969 | bne clear_utlb_entry | ||
970 | addis r3, 0, 0x8000 | ||
971 | addis r4, r4, 0x100 /* Increment the EPN */ | ||
972 | cmpwi r4, 0 | ||
973 | bne clear_utlb_entry | ||
974 | |||
975 | /* Create the entries in the other address space */ | ||
976 | mfmsr r5 | ||
977 | rlwinm r7, r5, 27, 31, 31 /* Get the TS (Bit 26) from MSR */ | ||
978 | xori r7, r7, 1 /* r7 = !TS */ | ||
979 | |||
980 | insrwi r24, r7, 1, 21 /* Change the TS in the saved TLB word 0 */ | ||
981 | |||
982 | /* | ||
983 | * write out the TLB entries for the tmp mapping | ||
984 | * Use way '0' so that we could easily invalidate it later. | ||
985 | */ | ||
986 | lis r3, 0x8000 /* Way '0' */ | ||
987 | |||
988 | tlbwe r24, r3, 0 | ||
989 | tlbwe r25, r3, 1 | ||
990 | tlbwe r26, r3, 2 | ||
991 | |||
992 | /* Update the msr to the new TS */ | ||
993 | insrwi r5, r7, 1, 26 | ||
994 | |||
995 | bl 1f | ||
996 | 1: mflr r6 | ||
997 | addi r6, r6, (2f-1b) | ||
998 | |||
999 | mtspr SPRN_SRR0, r6 | ||
1000 | mtspr SPRN_SRR1, r5 | ||
1001 | rfi | ||
1002 | |||
1003 | /* | ||
1004 | * Now we are in the tmp address space. | ||
1005 | * Create a 1:1 mapping for 0-2GiB in the original TS. | ||
1006 | */ | ||
1007 | 2: | ||
1008 | li r3, 0 | ||
1009 | li r4, 0 /* TLB Word 0 */ | ||
1010 | li r5, 0 /* TLB Word 1 */ | ||
1011 | li r6, 0 | ||
1012 | ori r6, r6, PPC47x_TLB2_S_RWX /* TLB word 2 */ | ||
1013 | |||
1014 | li r8, 0 /* PageIndex */ | ||
1015 | |||
1016 | xori r7, r7, 1 /* revert back to original TS */ | ||
1017 | |||
1018 | write_utlb: | ||
1019 | rotlwi r5, r8, 28 /* RPN = PageIndex * 256M */ | ||
1020 | /* ERPN = 0 as we don't use memory above 2G */ | ||
1021 | |||
1022 | mr r4, r5 /* EPN = RPN */ | ||
1023 | ori r4, r4, (PPC47x_TLB0_VALID | PPC47x_TLB0_256M) | ||
1024 | insrwi r4, r7, 1, 21 /* Insert the TS to Word 0 */ | ||
1025 | |||
1026 | tlbwe r4, r3, 0 /* Write out the entries */ | ||
1027 | tlbwe r5, r3, 1 | ||
1028 | tlbwe r6, r3, 2 | ||
1029 | addi r8, r8, 1 | ||
1030 | cmpwi r8, 8 /* Have we completed ? */ | ||
1031 | bne write_utlb | ||
1032 | |||
1033 | /* make sure we complete the TLB write up */ | ||
1034 | isync | ||
1035 | |||
1036 | /* | ||
1037 | * Prepare to jump to the 1:1 mapping. | ||
1038 | * 1) Extract page size of the tmp mapping | ||
1039 | * DSIZ = TLB_Word0[22:27] | ||
1040 | * 2) Calculate the physical address of the address | ||
1041 | * to jump to. | ||
1042 | */ | ||
1043 | rlwinm r10, r24, 0, 22, 27 | ||
1044 | |||
1045 | cmpwi r10, PPC47x_TLB0_4K | ||
1046 | bne 0f | ||
1047 | li r10, 0x1000 /* r10 = 4k */ | ||
1048 | bl 1f | ||
1049 | |||
1050 | 0: | ||
1051 | /* Defaults to 256M */ | ||
1052 | lis r10, 0x1000 | ||
1053 | |||
1054 | bl 1f | ||
1055 | 1: mflr r4 | ||
1056 | addi r4, r4, (2f-1b) /* virtual address of 2f */ | ||
1057 | |||
1058 | subi r11, r10, 1 /* offsetmask = Pagesize - 1 */ | ||
1059 | not r10, r11 /* Pagemask = ~(offsetmask) */ | ||
1060 | |||
1061 | and r5, r25, r10 /* Physical page */ | ||
1062 | and r6, r4, r11 /* offset within the current page */ | ||
1063 | |||
1064 | or r5, r5, r6 /* Physical address for 2f */ | ||
1065 | |||
1066 | /* Switch the TS in MSR to the original one */ | ||
1067 | mfmsr r8 | ||
1068 | insrwi r8, r7, 1, 26 | ||
1069 | |||
1070 | mtspr SPRN_SRR1, r8 | ||
1071 | mtspr SPRN_SRR0, r5 | ||
1072 | rfi | ||
1073 | |||
1074 | 2: | ||
1075 | /* Invalidate the tmp mapping */ | ||
1076 | lis r3, 0x8000 /* Way '0' */ | ||
1077 | |||
1078 | clrrwi r24, r24, 12 /* Clear the valid bit */ | ||
1079 | tlbwe r24, r3, 0 | ||
1080 | tlbwe r25, r3, 1 | ||
1081 | tlbwe r26, r3, 2 | ||
1082 | |||
1083 | /* Make sure we complete the TLB write and flush the shadow TLB */ | ||
1084 | isync | ||
1085 | |||
1086 | #endif | ||
1087 | |||
1088 | ppc44x_map_done: | ||
1089 | |||
903 | 1090 | ||
904 | /* Restore the parameters */ | 1091 | /* Restore the parameters */ |
905 | mr r3, r29 | 1092 | mr r3, r29 |
diff --git a/arch/powerpc/kernel/paca.c b/arch/powerpc/kernel/paca.c index 0bb1f98613ba..fbe1a12dc7f1 100644 --- a/arch/powerpc/kernel/paca.c +++ b/arch/powerpc/kernel/paca.c | |||
@@ -36,10 +36,7 @@ struct lppaca lppaca[] = { | |||
36 | [0 ... (NR_LPPACAS-1)] = { | 36 | [0 ... (NR_LPPACAS-1)] = { |
37 | .desc = 0xd397d781, /* "LpPa" */ | 37 | .desc = 0xd397d781, /* "LpPa" */ |
38 | .size = sizeof(struct lppaca), | 38 | .size = sizeof(struct lppaca), |
39 | .dyn_proc_status = 2, | ||
40 | .decr_val = 0x00ff0000, | ||
41 | .fpregs_in_use = 1, | 39 | .fpregs_in_use = 1, |
42 | .end_of_quantum = 0xfffffffffffffffful, | ||
43 | .slb_count = 64, | 40 | .slb_count = 64, |
44 | .vmxregs_in_use = 0, | 41 | .vmxregs_in_use = 0, |
45 | .page_ins = 0, | 42 | .page_ins = 0, |
diff --git a/arch/powerpc/kernel/process.c b/arch/powerpc/kernel/process.c index aa05935b6947..7f8ec1de0ace 100644 --- a/arch/powerpc/kernel/process.c +++ b/arch/powerpc/kernel/process.c | |||
@@ -124,7 +124,7 @@ void enable_kernel_altivec(void) | |||
124 | if (current->thread.regs && (current->thread.regs->msr & MSR_VEC)) | 124 | if (current->thread.regs && (current->thread.regs->msr & MSR_VEC)) |
125 | giveup_altivec(current); | 125 | giveup_altivec(current); |
126 | else | 126 | else |
127 | giveup_altivec(NULL); /* just enable AltiVec for kernel - force */ | 127 | giveup_altivec_notask(); |
128 | #else | 128 | #else |
129 | giveup_altivec(last_task_used_altivec); | 129 | giveup_altivec(last_task_used_altivec); |
130 | #endif /* CONFIG_SMP */ | 130 | #endif /* CONFIG_SMP */ |
diff --git a/arch/powerpc/kernel/prom_init.c b/arch/powerpc/kernel/prom_init.c index 99860273211b..1b488e5305c5 100644 --- a/arch/powerpc/kernel/prom_init.c +++ b/arch/powerpc/kernel/prom_init.c | |||
@@ -680,6 +680,9 @@ static void __init early_cmdline_parse(void) | |||
680 | #define OV3_VMX 0x40 /* VMX/Altivec */ | 680 | #define OV3_VMX 0x40 /* VMX/Altivec */ |
681 | #define OV3_DFP 0x20 /* decimal FP */ | 681 | #define OV3_DFP 0x20 /* decimal FP */ |
682 | 682 | ||
683 | /* Option vector 4: IBM PAPR implementation */ | ||
684 | #define OV4_MIN_ENT_CAP 0x01 /* minimum VP entitled capacity */ | ||
685 | |||
683 | /* Option vector 5: PAPR/OF options supported */ | 686 | /* Option vector 5: PAPR/OF options supported */ |
684 | #define OV5_LPAR 0x80 /* logical partitioning supported */ | 687 | #define OV5_LPAR 0x80 /* logical partitioning supported */ |
685 | #define OV5_SPLPAR 0x40 /* shared-processor LPAR supported */ | 688 | #define OV5_SPLPAR 0x40 /* shared-processor LPAR supported */ |
@@ -701,6 +704,8 @@ static void __init early_cmdline_parse(void) | |||
701 | #define OV5_XCMO 0x00 | 704 | #define OV5_XCMO 0x00 |
702 | #endif | 705 | #endif |
703 | #define OV5_TYPE1_AFFINITY 0x80 /* Type 1 NUMA affinity */ | 706 | #define OV5_TYPE1_AFFINITY 0x80 /* Type 1 NUMA affinity */ |
707 | #define OV5_PFO_HW_RNG 0x80 /* PFO Random Number Generator */ | ||
708 | #define OV5_PFO_HW_ENCR 0x20 /* PFO Encryption Accelerator */ | ||
704 | 709 | ||
705 | /* Option Vector 6: IBM PAPR hints */ | 710 | /* Option Vector 6: IBM PAPR hints */ |
706 | #define OV6_LINUX 0x02 /* Linux is our OS */ | 711 | #define OV6_LINUX 0x02 /* Linux is our OS */ |
@@ -744,11 +749,12 @@ static unsigned char ibm_architecture_vec[] = { | |||
744 | OV3_FP | OV3_VMX | OV3_DFP, | 749 | OV3_FP | OV3_VMX | OV3_DFP, |
745 | 750 | ||
746 | /* option vector 4: IBM PAPR implementation */ | 751 | /* option vector 4: IBM PAPR implementation */ |
747 | 2 - 2, /* length */ | 752 | 3 - 2, /* length */ |
748 | 0, /* don't halt */ | 753 | 0, /* don't halt */ |
754 | OV4_MIN_ENT_CAP, /* minimum VP entitled capacity */ | ||
749 | 755 | ||
750 | /* option vector 5: PAPR/OF options */ | 756 | /* option vector 5: PAPR/OF options */ |
751 | 13 - 2, /* length */ | 757 | 18 - 2, /* length */ |
752 | 0, /* don't ignore, don't halt */ | 758 | 0, /* don't ignore, don't halt */ |
753 | OV5_LPAR | OV5_SPLPAR | OV5_LARGE_PAGES | OV5_DRCONF_MEMORY | | 759 | OV5_LPAR | OV5_SPLPAR | OV5_LARGE_PAGES | OV5_DRCONF_MEMORY | |
754 | OV5_DONATE_DEDICATE_CPU | OV5_MSI, | 760 | OV5_DONATE_DEDICATE_CPU | OV5_MSI, |
@@ -762,8 +768,13 @@ static unsigned char ibm_architecture_vec[] = { | |||
762 | * must match by the macro below. Update the definition if | 768 | * must match by the macro below. Update the definition if |
763 | * the structure layout changes. | 769 | * the structure layout changes. |
764 | */ | 770 | */ |
765 | #define IBM_ARCH_VEC_NRCORES_OFFSET 100 | 771 | #define IBM_ARCH_VEC_NRCORES_OFFSET 101 |
766 | W(NR_CPUS), /* number of cores supported */ | 772 | W(NR_CPUS), /* number of cores supported */ |
773 | 0, | ||
774 | 0, | ||
775 | 0, | ||
776 | 0, | ||
777 | OV5_PFO_HW_RNG | OV5_PFO_HW_ENCR, | ||
767 | 778 | ||
768 | /* option vector 6: IBM PAPR hints */ | 779 | /* option vector 6: IBM PAPR hints */ |
769 | 4 - 2, /* length */ | 780 | 4 - 2, /* length */ |
diff --git a/arch/powerpc/kernel/ptrace.c b/arch/powerpc/kernel/ptrace.c index dd5e214cdf21..c10fc28b9092 100644 --- a/arch/powerpc/kernel/ptrace.c +++ b/arch/powerpc/kernel/ptrace.c | |||
@@ -1432,40 +1432,6 @@ static long ppc_del_hwdebug(struct task_struct *child, long addr, long data) | |||
1432 | #endif | 1432 | #endif |
1433 | } | 1433 | } |
1434 | 1434 | ||
1435 | /* | ||
1436 | * Here are the old "legacy" powerpc specific getregs/setregs ptrace calls, | ||
1437 | * we mark them as obsolete now, they will be removed in a future version | ||
1438 | */ | ||
1439 | static long arch_ptrace_old(struct task_struct *child, long request, | ||
1440 | unsigned long addr, unsigned long data) | ||
1441 | { | ||
1442 | void __user *datavp = (void __user *) data; | ||
1443 | |||
1444 | switch (request) { | ||
1445 | case PPC_PTRACE_GETREGS: /* Get GPRs 0 - 31. */ | ||
1446 | return copy_regset_to_user(child, &user_ppc_native_view, | ||
1447 | REGSET_GPR, 0, 32 * sizeof(long), | ||
1448 | datavp); | ||
1449 | |||
1450 | case PPC_PTRACE_SETREGS: /* Set GPRs 0 - 31. */ | ||
1451 | return copy_regset_from_user(child, &user_ppc_native_view, | ||
1452 | REGSET_GPR, 0, 32 * sizeof(long), | ||
1453 | datavp); | ||
1454 | |||
1455 | case PPC_PTRACE_GETFPREGS: /* Get FPRs 0 - 31. */ | ||
1456 | return copy_regset_to_user(child, &user_ppc_native_view, | ||
1457 | REGSET_FPR, 0, 32 * sizeof(double), | ||
1458 | datavp); | ||
1459 | |||
1460 | case PPC_PTRACE_SETFPREGS: /* Set FPRs 0 - 31. */ | ||
1461 | return copy_regset_from_user(child, &user_ppc_native_view, | ||
1462 | REGSET_FPR, 0, 32 * sizeof(double), | ||
1463 | datavp); | ||
1464 | } | ||
1465 | |||
1466 | return -EPERM; | ||
1467 | } | ||
1468 | |||
1469 | long arch_ptrace(struct task_struct *child, long request, | 1435 | long arch_ptrace(struct task_struct *child, long request, |
1470 | unsigned long addr, unsigned long data) | 1436 | unsigned long addr, unsigned long data) |
1471 | { | 1437 | { |
@@ -1687,14 +1653,6 @@ long arch_ptrace(struct task_struct *child, long request, | |||
1687 | datavp); | 1653 | datavp); |
1688 | #endif | 1654 | #endif |
1689 | 1655 | ||
1690 | /* Old reverse args ptrace callss */ | ||
1691 | case PPC_PTRACE_GETREGS: /* Get GPRs 0 - 31. */ | ||
1692 | case PPC_PTRACE_SETREGS: /* Set GPRs 0 - 31. */ | ||
1693 | case PPC_PTRACE_GETFPREGS: /* Get FPRs 0 - 31. */ | ||
1694 | case PPC_PTRACE_SETFPREGS: /* Get FPRs 0 - 31. */ | ||
1695 | ret = arch_ptrace_old(child, request, addr, data); | ||
1696 | break; | ||
1697 | |||
1698 | default: | 1656 | default: |
1699 | ret = ptrace_request(child, request, addr, data); | 1657 | ret = ptrace_request(child, request, addr, data); |
1700 | break; | 1658 | break; |
diff --git a/arch/powerpc/kernel/ptrace32.c b/arch/powerpc/kernel/ptrace32.c index 469349d14a97..8c21658719d9 100644 --- a/arch/powerpc/kernel/ptrace32.c +++ b/arch/powerpc/kernel/ptrace32.c | |||
@@ -39,30 +39,6 @@ | |||
39 | * in exit.c or in signal.c. | 39 | * in exit.c or in signal.c. |
40 | */ | 40 | */ |
41 | 41 | ||
42 | /* | ||
43 | * Here are the old "legacy" powerpc specific getregs/setregs ptrace calls, | ||
44 | * we mark them as obsolete now, they will be removed in a future version | ||
45 | */ | ||
46 | static long compat_ptrace_old(struct task_struct *child, long request, | ||
47 | long addr, long data) | ||
48 | { | ||
49 | switch (request) { | ||
50 | case PPC_PTRACE_GETREGS: /* Get GPRs 0 - 31. */ | ||
51 | return copy_regset_to_user(child, | ||
52 | task_user_regset_view(current), 0, | ||
53 | 0, 32 * sizeof(compat_long_t), | ||
54 | compat_ptr(data)); | ||
55 | |||
56 | case PPC_PTRACE_SETREGS: /* Set GPRs 0 - 31. */ | ||
57 | return copy_regset_from_user(child, | ||
58 | task_user_regset_view(current), 0, | ||
59 | 0, 32 * sizeof(compat_long_t), | ||
60 | compat_ptr(data)); | ||
61 | } | ||
62 | |||
63 | return -EPERM; | ||
64 | } | ||
65 | |||
66 | /* Macros to workout the correct index for the FPR in the thread struct */ | 42 | /* Macros to workout the correct index for the FPR in the thread struct */ |
67 | #define FPRNUMBER(i) (((i) - PT_FPR0) >> 1) | 43 | #define FPRNUMBER(i) (((i) - PT_FPR0) >> 1) |
68 | #define FPRHALF(i) (((i) - PT_FPR0) & 1) | 44 | #define FPRHALF(i) (((i) - PT_FPR0) & 1) |
@@ -308,8 +284,6 @@ long compat_arch_ptrace(struct task_struct *child, compat_long_t request, | |||
308 | case PTRACE_SETVSRREGS: | 284 | case PTRACE_SETVSRREGS: |
309 | case PTRACE_GETREGS64: | 285 | case PTRACE_GETREGS64: |
310 | case PTRACE_SETREGS64: | 286 | case PTRACE_SETREGS64: |
311 | case PPC_PTRACE_GETFPREGS: | ||
312 | case PPC_PTRACE_SETFPREGS: | ||
313 | case PTRACE_KILL: | 287 | case PTRACE_KILL: |
314 | case PTRACE_SINGLESTEP: | 288 | case PTRACE_SINGLESTEP: |
315 | case PTRACE_DETACH: | 289 | case PTRACE_DETACH: |
@@ -322,12 +296,6 @@ long compat_arch_ptrace(struct task_struct *child, compat_long_t request, | |||
322 | ret = arch_ptrace(child, request, addr, data); | 296 | ret = arch_ptrace(child, request, addr, data); |
323 | break; | 297 | break; |
324 | 298 | ||
325 | /* Old reverse args ptrace callss */ | ||
326 | case PPC_PTRACE_GETREGS: /* Get GPRs 0 - 31. */ | ||
327 | case PPC_PTRACE_SETREGS: /* Set GPRs 0 - 31. */ | ||
328 | ret = compat_ptrace_old(child, request, addr, data); | ||
329 | break; | ||
330 | |||
331 | default: | 299 | default: |
332 | ret = compat_ptrace_request(child, request, addr, data); | 300 | ret = compat_ptrace_request(child, request, addr, data); |
333 | break; | 301 | break; |
diff --git a/arch/powerpc/kernel/vector.S b/arch/powerpc/kernel/vector.S index 4d5a3edff49e..e830289d2e48 100644 --- a/arch/powerpc/kernel/vector.S +++ b/arch/powerpc/kernel/vector.S | |||
@@ -89,6 +89,16 @@ _GLOBAL(load_up_altivec) | |||
89 | /* restore registers and return */ | 89 | /* restore registers and return */ |
90 | blr | 90 | blr |
91 | 91 | ||
92 | _GLOBAL(giveup_altivec_notask) | ||
93 | mfmsr r3 | ||
94 | andis. r4,r3,MSR_VEC@h | ||
95 | bnelr /* Already enabled? */ | ||
96 | oris r3,r3,MSR_VEC@h | ||
97 | SYNC | ||
98 | MTMSRD(r3) /* enable use of VMX now */ | ||
99 | isync | ||
100 | blr | ||
101 | |||
92 | /* | 102 | /* |
93 | * giveup_altivec(tsk) | 103 | * giveup_altivec(tsk) |
94 | * Disable VMX for the task given as the argument, | 104 | * Disable VMX for the task given as the argument, |
diff --git a/arch/powerpc/kernel/vio.c b/arch/powerpc/kernel/vio.c index a3a99901c8ec..cb87301ccd55 100644 --- a/arch/powerpc/kernel/vio.c +++ b/arch/powerpc/kernel/vio.c | |||
@@ -14,7 +14,9 @@ | |||
14 | * 2 of the License, or (at your option) any later version. | 14 | * 2 of the License, or (at your option) any later version. |
15 | */ | 15 | */ |
16 | 16 | ||
17 | #include <linux/cpu.h> | ||
17 | #include <linux/types.h> | 18 | #include <linux/types.h> |
19 | #include <linux/delay.h> | ||
18 | #include <linux/stat.h> | 20 | #include <linux/stat.h> |
19 | #include <linux/device.h> | 21 | #include <linux/device.h> |
20 | #include <linux/init.h> | 22 | #include <linux/init.h> |
@@ -709,13 +711,26 @@ static int vio_cmo_bus_probe(struct vio_dev *viodev) | |||
709 | struct vio_driver *viodrv = to_vio_driver(dev->driver); | 711 | struct vio_driver *viodrv = to_vio_driver(dev->driver); |
710 | unsigned long flags; | 712 | unsigned long flags; |
711 | size_t size; | 713 | size_t size; |
714 | bool dma_capable = false; | ||
715 | |||
716 | /* A device requires entitlement if it has a DMA window property */ | ||
717 | switch (viodev->family) { | ||
718 | case VDEVICE: | ||
719 | if (of_get_property(viodev->dev.of_node, | ||
720 | "ibm,my-dma-window", NULL)) | ||
721 | dma_capable = true; | ||
722 | break; | ||
723 | case PFO: | ||
724 | dma_capable = false; | ||
725 | break; | ||
726 | default: | ||
727 | dev_warn(dev, "unknown device family: %d\n", viodev->family); | ||
728 | BUG(); | ||
729 | break; | ||
730 | } | ||
712 | 731 | ||
713 | /* | 732 | /* Configure entitlement for the device. */ |
714 | * Check to see that device has a DMA window and configure | 733 | if (dma_capable) { |
715 | * entitlement for the device. | ||
716 | */ | ||
717 | if (of_get_property(viodev->dev.of_node, | ||
718 | "ibm,my-dma-window", NULL)) { | ||
719 | /* Check that the driver is CMO enabled and get desired DMA */ | 734 | /* Check that the driver is CMO enabled and get desired DMA */ |
720 | if (!viodrv->get_desired_dma) { | 735 | if (!viodrv->get_desired_dma) { |
721 | dev_err(dev, "%s: device driver does not support CMO\n", | 736 | dev_err(dev, "%s: device driver does not support CMO\n", |
@@ -1050,6 +1065,94 @@ static void vio_cmo_sysfs_init(void) { } | |||
1050 | EXPORT_SYMBOL(vio_cmo_entitlement_update); | 1065 | EXPORT_SYMBOL(vio_cmo_entitlement_update); |
1051 | EXPORT_SYMBOL(vio_cmo_set_dev_desired); | 1066 | EXPORT_SYMBOL(vio_cmo_set_dev_desired); |
1052 | 1067 | ||
1068 | |||
1069 | /* | ||
1070 | * Platform Facilities Option (PFO) support | ||
1071 | */ | ||
1072 | |||
1073 | /** | ||
1074 | * vio_h_cop_sync - Perform a synchronous PFO co-processor operation | ||
1075 | * | ||
1076 | * @vdev - Pointer to a struct vio_dev for device | ||
1077 | * @op - Pointer to a struct vio_pfo_op for the operation parameters | ||
1078 | * | ||
1079 | * Calls the hypervisor to synchronously perform the PFO operation | ||
1080 | * described in @op. In the case of a busy response from the hypervisor, | ||
1081 | * the operation will be re-submitted indefinitely unless a non-zero timeout | ||
1082 | * is specified or an error occurs. The timeout places a limit on when to | ||
1083 | * stop re-submitting a operation, the total time can be exceeded if an | ||
1084 | * operation is in progress. | ||
1085 | * | ||
1086 | * If op->hcall_ret is not NULL, this will be set to the return from the | ||
1087 | * last h_cop_op call or it will be 0 if an error not involving the h_call | ||
1088 | * was encountered. | ||
1089 | * | ||
1090 | * Returns: | ||
1091 | * 0 on success, | ||
1092 | * -EINVAL if the h_call fails due to an invalid parameter, | ||
1093 | * -E2BIG if the h_call can not be performed synchronously, | ||
1094 | * -EBUSY if a timeout is specified and has elapsed, | ||
1095 | * -EACCES if the memory area for data/status has been rescinded, or | ||
1096 | * -EPERM if a hardware fault has been indicated | ||
1097 | */ | ||
1098 | int vio_h_cop_sync(struct vio_dev *vdev, struct vio_pfo_op *op) | ||
1099 | { | ||
1100 | struct device *dev = &vdev->dev; | ||
1101 | unsigned long deadline = 0; | ||
1102 | long hret = 0; | ||
1103 | int ret = 0; | ||
1104 | |||
1105 | if (op->timeout) | ||
1106 | deadline = jiffies + msecs_to_jiffies(op->timeout); | ||
1107 | |||
1108 | while (true) { | ||
1109 | hret = plpar_hcall_norets(H_COP, op->flags, | ||
1110 | vdev->resource_id, | ||
1111 | op->in, op->inlen, op->out, | ||
1112 | op->outlen, op->csbcpb); | ||
1113 | |||
1114 | if (hret == H_SUCCESS || | ||
1115 | (hret != H_NOT_ENOUGH_RESOURCES && | ||
1116 | hret != H_BUSY && hret != H_RESOURCE) || | ||
1117 | (op->timeout && time_after(deadline, jiffies))) | ||
1118 | break; | ||
1119 | |||
1120 | dev_dbg(dev, "%s: hcall ret(%ld), retrying.\n", __func__, hret); | ||
1121 | } | ||
1122 | |||
1123 | switch (hret) { | ||
1124 | case H_SUCCESS: | ||
1125 | ret = 0; | ||
1126 | break; | ||
1127 | case H_OP_MODE: | ||
1128 | case H_TOO_BIG: | ||
1129 | ret = -E2BIG; | ||
1130 | break; | ||
1131 | case H_RESCINDED: | ||
1132 | ret = -EACCES; | ||
1133 | break; | ||
1134 | case H_HARDWARE: | ||
1135 | ret = -EPERM; | ||
1136 | break; | ||
1137 | case H_NOT_ENOUGH_RESOURCES: | ||
1138 | case H_RESOURCE: | ||
1139 | case H_BUSY: | ||
1140 | ret = -EBUSY; | ||
1141 | break; | ||
1142 | default: | ||
1143 | ret = -EINVAL; | ||
1144 | break; | ||
1145 | } | ||
1146 | |||
1147 | if (ret) | ||
1148 | dev_dbg(dev, "%s: Sync h_cop_op failure (ret:%d) (hret:%ld)\n", | ||
1149 | __func__, ret, hret); | ||
1150 | |||
1151 | op->hcall_err = hret; | ||
1152 | return ret; | ||
1153 | } | ||
1154 | EXPORT_SYMBOL(vio_h_cop_sync); | ||
1155 | |||
1053 | static struct iommu_table *vio_build_iommu_table(struct vio_dev *dev) | 1156 | static struct iommu_table *vio_build_iommu_table(struct vio_dev *dev) |
1054 | { | 1157 | { |
1055 | const unsigned char *dma_window; | 1158 | const unsigned char *dma_window; |
@@ -1211,35 +1314,87 @@ static void __devinit vio_dev_release(struct device *dev) | |||
1211 | struct vio_dev *vio_register_device_node(struct device_node *of_node) | 1314 | struct vio_dev *vio_register_device_node(struct device_node *of_node) |
1212 | { | 1315 | { |
1213 | struct vio_dev *viodev; | 1316 | struct vio_dev *viodev; |
1317 | struct device_node *parent_node; | ||
1214 | const unsigned int *unit_address; | 1318 | const unsigned int *unit_address; |
1319 | const unsigned int *pfo_resid = NULL; | ||
1320 | enum vio_dev_family family; | ||
1321 | const char *of_node_name = of_node->name ? of_node->name : "<unknown>"; | ||
1215 | 1322 | ||
1216 | /* we need the 'device_type' property, in order to match with drivers */ | 1323 | /* |
1217 | if (of_node->type == NULL) { | 1324 | * Determine if this node is a under the /vdevice node or under the |
1218 | printk(KERN_WARNING "%s: node %s missing 'device_type'\n", | 1325 | * /ibm,platform-facilities node. This decides the device's family. |
1219 | __func__, | 1326 | */ |
1220 | of_node->name ? of_node->name : "<unknown>"); | 1327 | parent_node = of_get_parent(of_node); |
1328 | if (parent_node) { | ||
1329 | if (!strcmp(parent_node->full_name, "/ibm,platform-facilities")) | ||
1330 | family = PFO; | ||
1331 | else if (!strcmp(parent_node->full_name, "/vdevice")) | ||
1332 | family = VDEVICE; | ||
1333 | else { | ||
1334 | pr_warn("%s: parent(%s) of %s not recognized.\n", | ||
1335 | __func__, | ||
1336 | parent_node->full_name, | ||
1337 | of_node_name); | ||
1338 | of_node_put(parent_node); | ||
1339 | return NULL; | ||
1340 | } | ||
1341 | of_node_put(parent_node); | ||
1342 | } else { | ||
1343 | pr_warn("%s: could not determine the parent of node %s.\n", | ||
1344 | __func__, of_node_name); | ||
1221 | return NULL; | 1345 | return NULL; |
1222 | } | 1346 | } |
1223 | 1347 | ||
1224 | unit_address = of_get_property(of_node, "reg", NULL); | 1348 | if (family == PFO) { |
1225 | if (unit_address == NULL) { | 1349 | if (of_get_property(of_node, "interrupt-controller", NULL)) { |
1226 | printk(KERN_WARNING "%s: node %s missing 'reg'\n", | 1350 | pr_debug("%s: Skipping the interrupt controller %s.\n", |
1227 | __func__, | 1351 | __func__, of_node_name); |
1228 | of_node->name ? of_node->name : "<unknown>"); | 1352 | return NULL; |
1229 | return NULL; | 1353 | } |
1230 | } | 1354 | } |
1231 | 1355 | ||
1232 | /* allocate a vio_dev for this node */ | 1356 | /* allocate a vio_dev for this node */ |
1233 | viodev = kzalloc(sizeof(struct vio_dev), GFP_KERNEL); | 1357 | viodev = kzalloc(sizeof(struct vio_dev), GFP_KERNEL); |
1234 | if (viodev == NULL) | 1358 | if (viodev == NULL) { |
1359 | pr_warn("%s: allocation failure for VIO device.\n", __func__); | ||
1235 | return NULL; | 1360 | return NULL; |
1361 | } | ||
1236 | 1362 | ||
1237 | viodev->irq = irq_of_parse_and_map(of_node, 0); | 1363 | /* we need the 'device_type' property, in order to match with drivers */ |
1364 | viodev->family = family; | ||
1365 | if (viodev->family == VDEVICE) { | ||
1366 | if (of_node->type != NULL) | ||
1367 | viodev->type = of_node->type; | ||
1368 | else { | ||
1369 | pr_warn("%s: node %s is missing the 'device_type' " | ||
1370 | "property.\n", __func__, of_node_name); | ||
1371 | goto out; | ||
1372 | } | ||
1373 | |||
1374 | unit_address = of_get_property(of_node, "reg", NULL); | ||
1375 | if (unit_address == NULL) { | ||
1376 | pr_warn("%s: node %s missing 'reg'\n", | ||
1377 | __func__, of_node_name); | ||
1378 | goto out; | ||
1379 | } | ||
1380 | dev_set_name(&viodev->dev, "%x", *unit_address); | ||
1381 | viodev->irq = irq_of_parse_and_map(of_node, 0); | ||
1382 | viodev->unit_address = *unit_address; | ||
1383 | } else { | ||
1384 | /* PFO devices need their resource_id for submitting COP_OPs | ||
1385 | * This is an optional field for devices, but is required when | ||
1386 | * performing synchronous ops */ | ||
1387 | pfo_resid = of_get_property(of_node, "ibm,resource-id", NULL); | ||
1388 | if (pfo_resid != NULL) | ||
1389 | viodev->resource_id = *pfo_resid; | ||
1390 | |||
1391 | unit_address = NULL; | ||
1392 | dev_set_name(&viodev->dev, "%s", of_node_name); | ||
1393 | viodev->type = of_node_name; | ||
1394 | viodev->irq = 0; | ||
1395 | } | ||
1238 | 1396 | ||
1239 | dev_set_name(&viodev->dev, "%x", *unit_address); | ||
1240 | viodev->name = of_node->name; | 1397 | viodev->name = of_node->name; |
1241 | viodev->type = of_node->type; | ||
1242 | viodev->unit_address = *unit_address; | ||
1243 | viodev->dev.of_node = of_node_get(of_node); | 1398 | viodev->dev.of_node = of_node_get(of_node); |
1244 | 1399 | ||
1245 | if (firmware_has_feature(FW_FEATURE_CMO)) | 1400 | if (firmware_has_feature(FW_FEATURE_CMO)) |
@@ -1267,16 +1422,51 @@ struct vio_dev *vio_register_device_node(struct device_node *of_node) | |||
1267 | } | 1422 | } |
1268 | 1423 | ||
1269 | return viodev; | 1424 | return viodev; |
1425 | |||
1426 | out: /* Use this exit point for any return prior to device_register */ | ||
1427 | kfree(viodev); | ||
1428 | |||
1429 | return NULL; | ||
1270 | } | 1430 | } |
1271 | EXPORT_SYMBOL(vio_register_device_node); | 1431 | EXPORT_SYMBOL(vio_register_device_node); |
1272 | 1432 | ||
1433 | /* | ||
1434 | * vio_bus_scan_for_devices - Scan OF and register each child device | ||
1435 | * @root_name - OF node name for the root of the subtree to search. | ||
1436 | * This must be non-NULL | ||
1437 | * | ||
1438 | * Starting from the root node provide, register the device node for | ||
1439 | * each child beneath the root. | ||
1440 | */ | ||
1441 | static void vio_bus_scan_register_devices(char *root_name) | ||
1442 | { | ||
1443 | struct device_node *node_root, *node_child; | ||
1444 | |||
1445 | if (!root_name) | ||
1446 | return; | ||
1447 | |||
1448 | node_root = of_find_node_by_name(NULL, root_name); | ||
1449 | if (node_root) { | ||
1450 | |||
1451 | /* | ||
1452 | * Create struct vio_devices for each virtual device in | ||
1453 | * the device tree. Drivers will associate with them later. | ||
1454 | */ | ||
1455 | node_child = of_get_next_child(node_root, NULL); | ||
1456 | while (node_child) { | ||
1457 | vio_register_device_node(node_child); | ||
1458 | node_child = of_get_next_child(node_root, node_child); | ||
1459 | } | ||
1460 | of_node_put(node_root); | ||
1461 | } | ||
1462 | } | ||
1463 | |||
1273 | /** | 1464 | /** |
1274 | * vio_bus_init: - Initialize the virtual IO bus | 1465 | * vio_bus_init: - Initialize the virtual IO bus |
1275 | */ | 1466 | */ |
1276 | static int __init vio_bus_init(void) | 1467 | static int __init vio_bus_init(void) |
1277 | { | 1468 | { |
1278 | int err; | 1469 | int err; |
1279 | struct device_node *node_vroot; | ||
1280 | 1470 | ||
1281 | if (firmware_has_feature(FW_FEATURE_CMO)) | 1471 | if (firmware_has_feature(FW_FEATURE_CMO)) |
1282 | vio_cmo_sysfs_init(); | 1472 | vio_cmo_sysfs_init(); |
@@ -1301,19 +1491,8 @@ static int __init vio_bus_init(void) | |||
1301 | if (firmware_has_feature(FW_FEATURE_CMO)) | 1491 | if (firmware_has_feature(FW_FEATURE_CMO)) |
1302 | vio_cmo_bus_init(); | 1492 | vio_cmo_bus_init(); |
1303 | 1493 | ||
1304 | node_vroot = of_find_node_by_name(NULL, "vdevice"); | 1494 | vio_bus_scan_register_devices("vdevice"); |
1305 | if (node_vroot) { | 1495 | vio_bus_scan_register_devices("ibm,platform-facilities"); |
1306 | struct device_node *of_node; | ||
1307 | |||
1308 | /* | ||
1309 | * Create struct vio_devices for each virtual device in | ||
1310 | * the device tree. Drivers will associate with them later. | ||
1311 | */ | ||
1312 | for (of_node = node_vroot->child; of_node != NULL; | ||
1313 | of_node = of_node->sibling) | ||
1314 | vio_register_device_node(of_node); | ||
1315 | of_node_put(node_vroot); | ||
1316 | } | ||
1317 | 1496 | ||
1318 | return 0; | 1497 | return 0; |
1319 | } | 1498 | } |
@@ -1436,12 +1615,28 @@ struct vio_dev *vio_find_node(struct device_node *vnode) | |||
1436 | { | 1615 | { |
1437 | const uint32_t *unit_address; | 1616 | const uint32_t *unit_address; |
1438 | char kobj_name[20]; | 1617 | char kobj_name[20]; |
1618 | struct device_node *vnode_parent; | ||
1619 | const char *dev_type; | ||
1620 | |||
1621 | vnode_parent = of_get_parent(vnode); | ||
1622 | if (!vnode_parent) | ||
1623 | return NULL; | ||
1624 | |||
1625 | dev_type = of_get_property(vnode_parent, "device_type", NULL); | ||
1626 | of_node_put(vnode_parent); | ||
1627 | if (!dev_type) | ||
1628 | return NULL; | ||
1439 | 1629 | ||
1440 | /* construct the kobject name from the device node */ | 1630 | /* construct the kobject name from the device node */ |
1441 | unit_address = of_get_property(vnode, "reg", NULL); | 1631 | if (!strcmp(dev_type, "vdevice")) { |
1442 | if (!unit_address) | 1632 | unit_address = of_get_property(vnode, "reg", NULL); |
1633 | if (!unit_address) | ||
1634 | return NULL; | ||
1635 | snprintf(kobj_name, sizeof(kobj_name), "%x", *unit_address); | ||
1636 | } else if (!strcmp(dev_type, "ibm,platform-facilities")) | ||
1637 | snprintf(kobj_name, sizeof(kobj_name), "%s", vnode->name); | ||
1638 | else | ||
1443 | return NULL; | 1639 | return NULL; |
1444 | snprintf(kobj_name, sizeof(kobj_name), "%x", *unit_address); | ||
1445 | 1640 | ||
1446 | return vio_find_name(kobj_name); | 1641 | return vio_find_name(kobj_name); |
1447 | } | 1642 | } |