diff options
Diffstat (limited to 'arch/powerpc/kernel')
32 files changed, 1681 insertions, 2103 deletions
diff --git a/arch/powerpc/kernel/Makefile b/arch/powerpc/kernel/Makefile index 3e779f07f21b..42c42ecad00c 100644 --- a/arch/powerpc/kernel/Makefile +++ b/arch/powerpc/kernel/Makefile | |||
| @@ -12,7 +12,8 @@ endif | |||
| 12 | 12 | ||
| 13 | obj-y := semaphore.o cputable.o ptrace.o syscalls.o \ | 13 | obj-y := semaphore.o cputable.o ptrace.o syscalls.o \ |
| 14 | irq.o align.o signal_32.o pmc.o vdso.o \ | 14 | irq.o align.o signal_32.o pmc.o vdso.o \ |
| 15 | init_task.o process.o systbl.o idle.o | 15 | init_task.o process.o systbl.o idle.o \ |
| 16 | signal.o | ||
| 16 | obj-y += vdso32/ | 17 | obj-y += vdso32/ |
| 17 | obj-$(CONFIG_PPC64) += setup_64.o binfmt_elf32.o sys_ppc32.o \ | 18 | obj-$(CONFIG_PPC64) += setup_64.o binfmt_elf32.o sys_ppc32.o \ |
| 18 | signal_64.o ptrace32.o \ | 19 | signal_64.o ptrace32.o \ |
| @@ -65,9 +66,9 @@ obj-$(CONFIG_PPC_UDBG_16550) += legacy_serial.o udbg_16550.o | |||
| 65 | module-$(CONFIG_PPC64) += module_64.o | 66 | module-$(CONFIG_PPC64) += module_64.o |
| 66 | obj-$(CONFIG_MODULES) += $(module-y) | 67 | obj-$(CONFIG_MODULES) += $(module-y) |
| 67 | 68 | ||
| 68 | pci64-$(CONFIG_PPC64) += pci_64.o pci_dn.o | 69 | pci64-$(CONFIG_PPC64) += pci_64.o pci_dn.o isa-bridge.o |
| 69 | pci32-$(CONFIG_PPC32) := pci_32.o | 70 | pci32-$(CONFIG_PPC32) := pci_32.o |
| 70 | obj-$(CONFIG_PCI) += $(pci64-y) $(pci32-y) | 71 | obj-$(CONFIG_PCI) += $(pci64-y) $(pci32-y) pci-common.o |
| 71 | obj-$(CONFIG_PCI_MSI) += msi.o | 72 | obj-$(CONFIG_PCI_MSI) += msi.o |
| 72 | kexec-$(CONFIG_PPC64) := machine_kexec_64.o | 73 | kexec-$(CONFIG_PPC64) := machine_kexec_64.o |
| 73 | kexec-$(CONFIG_PPC32) := machine_kexec_32.o | 74 | kexec-$(CONFIG_PPC32) := machine_kexec_32.o |
diff --git a/arch/powerpc/kernel/cputable.c b/arch/powerpc/kernel/cputable.c index b2b5d664d328..b1f8000952f3 100644 --- a/arch/powerpc/kernel/cputable.c +++ b/arch/powerpc/kernel/cputable.c | |||
| @@ -294,6 +294,21 @@ static struct cpu_spec cpu_specs[] = { | |||
| 294 | .oprofile_mmcra_sipr = MMCRA_SIPR, | 294 | .oprofile_mmcra_sipr = MMCRA_SIPR, |
| 295 | .platform = "power5", | 295 | .platform = "power5", |
| 296 | }, | 296 | }, |
| 297 | { /* Power5++ */ | ||
| 298 | .pvr_mask = 0xffffff00, | ||
| 299 | .pvr_value = 0x003b0300, | ||
| 300 | .cpu_name = "POWER5+ (gs)", | ||
| 301 | .cpu_features = CPU_FTRS_POWER5, | ||
| 302 | .cpu_user_features = COMMON_USER_POWER5_PLUS, | ||
| 303 | .icache_bsize = 128, | ||
| 304 | .dcache_bsize = 128, | ||
| 305 | .num_pmcs = 6, | ||
| 306 | .oprofile_cpu_type = "ppc64/power5++", | ||
| 307 | .oprofile_type = PPC_OPROFILE_POWER4, | ||
| 308 | .oprofile_mmcra_sihv = MMCRA_SIHV, | ||
| 309 | .oprofile_mmcra_sipr = MMCRA_SIPR, | ||
| 310 | .platform = "power5+", | ||
| 311 | }, | ||
| 297 | { /* Power5 GS */ | 312 | { /* Power5 GS */ |
| 298 | .pvr_mask = 0xffff0000, | 313 | .pvr_mask = 0xffff0000, |
| 299 | .pvr_value = 0x003b0000, | 314 | .pvr_value = 0x003b0000, |
| @@ -1178,8 +1193,8 @@ static struct cpu_spec cpu_specs[] = { | |||
| 1178 | .platform = "ppc440", | 1193 | .platform = "ppc440", |
| 1179 | }, | 1194 | }, |
| 1180 | { /* 440SP Rev. A */ | 1195 | { /* 440SP Rev. A */ |
| 1181 | .pvr_mask = 0xff000fff, | 1196 | .pvr_mask = 0xfff00fff, |
| 1182 | .pvr_value = 0x53000891, | 1197 | .pvr_value = 0x53200891, |
| 1183 | .cpu_name = "440SP Rev. A", | 1198 | .cpu_name = "440SP Rev. A", |
| 1184 | .cpu_features = CPU_FTRS_44X, | 1199 | .cpu_features = CPU_FTRS_44X, |
| 1185 | .cpu_user_features = COMMON_USER_BOOKE, | 1200 | .cpu_user_features = COMMON_USER_BOOKE, |
| @@ -1188,9 +1203,19 @@ static struct cpu_spec cpu_specs[] = { | |||
| 1188 | .platform = "ppc440", | 1203 | .platform = "ppc440", |
| 1189 | }, | 1204 | }, |
| 1190 | { /* 440SPe Rev. A */ | 1205 | { /* 440SPe Rev. A */ |
| 1191 | .pvr_mask = 0xff000fff, | 1206 | .pvr_mask = 0xfff00fff, |
| 1192 | .pvr_value = 0x53000890, | 1207 | .pvr_value = 0x53400890, |
| 1193 | .cpu_name = "440SPe Rev. A", | 1208 | .cpu_name = "440SPe Rev. A", |
| 1209 | .cpu_features = CPU_FTRS_44X, | ||
| 1210 | .cpu_user_features = COMMON_USER_BOOKE, | ||
| 1211 | .icache_bsize = 32, | ||
| 1212 | .dcache_bsize = 32, | ||
| 1213 | .platform = "ppc440", | ||
| 1214 | }, | ||
| 1215 | { /* 440SPe Rev. B */ | ||
| 1216 | .pvr_mask = 0xfff00fff, | ||
| 1217 | .pvr_value = 0x53400891, | ||
| 1218 | .cpu_name = "440SPe Rev. B", | ||
| 1194 | .cpu_features = CPU_FTRS_44X, | 1219 | .cpu_features = CPU_FTRS_44X, |
| 1195 | .cpu_user_features = COMMON_USER_BOOKE, | 1220 | .cpu_user_features = COMMON_USER_BOOKE, |
| 1196 | .icache_bsize = 32, | 1221 | .icache_bsize = 32, |
diff --git a/arch/powerpc/kernel/head_32.S b/arch/powerpc/kernel/head_32.S index c897203198b1..7d73a13450b0 100644 --- a/arch/powerpc/kernel/head_32.S +++ b/arch/powerpc/kernel/head_32.S | |||
| @@ -9,7 +9,6 @@ | |||
| 9 | * rewritten by Paul Mackerras. | 9 | * rewritten by Paul Mackerras. |
| 10 | * Copyright (C) 1996 Paul Mackerras. | 10 | * Copyright (C) 1996 Paul Mackerras. |
| 11 | * MPC8xx modifications Copyright (C) 1997 Dan Malek (dmalek@jlc.net). | 11 | * MPC8xx modifications Copyright (C) 1997 Dan Malek (dmalek@jlc.net). |
| 12 | * Amiga/APUS changes by Jesper Skov (jskov@cygnus.co.uk). | ||
| 13 | * | 12 | * |
| 14 | * This file contains the low-level support and setup for the | 13 | * This file contains the low-level support and setup for the |
| 15 | * PowerPC platform, including trap and interrupt dispatch. | 14 | * PowerPC platform, including trap and interrupt dispatch. |
| @@ -32,10 +31,6 @@ | |||
| 32 | #include <asm/ppc_asm.h> | 31 | #include <asm/ppc_asm.h> |
| 33 | #include <asm/asm-offsets.h> | 32 | #include <asm/asm-offsets.h> |
| 34 | 33 | ||
| 35 | #ifdef CONFIG_APUS | ||
| 36 | #include <asm/amigappc.h> | ||
| 37 | #endif | ||
| 38 | |||
| 39 | /* 601 only have IBAT; cr0.eq is set on 601 when using this macro */ | 34 | /* 601 only have IBAT; cr0.eq is set on 601 when using this macro */ |
| 40 | #define LOAD_BAT(n, reg, RA, RB) \ | 35 | #define LOAD_BAT(n, reg, RA, RB) \ |
| 41 | /* see the comment for clear_bats() -- Cort */ \ | 36 | /* see the comment for clear_bats() -- Cort */ \ |
| @@ -92,11 +87,6 @@ _start: | |||
| 92 | * r4: virtual address of boot_infos_t | 87 | * r4: virtual address of boot_infos_t |
| 93 | * r5: 0 | 88 | * r5: 0 |
| 94 | * | 89 | * |
| 95 | * APUS | ||
| 96 | * r3: 'APUS' | ||
| 97 | * r4: physical address of memory base | ||
| 98 | * Linux/m68k style BootInfo structure at &_end. | ||
| 99 | * | ||
| 100 | * PREP | 90 | * PREP |
| 101 | * This is jumped to on prep systems right after the kernel is relocated | 91 | * This is jumped to on prep systems right after the kernel is relocated |
| 102 | * to its proper place in memory by the boot loader. The expected layout | 92 | * to its proper place in memory by the boot loader. The expected layout |
| @@ -150,14 +140,6 @@ __start: | |||
| 150 | */ | 140 | */ |
| 151 | bl early_init | 141 | bl early_init |
| 152 | 142 | ||
| 153 | #ifdef CONFIG_APUS | ||
| 154 | /* On APUS the __va/__pa constants need to be set to the correct | ||
| 155 | * values before continuing. | ||
| 156 | */ | ||
| 157 | mr r4,r30 | ||
| 158 | bl fix_mem_constants | ||
| 159 | #endif /* CONFIG_APUS */ | ||
| 160 | |||
| 161 | /* Switch MMU off, clear BATs and flush TLB. At this point, r3 contains | 143 | /* Switch MMU off, clear BATs and flush TLB. At this point, r3 contains |
| 162 | * the physical address we are running at, returned by early_init() | 144 | * the physical address we are running at, returned by early_init() |
| 163 | */ | 145 | */ |
| @@ -167,7 +149,7 @@ __after_mmu_off: | |||
| 167 | bl flush_tlbs | 149 | bl flush_tlbs |
| 168 | 150 | ||
| 169 | bl initial_bats | 151 | bl initial_bats |
| 170 | #if !defined(CONFIG_APUS) && defined(CONFIG_BOOTX_TEXT) | 152 | #if defined(CONFIG_BOOTX_TEXT) |
| 171 | bl setup_disp_bat | 153 | bl setup_disp_bat |
| 172 | #endif | 154 | #endif |
| 173 | 155 | ||
| @@ -183,7 +165,6 @@ __after_mmu_off: | |||
| 183 | #endif /* CONFIG_6xx */ | 165 | #endif /* CONFIG_6xx */ |
| 184 | 166 | ||
| 185 | 167 | ||
| 186 | #ifndef CONFIG_APUS | ||
| 187 | /* | 168 | /* |
| 188 | * We need to run with _start at physical address 0. | 169 | * We need to run with _start at physical address 0. |
| 189 | * On CHRP, we are loaded at 0x10000 since OF on CHRP uses | 170 | * On CHRP, we are loaded at 0x10000 since OF on CHRP uses |
| @@ -196,7 +177,6 @@ __after_mmu_off: | |||
| 196 | addis r4,r3,KERNELBASE@h /* current address of _start */ | 177 | addis r4,r3,KERNELBASE@h /* current address of _start */ |
| 197 | cmpwi 0,r4,0 /* are we already running at 0? */ | 178 | cmpwi 0,r4,0 /* are we already running at 0? */ |
| 198 | bne relocate_kernel | 179 | bne relocate_kernel |
| 199 | #endif /* CONFIG_APUS */ | ||
| 200 | /* | 180 | /* |
| 201 | * we now have the 1st 16M of ram mapped with the bats. | 181 | * we now have the 1st 16M of ram mapped with the bats. |
| 202 | * prep needs the mmu to be turned on here, but pmac already has it on. | 182 | * prep needs the mmu to be turned on here, but pmac already has it on. |
| @@ -881,85 +861,6 @@ _GLOBAL(copy_and_flush) | |||
| 881 | addi r6,r6,4 | 861 | addi r6,r6,4 |
| 882 | blr | 862 | blr |
| 883 | 863 | ||
| 884 | #ifdef CONFIG_APUS | ||
| 885 | /* | ||
| 886 | * On APUS the physical base address of the kernel is not known at compile | ||
| 887 | * time, which means the __pa/__va constants used are incorrect. In the | ||
| 888 | * __init section is recorded the virtual addresses of instructions using | ||
| 889 | * these constants, so all that has to be done is fix these before | ||
| 890 | * continuing the kernel boot. | ||
| 891 | * | ||
| 892 | * r4 = The physical address of the kernel base. | ||
| 893 | */ | ||
| 894 | fix_mem_constants: | ||
| 895 | mr r10,r4 | ||
| 896 | addis r10,r10,-KERNELBASE@h /* virt_to_phys constant */ | ||
| 897 | neg r11,r10 /* phys_to_virt constant */ | ||
| 898 | |||
| 899 | lis r12,__vtop_table_begin@h | ||
| 900 | ori r12,r12,__vtop_table_begin@l | ||
| 901 | add r12,r12,r10 /* table begin phys address */ | ||
| 902 | lis r13,__vtop_table_end@h | ||
| 903 | ori r13,r13,__vtop_table_end@l | ||
| 904 | add r13,r13,r10 /* table end phys address */ | ||
| 905 | subi r12,r12,4 | ||
| 906 | subi r13,r13,4 | ||
| 907 | 1: lwzu r14,4(r12) /* virt address of instruction */ | ||
| 908 | add r14,r14,r10 /* phys address of instruction */ | ||
| 909 | lwz r15,0(r14) /* instruction, now insert top */ | ||
| 910 | rlwimi r15,r10,16,16,31 /* half of vp const in low half */ | ||
| 911 | stw r15,0(r14) /* of instruction and restore. */ | ||
| 912 | dcbst r0,r14 /* write it to memory */ | ||
| 913 | sync | ||
| 914 | icbi r0,r14 /* flush the icache line */ | ||
| 915 | cmpw r12,r13 | ||
| 916 | bne 1b | ||
| 917 | sync /* additional sync needed on g4 */ | ||
| 918 | isync | ||
| 919 | |||
| 920 | /* | ||
| 921 | * Map the memory where the exception handlers will | ||
| 922 | * be copied to when hash constants have been patched. | ||
| 923 | */ | ||
| 924 | #ifdef CONFIG_APUS_FAST_EXCEPT | ||
| 925 | lis r8,0xfff0 | ||
| 926 | #else | ||
| 927 | lis r8,0 | ||
| 928 | #endif | ||
| 929 | ori r8,r8,0x2 /* 128KB, supervisor */ | ||
| 930 | mtspr SPRN_DBAT3U,r8 | ||
| 931 | mtspr SPRN_DBAT3L,r8 | ||
| 932 | |||
| 933 | lis r12,__ptov_table_begin@h | ||
| 934 | ori r12,r12,__ptov_table_begin@l | ||
| 935 | add r12,r12,r10 /* table begin phys address */ | ||
| 936 | lis r13,__ptov_table_end@h | ||
| 937 | ori r13,r13,__ptov_table_end@l | ||
| 938 | add r13,r13,r10 /* table end phys address */ | ||
| 939 | subi r12,r12,4 | ||
| 940 | subi r13,r13,4 | ||
| 941 | 1: lwzu r14,4(r12) /* virt address of instruction */ | ||
| 942 | add r14,r14,r10 /* phys address of instruction */ | ||
| 943 | lwz r15,0(r14) /* instruction, now insert top */ | ||
| 944 | rlwimi r15,r11,16,16,31 /* half of pv const in low half*/ | ||
| 945 | stw r15,0(r14) /* of instruction and restore. */ | ||
| 946 | dcbst r0,r14 /* write it to memory */ | ||
| 947 | sync | ||
| 948 | icbi r0,r14 /* flush the icache line */ | ||
| 949 | cmpw r12,r13 | ||
| 950 | bne 1b | ||
| 951 | |||
| 952 | sync /* additional sync needed on g4 */ | ||
| 953 | isync /* No speculative loading until now */ | ||
| 954 | blr | ||
| 955 | |||
| 956 | /*********************************************************************** | ||
| 957 | * Please note that on APUS the exception handlers are located at the | ||
| 958 | * physical address 0xfff0000. For this reason, the exception handlers | ||
| 959 | * cannot use relative branches to access the code below. | ||
| 960 | ***********************************************************************/ | ||
| 961 | #endif /* CONFIG_APUS */ | ||
| 962 | |||
| 963 | #ifdef CONFIG_SMP | 864 | #ifdef CONFIG_SMP |
| 964 | #ifdef CONFIG_GEMINI | 865 | #ifdef CONFIG_GEMINI |
| 965 | .globl __secondary_start_gemini | 866 | .globl __secondary_start_gemini |
| @@ -1135,19 +1036,6 @@ start_here: | |||
| 1135 | bl __save_cpu_setup | 1036 | bl __save_cpu_setup |
| 1136 | bl MMU_init | 1037 | bl MMU_init |
| 1137 | 1038 | ||
| 1138 | #ifdef CONFIG_APUS | ||
| 1139 | /* Copy exception code to exception vector base on APUS. */ | ||
| 1140 | lis r4,KERNELBASE@h | ||
| 1141 | #ifdef CONFIG_APUS_FAST_EXCEPT | ||
| 1142 | lis r3,0xfff0 /* Copy to 0xfff00000 */ | ||
| 1143 | #else | ||
| 1144 | lis r3,0 /* Copy to 0x00000000 */ | ||
| 1145 | #endif | ||
| 1146 | li r5,0x4000 /* # bytes of memory to copy */ | ||
| 1147 | li r6,0 | ||
| 1148 | bl copy_and_flush /* copy the first 0x4000 bytes */ | ||
| 1149 | #endif /* CONFIG_APUS */ | ||
| 1150 | |||
| 1151 | /* | 1039 | /* |
| 1152 | * Go back to running unmapped so we can load up new values | 1040 | * Go back to running unmapped so we can load up new values |
| 1153 | * for SDR1 (hash table pointer) and the segment registers | 1041 | * for SDR1 (hash table pointer) and the segment registers |
| @@ -1324,11 +1212,7 @@ initial_bats: | |||
| 1324 | #else | 1212 | #else |
| 1325 | ori r8,r8,2 /* R/W access */ | 1213 | ori r8,r8,2 /* R/W access */ |
| 1326 | #endif /* CONFIG_SMP */ | 1214 | #endif /* CONFIG_SMP */ |
| 1327 | #ifdef CONFIG_APUS | ||
| 1328 | ori r11,r11,BL_8M<<2|0x2 /* set up 8MB BAT registers for 604 */ | ||
| 1329 | #else | ||
| 1330 | ori r11,r11,BL_256M<<2|0x2 /* set up BAT registers for 604 */ | 1215 | ori r11,r11,BL_256M<<2|0x2 /* set up BAT registers for 604 */ |
| 1331 | #endif /* CONFIG_APUS */ | ||
| 1332 | 1216 | ||
| 1333 | mtspr SPRN_DBAT0L,r8 /* N.B. 6xx (not 601) have valid */ | 1217 | mtspr SPRN_DBAT0L,r8 /* N.B. 6xx (not 601) have valid */ |
| 1334 | mtspr SPRN_DBAT0U,r11 /* bit in upper BAT register */ | 1218 | mtspr SPRN_DBAT0U,r11 /* bit in upper BAT register */ |
| @@ -1338,7 +1222,7 @@ initial_bats: | |||
| 1338 | blr | 1222 | blr |
| 1339 | 1223 | ||
| 1340 | 1224 | ||
| 1341 | #if !defined(CONFIG_APUS) && defined(CONFIG_BOOTX_TEXT) | 1225 | #ifdef CONFIG_BOOTX_TEXT |
| 1342 | setup_disp_bat: | 1226 | setup_disp_bat: |
| 1343 | /* | 1227 | /* |
| 1344 | * setup the display bat prepared for us in prom.c | 1228 | * setup the display bat prepared for us in prom.c |
| @@ -1362,7 +1246,7 @@ setup_disp_bat: | |||
| 1362 | 1: mtspr SPRN_IBAT3L,r8 | 1246 | 1: mtspr SPRN_IBAT3L,r8 |
| 1363 | mtspr SPRN_IBAT3U,r11 | 1247 | mtspr SPRN_IBAT3U,r11 |
| 1364 | blr | 1248 | blr |
| 1365 | #endif /* !defined(CONFIG_APUS) && defined(CONFIG_BOOTX_TEXT) */ | 1249 | #endif /* CONFIG_BOOTX_TEXT */ |
| 1366 | 1250 | ||
| 1367 | #ifdef CONFIG_8260 | 1251 | #ifdef CONFIG_8260 |
| 1368 | /* Jump into the system reset for the rom. | 1252 | /* Jump into the system reset for the rom. |
diff --git a/arch/powerpc/kernel/head_64.S b/arch/powerpc/kernel/head_64.S index 1111fcec7673..8cdd48ea4391 100644 --- a/arch/powerpc/kernel/head_64.S +++ b/arch/powerpc/kernel/head_64.S | |||
| @@ -103,8 +103,8 @@ __secondary_hold_acknowledge: | |||
| 103 | 103 | ||
| 104 | . = 0x60 | 104 | . = 0x60 |
| 105 | /* | 105 | /* |
| 106 | * The following code is used on pSeries to hold secondary processors | 106 | * The following code is used to hold secondary processors |
| 107 | * in a spin loop after they have been freed from OpenFirmware, but | 107 | * in a spin loop after they have entered the kernel, but |
| 108 | * before the bulk of the kernel has been relocated. This code | 108 | * before the bulk of the kernel has been relocated. This code |
| 109 | * is relocated to physical address 0x60 before prom_init is run. | 109 | * is relocated to physical address 0x60 before prom_init is run. |
| 110 | * All of it must fit below the first exception vector at 0x100. | 110 | * All of it must fit below the first exception vector at 0x100. |
diff --git a/arch/powerpc/kernel/io.c b/arch/powerpc/kernel/io.c index 34ae11494ddc..e31aca9208eb 100644 --- a/arch/powerpc/kernel/io.c +++ b/arch/powerpc/kernel/io.c | |||
| @@ -35,7 +35,7 @@ void _insb(const volatile u8 __iomem *port, void *buf, long count) | |||
| 35 | asm volatile("sync"); | 35 | asm volatile("sync"); |
| 36 | do { | 36 | do { |
| 37 | tmp = *port; | 37 | tmp = *port; |
| 38 | asm volatile("eieio"); | 38 | eieio(); |
| 39 | *tbuf++ = tmp; | 39 | *tbuf++ = tmp; |
| 40 | } while (--count != 0); | 40 | } while (--count != 0); |
| 41 | asm volatile("twi 0,%0,0; isync" : : "r" (tmp)); | 41 | asm volatile("twi 0,%0,0; isync" : : "r" (tmp)); |
| @@ -66,7 +66,7 @@ void _insw_ns(const volatile u16 __iomem *port, void *buf, long count) | |||
| 66 | asm volatile("sync"); | 66 | asm volatile("sync"); |
| 67 | do { | 67 | do { |
| 68 | tmp = *port; | 68 | tmp = *port; |
| 69 | asm volatile("eieio"); | 69 | eieio(); |
| 70 | *tbuf++ = tmp; | 70 | *tbuf++ = tmp; |
| 71 | } while (--count != 0); | 71 | } while (--count != 0); |
| 72 | asm volatile("twi 0,%0,0; isync" : : "r" (tmp)); | 72 | asm volatile("twi 0,%0,0; isync" : : "r" (tmp)); |
| @@ -97,7 +97,7 @@ void _insl_ns(const volatile u32 __iomem *port, void *buf, long count) | |||
| 97 | asm volatile("sync"); | 97 | asm volatile("sync"); |
| 98 | do { | 98 | do { |
| 99 | tmp = *port; | 99 | tmp = *port; |
| 100 | asm volatile("eieio"); | 100 | eieio(); |
| 101 | *tbuf++ = tmp; | 101 | *tbuf++ = tmp; |
| 102 | } while (--count != 0); | 102 | } while (--count != 0); |
| 103 | asm volatile("twi 0,%0,0; isync" : : "r" (tmp)); | 103 | asm volatile("twi 0,%0,0; isync" : : "r" (tmp)); |
| @@ -155,21 +155,21 @@ void _memcpy_fromio(void *dest, const volatile void __iomem *src, | |||
| 155 | __asm__ __volatile__ ("sync" : : : "memory"); | 155 | __asm__ __volatile__ ("sync" : : : "memory"); |
| 156 | while(n && (!IO_CHECK_ALIGN(vsrc, 4) || !IO_CHECK_ALIGN(dest, 4))) { | 156 | while(n && (!IO_CHECK_ALIGN(vsrc, 4) || !IO_CHECK_ALIGN(dest, 4))) { |
| 157 | *((u8 *)dest) = *((volatile u8 *)vsrc); | 157 | *((u8 *)dest) = *((volatile u8 *)vsrc); |
| 158 | __asm__ __volatile__ ("eieio" : : : "memory"); | 158 | eieio(); |
| 159 | vsrc++; | 159 | vsrc++; |
| 160 | dest++; | 160 | dest++; |
| 161 | n--; | 161 | n--; |
| 162 | } | 162 | } |
| 163 | while(n > 4) { | 163 | while(n > 4) { |
| 164 | *((u32 *)dest) = *((volatile u32 *)vsrc); | 164 | *((u32 *)dest) = *((volatile u32 *)vsrc); |
| 165 | __asm__ __volatile__ ("eieio" : : : "memory"); | 165 | eieio(); |
| 166 | vsrc += 4; | 166 | vsrc += 4; |
| 167 | dest += 4; | 167 | dest += 4; |
| 168 | n -= 4; | 168 | n -= 4; |
| 169 | } | 169 | } |
| 170 | while(n) { | 170 | while(n) { |
| 171 | *((u8 *)dest) = *((volatile u8 *)vsrc); | 171 | *((u8 *)dest) = *((volatile u8 *)vsrc); |
| 172 | __asm__ __volatile__ ("eieio" : : : "memory"); | 172 | eieio(); |
| 173 | vsrc++; | 173 | vsrc++; |
| 174 | dest++; | 174 | dest++; |
| 175 | n--; | 175 | n--; |
diff --git a/arch/powerpc/kernel/irq.c b/arch/powerpc/kernel/irq.c index c2b84c64db20..2fc87862146c 100644 --- a/arch/powerpc/kernel/irq.c +++ b/arch/powerpc/kernel/irq.c | |||
| @@ -7,7 +7,6 @@ | |||
| 7 | * Copyright (C) 1996-2001 Cort Dougan | 7 | * Copyright (C) 1996-2001 Cort Dougan |
| 8 | * Adapted for Power Macintosh by Paul Mackerras | 8 | * Adapted for Power Macintosh by Paul Mackerras |
| 9 | * Copyright (C) 1996 Paul Mackerras (paulus@cs.anu.edu.au) | 9 | * Copyright (C) 1996 Paul Mackerras (paulus@cs.anu.edu.au) |
| 10 | * Amiga/APUS changes by Jesper Skov (jskov@cygnus.co.uk). | ||
| 11 | * | 10 | * |
| 12 | * This program is free software; you can redistribute it and/or | 11 | * This program is free software; you can redistribute it and/or |
| 13 | * modify it under the terms of the GNU General Public License | 12 | * modify it under the terms of the GNU General Public License |
| @@ -337,7 +336,8 @@ void do_IRQ(struct pt_regs *regs) | |||
| 337 | 336 | ||
| 338 | void __init init_IRQ(void) | 337 | void __init init_IRQ(void) |
| 339 | { | 338 | { |
| 340 | ppc_md.init_IRQ(); | 339 | if (ppc_md.init_IRQ) |
| 340 | ppc_md.init_IRQ(); | ||
| 341 | #ifdef CONFIG_PPC64 | 341 | #ifdef CONFIG_PPC64 |
| 342 | irq_ctx_init(); | 342 | irq_ctx_init(); |
| 343 | #endif | 343 | #endif |
| @@ -597,6 +597,49 @@ static void irq_radix_rdunlock(unsigned long flags) | |||
| 597 | local_irq_restore(flags); | 597 | local_irq_restore(flags); |
| 598 | } | 598 | } |
| 599 | 599 | ||
| 600 | static int irq_setup_virq(struct irq_host *host, unsigned int virq, | ||
| 601 | irq_hw_number_t hwirq) | ||
| 602 | { | ||
| 603 | /* Clear IRQ_NOREQUEST flag */ | ||
| 604 | get_irq_desc(virq)->status &= ~IRQ_NOREQUEST; | ||
| 605 | |||
| 606 | /* map it */ | ||
| 607 | smp_wmb(); | ||
| 608 | irq_map[virq].hwirq = hwirq; | ||
| 609 | smp_mb(); | ||
| 610 | |||
| 611 | if (host->ops->map(host, virq, hwirq)) { | ||
| 612 | pr_debug("irq: -> mapping failed, freeing\n"); | ||
| 613 | irq_free_virt(virq, 1); | ||
| 614 | return -1; | ||
| 615 | } | ||
| 616 | |||
| 617 | return 0; | ||
| 618 | } | ||
| 619 | |||
| 620 | unsigned int irq_create_direct_mapping(struct irq_host *host) | ||
| 621 | { | ||
| 622 | unsigned int virq; | ||
| 623 | |||
| 624 | if (host == NULL) | ||
| 625 | host = irq_default_host; | ||
| 626 | |||
| 627 | BUG_ON(host == NULL); | ||
| 628 | WARN_ON(host->revmap_type != IRQ_HOST_MAP_NOMAP); | ||
| 629 | |||
| 630 | virq = irq_alloc_virt(host, 1, 0); | ||
| 631 | if (virq == NO_IRQ) { | ||
| 632 | pr_debug("irq: create_direct virq allocation failed\n"); | ||
| 633 | return NO_IRQ; | ||
| 634 | } | ||
| 635 | |||
| 636 | pr_debug("irq: create_direct obtained virq %d\n", virq); | ||
| 637 | |||
| 638 | if (irq_setup_virq(host, virq, virq)) | ||
| 639 | return NO_IRQ; | ||
| 640 | |||
| 641 | return virq; | ||
| 642 | } | ||
| 600 | 643 | ||
| 601 | unsigned int irq_create_mapping(struct irq_host *host, | 644 | unsigned int irq_create_mapping(struct irq_host *host, |
| 602 | irq_hw_number_t hwirq) | 645 | irq_hw_number_t hwirq) |
| @@ -645,18 +688,9 @@ unsigned int irq_create_mapping(struct irq_host *host, | |||
| 645 | } | 688 | } |
| 646 | pr_debug("irq: -> obtained virq %d\n", virq); | 689 | pr_debug("irq: -> obtained virq %d\n", virq); |
| 647 | 690 | ||
| 648 | /* Clear IRQ_NOREQUEST flag */ | 691 | if (irq_setup_virq(host, virq, hwirq)) |
| 649 | get_irq_desc(virq)->status &= ~IRQ_NOREQUEST; | ||
| 650 | |||
| 651 | /* map it */ | ||
| 652 | smp_wmb(); | ||
| 653 | irq_map[virq].hwirq = hwirq; | ||
| 654 | smp_mb(); | ||
| 655 | if (host->ops->map(host, virq, hwirq)) { | ||
| 656 | pr_debug("irq: -> mapping failed, freeing\n"); | ||
| 657 | irq_free_virt(virq, 1); | ||
| 658 | return NO_IRQ; | 692 | return NO_IRQ; |
| 659 | } | 693 | |
| 660 | return virq; | 694 | return virq; |
| 661 | } | 695 | } |
| 662 | EXPORT_SYMBOL_GPL(irq_create_mapping); | 696 | EXPORT_SYMBOL_GPL(irq_create_mapping); |
diff --git a/arch/powerpc/kernel/isa-bridge.c b/arch/powerpc/kernel/isa-bridge.c new file mode 100644 index 000000000000..f0f49d1be3d5 --- /dev/null +++ b/arch/powerpc/kernel/isa-bridge.c | |||
| @@ -0,0 +1,271 @@ | |||
| 1 | /* | ||
| 2 | * Routines for tracking a legacy ISA bridge | ||
| 3 | * | ||
| 4 | * Copyrigh 2007 Benjamin Herrenschmidt <benh@kernel.crashing.org>, IBM Corp. | ||
| 5 | * | ||
| 6 | * Some bits and pieces moved over from pci_64.c | ||
| 7 | * | ||
| 8 | * Copyrigh 2003 Anton Blanchard <anton@au.ibm.com>, IBM Corp. | ||
| 9 | * | ||
| 10 | * This program is free software; you can redistribute it and/or | ||
| 11 | * modify it under the terms of the GNU General Public License | ||
| 12 | * as published by the Free Software Foundation; either version | ||
| 13 | * 2 of the License, or (at your option) any later version. | ||
| 14 | */ | ||
| 15 | |||
| 16 | #define DEBUG | ||
| 17 | |||
| 18 | #include <linux/kernel.h> | ||
| 19 | #include <linux/pci.h> | ||
| 20 | #include <linux/string.h> | ||
| 21 | #include <linux/init.h> | ||
| 22 | #include <linux/mm.h> | ||
| 23 | #include <linux/notifier.h> | ||
| 24 | |||
| 25 | #include <asm/processor.h> | ||
| 26 | #include <asm/io.h> | ||
| 27 | #include <asm/prom.h> | ||
| 28 | #include <asm/pci-bridge.h> | ||
| 29 | #include <asm/machdep.h> | ||
| 30 | #include <asm/ppc-pci.h> | ||
| 31 | #include <asm/firmware.h> | ||
| 32 | |||
| 33 | unsigned long isa_io_base; /* NULL if no ISA bus */ | ||
| 34 | EXPORT_SYMBOL(isa_io_base); | ||
| 35 | |||
| 36 | /* Cached ISA bridge dev. */ | ||
| 37 | static struct device_node *isa_bridge_devnode; | ||
| 38 | struct pci_dev *isa_bridge_pcidev; | ||
| 39 | EXPORT_SYMBOL_GPL(isa_bridge_pcidev); | ||
| 40 | |||
| 41 | #define ISA_SPACE_MASK 0x1 | ||
| 42 | #define ISA_SPACE_IO 0x1 | ||
| 43 | |||
| 44 | static void __devinit pci_process_ISA_OF_ranges(struct device_node *isa_node, | ||
| 45 | unsigned long phb_io_base_phys) | ||
| 46 | { | ||
| 47 | /* We should get some saner parsing here and remove these structs */ | ||
| 48 | struct pci_address { | ||
| 49 | u32 a_hi; | ||
| 50 | u32 a_mid; | ||
| 51 | u32 a_lo; | ||
| 52 | }; | ||
| 53 | |||
| 54 | struct isa_address { | ||
| 55 | u32 a_hi; | ||
| 56 | u32 a_lo; | ||
| 57 | }; | ||
| 58 | |||
| 59 | struct isa_range { | ||
| 60 | struct isa_address isa_addr; | ||
| 61 | struct pci_address pci_addr; | ||
| 62 | unsigned int size; | ||
| 63 | }; | ||
| 64 | |||
| 65 | const struct isa_range *range; | ||
| 66 | unsigned long pci_addr; | ||
| 67 | unsigned int isa_addr; | ||
| 68 | unsigned int size; | ||
| 69 | int rlen = 0; | ||
| 70 | |||
| 71 | range = of_get_property(isa_node, "ranges", &rlen); | ||
| 72 | if (range == NULL || (rlen < sizeof(struct isa_range))) | ||
| 73 | goto inval_range; | ||
| 74 | |||
| 75 | /* From "ISA Binding to 1275" | ||
| 76 | * The ranges property is laid out as an array of elements, | ||
| 77 | * each of which comprises: | ||
| 78 | * cells 0 - 1: an ISA address | ||
| 79 | * cells 2 - 4: a PCI address | ||
| 80 | * (size depending on dev->n_addr_cells) | ||
| 81 | * cell 5: the size of the range | ||
| 82 | */ | ||
| 83 | if ((range->isa_addr.a_hi && ISA_SPACE_MASK) != ISA_SPACE_IO) { | ||
| 84 | range++; | ||
| 85 | rlen -= sizeof(struct isa_range); | ||
| 86 | if (rlen < sizeof(struct isa_range)) | ||
| 87 | goto inval_range; | ||
| 88 | } | ||
| 89 | if ((range->isa_addr.a_hi && ISA_SPACE_MASK) != ISA_SPACE_IO) | ||
| 90 | goto inval_range; | ||
| 91 | |||
| 92 | isa_addr = range->isa_addr.a_lo; | ||
| 93 | pci_addr = (unsigned long) range->pci_addr.a_mid << 32 | | ||
| 94 | range->pci_addr.a_lo; | ||
| 95 | |||
| 96 | /* Assume these are both zero. Note: We could fix that and | ||
| 97 | * do a proper parsing instead ... oh well, that will do for | ||
| 98 | * now as nobody uses fancy mappings for ISA bridges | ||
| 99 | */ | ||
| 100 | if ((pci_addr != 0) || (isa_addr != 0)) { | ||
| 101 | printk(KERN_ERR "unexpected isa to pci mapping: %s\n", | ||
| 102 | __FUNCTION__); | ||
| 103 | return; | ||
| 104 | } | ||
| 105 | |||
| 106 | /* Align size and make sure it's cropped to 64K */ | ||
| 107 | size = PAGE_ALIGN(range->size); | ||
| 108 | if (size > 0x10000) | ||
| 109 | size = 0x10000; | ||
| 110 | |||
| 111 | printk(KERN_ERR "no ISA IO ranges or unexpected isa range," | ||
| 112 | "mapping 64k\n"); | ||
| 113 | |||
| 114 | __ioremap_at(phb_io_base_phys, (void *)ISA_IO_BASE, | ||
| 115 | size, _PAGE_NO_CACHE|_PAGE_GUARDED); | ||
| 116 | return; | ||
| 117 | |||
| 118 | inval_range: | ||
| 119 | printk(KERN_ERR "no ISA IO ranges or unexpected isa range," | ||
| 120 | "mapping 64k\n"); | ||
| 121 | __ioremap_at(phb_io_base_phys, (void *)ISA_IO_BASE, | ||
| 122 | 0x10000, _PAGE_NO_CACHE|_PAGE_GUARDED); | ||
| 123 | } | ||
| 124 | |||
| 125 | |||
| 126 | /** | ||
| 127 | * isa_bridge_find_early - Find and map the ISA IO space early before | ||
| 128 | * main PCI discovery. This is optionally called by | ||
| 129 | * the arch code when adding PCI PHBs to get early | ||
| 130 | * access to ISA IO ports | ||
| 131 | */ | ||
| 132 | void __init isa_bridge_find_early(struct pci_controller *hose) | ||
| 133 | { | ||
| 134 | struct device_node *np, *parent = NULL, *tmp; | ||
| 135 | |||
| 136 | /* If we already have an ISA bridge, bail off */ | ||
| 137 | if (isa_bridge_devnode != NULL) | ||
| 138 | return; | ||
| 139 | |||
| 140 | /* For each "isa" node in the system. Note : we do a search by | ||
| 141 | * type and not by name. It might be better to do by name but that's | ||
| 142 | * what the code used to do and I don't want to break too much at | ||
| 143 | * once. We can look into changing that separately | ||
| 144 | */ | ||
| 145 | for_each_node_by_type(np, "isa") { | ||
| 146 | /* Look for our hose being a parent */ | ||
| 147 | for (parent = of_get_parent(np); parent;) { | ||
| 148 | if (parent == hose->arch_data) { | ||
| 149 | of_node_put(parent); | ||
| 150 | break; | ||
| 151 | } | ||
| 152 | tmp = parent; | ||
| 153 | parent = of_get_parent(parent); | ||
| 154 | of_node_put(tmp); | ||
| 155 | } | ||
| 156 | if (parent != NULL) | ||
| 157 | break; | ||
| 158 | } | ||
| 159 | if (np == NULL) | ||
| 160 | return; | ||
| 161 | isa_bridge_devnode = np; | ||
| 162 | |||
| 163 | /* Now parse the "ranges" property and setup the ISA mapping */ | ||
| 164 | pci_process_ISA_OF_ranges(np, hose->io_base_phys); | ||
| 165 | |||
| 166 | /* Set the global ISA io base to indicate we have an ISA bridge */ | ||
| 167 | isa_io_base = ISA_IO_BASE; | ||
| 168 | |||
| 169 | pr_debug("ISA bridge (early) is %s\n", np->full_name); | ||
| 170 | } | ||
| 171 | |||
| 172 | /** | ||
| 173 | * isa_bridge_find_late - Find and map the ISA IO space upon discovery of | ||
| 174 | * a new ISA bridge | ||
| 175 | */ | ||
| 176 | static void __devinit isa_bridge_find_late(struct pci_dev *pdev, | ||
| 177 | struct device_node *devnode) | ||
| 178 | { | ||
| 179 | struct pci_controller *hose = pci_bus_to_host(pdev->bus); | ||
| 180 | |||
| 181 | /* Store ISA device node and PCI device */ | ||
| 182 | isa_bridge_devnode = of_node_get(devnode); | ||
| 183 | isa_bridge_pcidev = pdev; | ||
| 184 | |||
| 185 | /* Now parse the "ranges" property and setup the ISA mapping */ | ||
| 186 | pci_process_ISA_OF_ranges(devnode, hose->io_base_phys); | ||
| 187 | |||
| 188 | /* Set the global ISA io base to indicate we have an ISA bridge */ | ||
| 189 | isa_io_base = ISA_IO_BASE; | ||
| 190 | |||
| 191 | pr_debug("ISA bridge (late) is %s on %s\n", | ||
| 192 | devnode->full_name, pci_name(pdev)); | ||
| 193 | } | ||
| 194 | |||
| 195 | /** | ||
| 196 | * isa_bridge_remove - Remove/unmap an ISA bridge | ||
| 197 | */ | ||
| 198 | static void isa_bridge_remove(void) | ||
| 199 | { | ||
| 200 | pr_debug("ISA bridge removed !\n"); | ||
| 201 | |||
| 202 | /* Clear the global ISA io base to indicate that we have no more | ||
| 203 | * ISA bridge. Note that drivers don't quite handle that, though | ||
| 204 | * we should probably do something about it. But do we ever really | ||
| 205 | * have ISA bridges being removed on machines using legacy devices ? | ||
| 206 | */ | ||
| 207 | isa_io_base = ISA_IO_BASE; | ||
| 208 | |||
| 209 | /* Clear references to the bridge */ | ||
| 210 | of_node_put(isa_bridge_devnode); | ||
| 211 | isa_bridge_devnode = NULL; | ||
| 212 | isa_bridge_pcidev = NULL; | ||
| 213 | |||
| 214 | /* Unmap the ISA area */ | ||
| 215 | __iounmap_at((void *)ISA_IO_BASE, 0x10000); | ||
| 216 | } | ||
| 217 | |||
| 218 | /** | ||
| 219 | * isa_bridge_notify - Get notified of PCI devices addition/removal | ||
| 220 | */ | ||
| 221 | static int __devinit isa_bridge_notify(struct notifier_block *nb, | ||
| 222 | unsigned long action, void *data) | ||
| 223 | { | ||
| 224 | struct device *dev = data; | ||
| 225 | struct pci_dev *pdev = to_pci_dev(dev); | ||
| 226 | struct device_node *devnode = pci_device_to_OF_node(pdev); | ||
| 227 | |||
| 228 | switch(action) { | ||
| 229 | case BUS_NOTIFY_ADD_DEVICE: | ||
| 230 | /* Check if we have an early ISA device, without PCI dev */ | ||
| 231 | if (isa_bridge_devnode && isa_bridge_devnode == devnode && | ||
| 232 | !isa_bridge_pcidev) { | ||
| 233 | pr_debug("ISA bridge PCI attached: %s\n", | ||
| 234 | pci_name(pdev)); | ||
| 235 | isa_bridge_pcidev = pdev; | ||
| 236 | } | ||
| 237 | |||
| 238 | /* Check if we have no ISA device, and this happens to be one, | ||
| 239 | * register it as such if it has an OF device | ||
| 240 | */ | ||
| 241 | if (!isa_bridge_devnode && devnode && devnode->type && | ||
| 242 | !strcmp(devnode->type, "isa")) | ||
| 243 | isa_bridge_find_late(pdev, devnode); | ||
| 244 | |||
| 245 | return 0; | ||
| 246 | case BUS_NOTIFY_DEL_DEVICE: | ||
| 247 | /* Check if this our existing ISA device */ | ||
| 248 | if (pdev == isa_bridge_pcidev || | ||
| 249 | (devnode && devnode == isa_bridge_devnode)) | ||
| 250 | isa_bridge_remove(); | ||
| 251 | return 0; | ||
| 252 | } | ||
| 253 | return 0; | ||
| 254 | } | ||
| 255 | |||
| 256 | static struct notifier_block isa_bridge_notifier = { | ||
| 257 | .notifier_call = isa_bridge_notify | ||
| 258 | }; | ||
| 259 | |||
| 260 | /** | ||
| 261 | * isa_bridge_init - register to be notified of ISA bridge addition/removal | ||
| 262 | * | ||
| 263 | */ | ||
| 264 | static int __init isa_bridge_init(void) | ||
| 265 | { | ||
| 266 | if (firmware_has_feature(FW_FEATURE_ISERIES)) | ||
| 267 | return 0; | ||
| 268 | bus_register_notifier(&pci_bus_type, &isa_bridge_notifier); | ||
| 269 | return 0; | ||
| 270 | } | ||
| 271 | arch_initcall(isa_bridge_init); | ||
diff --git a/arch/powerpc/kernel/misc_32.S b/arch/powerpc/kernel/misc_32.S index 98decf8ebff4..e708ab7ca9e8 100644 --- a/arch/powerpc/kernel/misc_32.S +++ b/arch/powerpc/kernel/misc_32.S | |||
| @@ -392,7 +392,7 @@ BEGIN_FTR_SECTION | |||
| 392 | mtspr SPRN_L1CSR0,r3 | 392 | mtspr SPRN_L1CSR0,r3 |
| 393 | isync | 393 | isync |
| 394 | blr | 394 | blr |
| 395 | END_FTR_SECTION_IFCLR(CPU_FTR_SPLIT_ID_CACHE) | 395 | END_FTR_SECTION_IFSET(CPU_FTR_UNIFIED_ID_CACHE) |
| 396 | mfspr r3,SPRN_L1CSR1 | 396 | mfspr r3,SPRN_L1CSR1 |
| 397 | ori r3,r3,L1CSR1_ICFI|L1CSR1_ICLFR | 397 | ori r3,r3,L1CSR1_ICFI|L1CSR1_ICLFR |
| 398 | mtspr SPRN_L1CSR1,r3 | 398 | mtspr SPRN_L1CSR1,r3 |
| @@ -419,7 +419,7 @@ END_FTR_SECTION_IFCLR(CPU_FTR_SPLIT_ID_CACHE) | |||
| 419 | _GLOBAL(__flush_icache_range) | 419 | _GLOBAL(__flush_icache_range) |
| 420 | BEGIN_FTR_SECTION | 420 | BEGIN_FTR_SECTION |
| 421 | blr /* for 601, do nothing */ | 421 | blr /* for 601, do nothing */ |
| 422 | END_FTR_SECTION_IFCLR(CPU_FTR_SPLIT_ID_CACHE) | 422 | END_FTR_SECTION_IFSET(CPU_FTR_COHERENT_ICACHE) |
| 423 | li r5,L1_CACHE_BYTES-1 | 423 | li r5,L1_CACHE_BYTES-1 |
| 424 | andc r3,r3,r5 | 424 | andc r3,r3,r5 |
| 425 | subf r4,r3,r4 | 425 | subf r4,r3,r4 |
| @@ -514,8 +514,8 @@ _GLOBAL(invalidate_dcache_range) | |||
| 514 | */ | 514 | */ |
| 515 | _GLOBAL(__flush_dcache_icache) | 515 | _GLOBAL(__flush_dcache_icache) |
| 516 | BEGIN_FTR_SECTION | 516 | BEGIN_FTR_SECTION |
| 517 | blr /* for 601, do nothing */ | 517 | blr |
| 518 | END_FTR_SECTION_IFCLR(CPU_FTR_SPLIT_ID_CACHE) | 518 | END_FTR_SECTION_IFSET(CPU_FTR_COHERENT_ICACHE) |
| 519 | rlwinm r3,r3,0,0,19 /* Get page base address */ | 519 | rlwinm r3,r3,0,0,19 /* Get page base address */ |
| 520 | li r4,4096/L1_CACHE_BYTES /* Number of lines in a page */ | 520 | li r4,4096/L1_CACHE_BYTES /* Number of lines in a page */ |
| 521 | mtctr r4 | 521 | mtctr r4 |
| @@ -543,7 +543,7 @@ END_FTR_SECTION_IFCLR(CPU_FTR_SPLIT_ID_CACHE) | |||
| 543 | _GLOBAL(__flush_dcache_icache_phys) | 543 | _GLOBAL(__flush_dcache_icache_phys) |
| 544 | BEGIN_FTR_SECTION | 544 | BEGIN_FTR_SECTION |
| 545 | blr /* for 601, do nothing */ | 545 | blr /* for 601, do nothing */ |
| 546 | END_FTR_SECTION_IFCLR(CPU_FTR_SPLIT_ID_CACHE) | 546 | END_FTR_SECTION_IFSET(CPU_FTR_COHERENT_ICACHE) |
| 547 | mfmsr r10 | 547 | mfmsr r10 |
| 548 | rlwinm r0,r10,0,28,26 /* clear DR */ | 548 | rlwinm r0,r10,0,28,26 /* clear DR */ |
| 549 | mtmsr r0 | 549 | mtmsr r0 |
diff --git a/arch/powerpc/kernel/misc_64.S b/arch/powerpc/kernel/misc_64.S index 519861da0423..bbb3ba54c51c 100644 --- a/arch/powerpc/kernel/misc_64.S +++ b/arch/powerpc/kernel/misc_64.S | |||
| @@ -646,6 +646,19 @@ _GLOBAL(kexec_sequence) | |||
| 646 | /* turn off mmu */ | 646 | /* turn off mmu */ |
| 647 | bl real_mode | 647 | bl real_mode |
| 648 | 648 | ||
| 649 | /* copy 0x100 bytes starting at start to 0 */ | ||
| 650 | li r3,0 | ||
| 651 | mr r4,r30 /* start, aka phys mem offset */ | ||
| 652 | li r5,0x100 | ||
| 653 | li r6,0 | ||
| 654 | bl .copy_and_flush /* (dest, src, copy limit, start offset) */ | ||
| 655 | 1: /* assume normal blr return */ | ||
| 656 | |||
| 657 | /* release other cpus to the new kernel secondary start at 0x60 */ | ||
| 658 | mflr r5 | ||
| 659 | li r6,1 | ||
| 660 | stw r6,kexec_flag-1b(5) | ||
| 661 | |||
| 649 | /* clear out hardware hash page table and tlb */ | 662 | /* clear out hardware hash page table and tlb */ |
| 650 | ld r5,0(r27) /* deref function descriptor */ | 663 | ld r5,0(r27) /* deref function descriptor */ |
| 651 | mtctr r5 | 664 | mtctr r5 |
| @@ -676,19 +689,6 @@ _GLOBAL(kexec_sequence) | |||
| 676 | * are the boot cpu ????? | 689 | * are the boot cpu ????? |
| 677 | * other device tree differences (prop sizes, va vs pa, etc)... | 690 | * other device tree differences (prop sizes, va vs pa, etc)... |
| 678 | */ | 691 | */ |
| 679 | |||
| 680 | /* copy 0x100 bytes starting at start to 0 */ | ||
| 681 | li r3,0 | ||
| 682 | mr r4,r30 | ||
| 683 | li r5,0x100 | ||
| 684 | li r6,0 | ||
| 685 | bl .copy_and_flush /* (dest, src, copy limit, start offset) */ | ||
| 686 | 1: /* assume normal blr return */ | ||
| 687 | |||
| 688 | /* release other cpus to the new kernel secondary start at 0x60 */ | ||
| 689 | mflr r5 | ||
| 690 | li r6,1 | ||
| 691 | stw r6,kexec_flag-1b(5) | ||
| 692 | mr r3,r25 # my phys cpu | 692 | mr r3,r25 # my phys cpu |
| 693 | mr r4,r30 # start, aka phys mem offset | 693 | mr r4,r30 # start, aka phys mem offset |
| 694 | mtlr 4 | 694 | mtlr 4 |
diff --git a/arch/powerpc/kernel/of_platform.c b/arch/powerpc/kernel/of_platform.c index d454f61c9c7c..9536ed7f247c 100644 --- a/arch/powerpc/kernel/of_platform.c +++ b/arch/powerpc/kernel/of_platform.c | |||
| @@ -427,14 +427,6 @@ static int __devinit of_pci_phb_probe(struct of_device *dev, | |||
| 427 | /* Process "ranges" property */ | 427 | /* Process "ranges" property */ |
| 428 | pci_process_bridge_OF_ranges(phb, dev->node, 0); | 428 | pci_process_bridge_OF_ranges(phb, dev->node, 0); |
| 429 | 429 | ||
| 430 | /* Setup IO space. We use the non-dynamic version of that code here, | ||
| 431 | * which doesn't quite support unplugging. Next kernel release will | ||
| 432 | * have a better fix for this. | ||
| 433 | * Note also that we don't do ISA, this will also be fixed with a | ||
| 434 | * more massive rework. | ||
| 435 | */ | ||
| 436 | pci_setup_phb_io(phb, pci_io_base == 0); | ||
| 437 | |||
| 438 | /* Init pci_dn data structures */ | 430 | /* Init pci_dn data structures */ |
| 439 | pci_devs_phb_init_dynamic(phb); | 431 | pci_devs_phb_init_dynamic(phb); |
| 440 | 432 | ||
diff --git a/arch/powerpc/kernel/pci-common.c b/arch/powerpc/kernel/pci-common.c new file mode 100644 index 000000000000..faf5ef3e90d0 --- /dev/null +++ b/arch/powerpc/kernel/pci-common.c | |||
| @@ -0,0 +1,454 @@ | |||
| 1 | /* | ||
| 2 | * Contains common pci routines for ALL ppc platform | ||
| 3 | * (based on pci_32.c and pci_64.c) | ||
| 4 | * | ||
| 5 | * Port for PPC64 David Engebretsen, IBM Corp. | ||
| 6 | * Contains common pci routines for ppc64 platform, pSeries and iSeries brands. | ||
| 7 | * | ||
| 8 | * Copyright (C) 2003 Anton Blanchard <anton@au.ibm.com>, IBM | ||
| 9 | * Rework, based on alpha PCI code. | ||
| 10 | * | ||
| 11 | * Common pmac/prep/chrp pci routines. -- Cort | ||
| 12 | * | ||
| 13 | * This program is free software; you can redistribute it and/or | ||
| 14 | * modify it under the terms of the GNU General Public License | ||
| 15 | * as published by the Free Software Foundation; either version | ||
| 16 | * 2 of the License, or (at your option) any later version. | ||
| 17 | */ | ||
| 18 | |||
| 19 | #undef DEBUG | ||
| 20 | |||
| 21 | #include <linux/kernel.h> | ||
| 22 | #include <linux/pci.h> | ||
| 23 | #include <linux/string.h> | ||
| 24 | #include <linux/init.h> | ||
| 25 | #include <linux/bootmem.h> | ||
| 26 | #include <linux/mm.h> | ||
| 27 | #include <linux/list.h> | ||
| 28 | #include <linux/syscalls.h> | ||
| 29 | #include <linux/irq.h> | ||
| 30 | #include <linux/vmalloc.h> | ||
| 31 | |||
| 32 | #include <asm/processor.h> | ||
| 33 | #include <asm/io.h> | ||
| 34 | #include <asm/prom.h> | ||
| 35 | #include <asm/pci-bridge.h> | ||
| 36 | #include <asm/byteorder.h> | ||
| 37 | #include <asm/machdep.h> | ||
| 38 | #include <asm/ppc-pci.h> | ||
| 39 | #include <asm/firmware.h> | ||
| 40 | |||
| 41 | #ifdef DEBUG | ||
| 42 | #include <asm/udbg.h> | ||
| 43 | #define DBG(fmt...) printk(fmt) | ||
| 44 | #else | ||
| 45 | #define DBG(fmt...) | ||
| 46 | #endif | ||
| 47 | |||
| 48 | static DEFINE_SPINLOCK(hose_spinlock); | ||
| 49 | |||
| 50 | /* XXX kill that some day ... */ | ||
| 51 | int global_phb_number; /* Global phb counter */ | ||
| 52 | |||
| 53 | extern struct list_head hose_list; | ||
| 54 | |||
| 55 | /* | ||
| 56 | * pci_controller(phb) initialized common variables. | ||
| 57 | */ | ||
| 58 | static void __devinit pci_setup_pci_controller(struct pci_controller *hose) | ||
| 59 | { | ||
| 60 | memset(hose, 0, sizeof(struct pci_controller)); | ||
| 61 | |||
| 62 | spin_lock(&hose_spinlock); | ||
| 63 | hose->global_number = global_phb_number++; | ||
| 64 | list_add_tail(&hose->list_node, &hose_list); | ||
| 65 | spin_unlock(&hose_spinlock); | ||
| 66 | } | ||
| 67 | |||
| 68 | struct pci_controller * pcibios_alloc_controller(struct device_node *dev) | ||
| 69 | { | ||
| 70 | struct pci_controller *phb; | ||
| 71 | |||
| 72 | if (mem_init_done) | ||
| 73 | phb = kmalloc(sizeof(struct pci_controller), GFP_KERNEL); | ||
| 74 | else | ||
| 75 | phb = alloc_bootmem(sizeof (struct pci_controller)); | ||
| 76 | if (phb == NULL) | ||
| 77 | return NULL; | ||
| 78 | pci_setup_pci_controller(phb); | ||
| 79 | phb->arch_data = dev; | ||
| 80 | phb->is_dynamic = mem_init_done; | ||
| 81 | #ifdef CONFIG_PPC64 | ||
| 82 | if (dev) { | ||
| 83 | int nid = of_node_to_nid(dev); | ||
| 84 | |||
| 85 | if (nid < 0 || !node_online(nid)) | ||
| 86 | nid = -1; | ||
| 87 | |||
| 88 | PHB_SET_NODE(phb, nid); | ||
| 89 | } | ||
| 90 | #endif | ||
| 91 | return phb; | ||
| 92 | } | ||
| 93 | |||
| 94 | void pcibios_free_controller(struct pci_controller *phb) | ||
| 95 | { | ||
| 96 | spin_lock(&hose_spinlock); | ||
| 97 | list_del(&phb->list_node); | ||
| 98 | spin_unlock(&hose_spinlock); | ||
| 99 | |||
| 100 | if (phb->is_dynamic) | ||
| 101 | kfree(phb); | ||
| 102 | } | ||
| 103 | |||
| 104 | /* | ||
| 105 | * Return the domain number for this bus. | ||
| 106 | */ | ||
| 107 | int pci_domain_nr(struct pci_bus *bus) | ||
| 108 | { | ||
| 109 | if (firmware_has_feature(FW_FEATURE_ISERIES)) | ||
| 110 | return 0; | ||
| 111 | else { | ||
| 112 | struct pci_controller *hose = pci_bus_to_host(bus); | ||
| 113 | |||
| 114 | return hose->global_number; | ||
| 115 | } | ||
| 116 | } | ||
| 117 | |||
| 118 | EXPORT_SYMBOL(pci_domain_nr); | ||
| 119 | |||
| 120 | #ifdef CONFIG_PPC_OF | ||
| 121 | |||
| 122 | /* This routine is meant to be used early during boot, when the | ||
| 123 | * PCI bus numbers have not yet been assigned, and you need to | ||
| 124 | * issue PCI config cycles to an OF device. | ||
| 125 | * It could also be used to "fix" RTAS config cycles if you want | ||
| 126 | * to set pci_assign_all_buses to 1 and still use RTAS for PCI | ||
| 127 | * config cycles. | ||
| 128 | */ | ||
| 129 | struct pci_controller* pci_find_hose_for_OF_device(struct device_node* node) | ||
| 130 | { | ||
| 131 | if (!have_of) | ||
| 132 | return NULL; | ||
| 133 | while(node) { | ||
| 134 | struct pci_controller *hose, *tmp; | ||
| 135 | list_for_each_entry_safe(hose, tmp, &hose_list, list_node) | ||
| 136 | if (hose->arch_data == node) | ||
| 137 | return hose; | ||
| 138 | node = node->parent; | ||
| 139 | } | ||
| 140 | return NULL; | ||
| 141 | } | ||
| 142 | |||
| 143 | static ssize_t pci_show_devspec(struct device *dev, | ||
| 144 | struct device_attribute *attr, char *buf) | ||
| 145 | { | ||
| 146 | struct pci_dev *pdev; | ||
| 147 | struct device_node *np; | ||
| 148 | |||
| 149 | pdev = to_pci_dev (dev); | ||
| 150 | np = pci_device_to_OF_node(pdev); | ||
| 151 | if (np == NULL || np->full_name == NULL) | ||
| 152 | return 0; | ||
| 153 | return sprintf(buf, "%s", np->full_name); | ||
| 154 | } | ||
| 155 | static DEVICE_ATTR(devspec, S_IRUGO, pci_show_devspec, NULL); | ||
| 156 | #endif /* CONFIG_PPC_OF */ | ||
| 157 | |||
| 158 | /* Add sysfs properties */ | ||
| 159 | void pcibios_add_platform_entries(struct pci_dev *pdev) | ||
| 160 | { | ||
| 161 | #ifdef CONFIG_PPC_OF | ||
| 162 | device_create_file(&pdev->dev, &dev_attr_devspec); | ||
| 163 | #endif /* CONFIG_PPC_OF */ | ||
| 164 | } | ||
| 165 | |||
| 166 | char __init *pcibios_setup(char *str) | ||
| 167 | { | ||
| 168 | return str; | ||
| 169 | } | ||
| 170 | |||
| 171 | /* | ||
| 172 | * Reads the interrupt pin to determine if interrupt is use by card. | ||
| 173 | * If the interrupt is used, then gets the interrupt line from the | ||
| 174 | * openfirmware and sets it in the pci_dev and pci_config line. | ||
| 175 | */ | ||
| 176 | int pci_read_irq_line(struct pci_dev *pci_dev) | ||
| 177 | { | ||
| 178 | struct of_irq oirq; | ||
| 179 | unsigned int virq; | ||
| 180 | |||
| 181 | DBG("Try to map irq for %s...\n", pci_name(pci_dev)); | ||
| 182 | |||
| 183 | #ifdef DEBUG | ||
| 184 | memset(&oirq, 0xff, sizeof(oirq)); | ||
| 185 | #endif | ||
| 186 | /* Try to get a mapping from the device-tree */ | ||
| 187 | if (of_irq_map_pci(pci_dev, &oirq)) { | ||
| 188 | u8 line, pin; | ||
| 189 | |||
| 190 | /* If that fails, lets fallback to what is in the config | ||
| 191 | * space and map that through the default controller. We | ||
| 192 | * also set the type to level low since that's what PCI | ||
| 193 | * interrupts are. If your platform does differently, then | ||
| 194 | * either provide a proper interrupt tree or don't use this | ||
| 195 | * function. | ||
| 196 | */ | ||
| 197 | if (pci_read_config_byte(pci_dev, PCI_INTERRUPT_PIN, &pin)) | ||
| 198 | return -1; | ||
| 199 | if (pin == 0) | ||
| 200 | return -1; | ||
| 201 | if (pci_read_config_byte(pci_dev, PCI_INTERRUPT_LINE, &line) || | ||
| 202 | line == 0xff) { | ||
| 203 | return -1; | ||
| 204 | } | ||
| 205 | DBG(" -> no map ! Using irq line %d from PCI config\n", line); | ||
| 206 | |||
| 207 | virq = irq_create_mapping(NULL, line); | ||
| 208 | if (virq != NO_IRQ) | ||
| 209 | set_irq_type(virq, IRQ_TYPE_LEVEL_LOW); | ||
| 210 | } else { | ||
| 211 | DBG(" -> got one, spec %d cells (0x%08x 0x%08x...) on %s\n", | ||
| 212 | oirq.size, oirq.specifier[0], oirq.specifier[1], | ||
| 213 | oirq.controller->full_name); | ||
| 214 | |||
| 215 | virq = irq_create_of_mapping(oirq.controller, oirq.specifier, | ||
| 216 | oirq.size); | ||
| 217 | } | ||
| 218 | if(virq == NO_IRQ) { | ||
| 219 | DBG(" -> failed to map !\n"); | ||
| 220 | return -1; | ||
| 221 | } | ||
| 222 | |||
| 223 | DBG(" -> mapped to linux irq %d\n", virq); | ||
| 224 | |||
| 225 | pci_dev->irq = virq; | ||
| 226 | |||
| 227 | return 0; | ||
| 228 | } | ||
| 229 | EXPORT_SYMBOL(pci_read_irq_line); | ||
| 230 | |||
| 231 | /* | ||
| 232 | * Platform support for /proc/bus/pci/X/Y mmap()s, | ||
| 233 | * modelled on the sparc64 implementation by Dave Miller. | ||
| 234 | * -- paulus. | ||
| 235 | */ | ||
| 236 | |||
| 237 | /* | ||
| 238 | * Adjust vm_pgoff of VMA such that it is the physical page offset | ||
| 239 | * corresponding to the 32-bit pci bus offset for DEV requested by the user. | ||
| 240 | * | ||
| 241 | * Basically, the user finds the base address for his device which he wishes | ||
| 242 | * to mmap. They read the 32-bit value from the config space base register, | ||
| 243 | * add whatever PAGE_SIZE multiple offset they wish, and feed this into the | ||
| 244 | * offset parameter of mmap on /proc/bus/pci/XXX for that device. | ||
| 245 | * | ||
| 246 | * Returns negative error code on failure, zero on success. | ||
| 247 | */ | ||
| 248 | static struct resource *__pci_mmap_make_offset(struct pci_dev *dev, | ||
| 249 | resource_size_t *offset, | ||
| 250 | enum pci_mmap_state mmap_state) | ||
| 251 | { | ||
| 252 | struct pci_controller *hose = pci_bus_to_host(dev->bus); | ||
| 253 | unsigned long io_offset = 0; | ||
| 254 | int i, res_bit; | ||
| 255 | |||
| 256 | if (hose == 0) | ||
| 257 | return NULL; /* should never happen */ | ||
| 258 | |||
| 259 | /* If memory, add on the PCI bridge address offset */ | ||
| 260 | if (mmap_state == pci_mmap_mem) { | ||
| 261 | #if 0 /* See comment in pci_resource_to_user() for why this is disabled */ | ||
| 262 | *offset += hose->pci_mem_offset; | ||
| 263 | #endif | ||
| 264 | res_bit = IORESOURCE_MEM; | ||
| 265 | } else { | ||
| 266 | io_offset = (unsigned long)hose->io_base_virt - _IO_BASE; | ||
| 267 | *offset += io_offset; | ||
| 268 | res_bit = IORESOURCE_IO; | ||
| 269 | } | ||
| 270 | |||
| 271 | /* | ||
| 272 | * Check that the offset requested corresponds to one of the | ||
| 273 | * resources of the device. | ||
| 274 | */ | ||
| 275 | for (i = 0; i <= PCI_ROM_RESOURCE; i++) { | ||
| 276 | struct resource *rp = &dev->resource[i]; | ||
| 277 | int flags = rp->flags; | ||
| 278 | |||
| 279 | /* treat ROM as memory (should be already) */ | ||
| 280 | if (i == PCI_ROM_RESOURCE) | ||
| 281 | flags |= IORESOURCE_MEM; | ||
| 282 | |||
| 283 | /* Active and same type? */ | ||
| 284 | if ((flags & res_bit) == 0) | ||
| 285 | continue; | ||
| 286 | |||
| 287 | /* In the range of this resource? */ | ||
| 288 | if (*offset < (rp->start & PAGE_MASK) || *offset > rp->end) | ||
| 289 | continue; | ||
| 290 | |||
| 291 | /* found it! construct the final physical address */ | ||
| 292 | if (mmap_state == pci_mmap_io) | ||
| 293 | *offset += hose->io_base_phys - io_offset; | ||
| 294 | return rp; | ||
| 295 | } | ||
| 296 | |||
| 297 | return NULL; | ||
| 298 | } | ||
| 299 | |||
| 300 | /* | ||
| 301 | * Set vm_page_prot of VMA, as appropriate for this architecture, for a pci | ||
| 302 | * device mapping. | ||
| 303 | */ | ||
| 304 | static pgprot_t __pci_mmap_set_pgprot(struct pci_dev *dev, struct resource *rp, | ||
| 305 | pgprot_t protection, | ||
| 306 | enum pci_mmap_state mmap_state, | ||
| 307 | int write_combine) | ||
| 308 | { | ||
| 309 | unsigned long prot = pgprot_val(protection); | ||
| 310 | |||
| 311 | /* Write combine is always 0 on non-memory space mappings. On | ||
| 312 | * memory space, if the user didn't pass 1, we check for a | ||
| 313 | * "prefetchable" resource. This is a bit hackish, but we use | ||
| 314 | * this to workaround the inability of /sysfs to provide a write | ||
| 315 | * combine bit | ||
| 316 | */ | ||
| 317 | if (mmap_state != pci_mmap_mem) | ||
| 318 | write_combine = 0; | ||
| 319 | else if (write_combine == 0) { | ||
| 320 | if (rp->flags & IORESOURCE_PREFETCH) | ||
| 321 | write_combine = 1; | ||
| 322 | } | ||
| 323 | |||
| 324 | /* XXX would be nice to have a way to ask for write-through */ | ||
| 325 | prot |= _PAGE_NO_CACHE; | ||
| 326 | if (write_combine) | ||
| 327 | prot &= ~_PAGE_GUARDED; | ||
| 328 | else | ||
| 329 | prot |= _PAGE_GUARDED; | ||
| 330 | |||
| 331 | return __pgprot(prot); | ||
| 332 | } | ||
| 333 | |||
| 334 | /* | ||
| 335 | * This one is used by /dev/mem and fbdev who have no clue about the | ||
| 336 | * PCI device, it tries to find the PCI device first and calls the | ||
| 337 | * above routine | ||
| 338 | */ | ||
| 339 | pgprot_t pci_phys_mem_access_prot(struct file *file, | ||
| 340 | unsigned long pfn, | ||
| 341 | unsigned long size, | ||
| 342 | pgprot_t protection) | ||
| 343 | { | ||
| 344 | struct pci_dev *pdev = NULL; | ||
| 345 | struct resource *found = NULL; | ||
| 346 | unsigned long prot = pgprot_val(protection); | ||
| 347 | unsigned long offset = pfn << PAGE_SHIFT; | ||
| 348 | int i; | ||
| 349 | |||
| 350 | if (page_is_ram(pfn)) | ||
| 351 | return __pgprot(prot); | ||
| 352 | |||
| 353 | prot |= _PAGE_NO_CACHE | _PAGE_GUARDED; | ||
| 354 | |||
| 355 | for_each_pci_dev(pdev) { | ||
| 356 | for (i = 0; i <= PCI_ROM_RESOURCE; i++) { | ||
| 357 | struct resource *rp = &pdev->resource[i]; | ||
| 358 | int flags = rp->flags; | ||
| 359 | |||
| 360 | /* Active and same type? */ | ||
| 361 | if ((flags & IORESOURCE_MEM) == 0) | ||
| 362 | continue; | ||
| 363 | /* In the range of this resource? */ | ||
| 364 | if (offset < (rp->start & PAGE_MASK) || | ||
| 365 | offset > rp->end) | ||
| 366 | continue; | ||
| 367 | found = rp; | ||
| 368 | break; | ||
| 369 | } | ||
| 370 | if (found) | ||
| 371 | break; | ||
| 372 | } | ||
| 373 | if (found) { | ||
| 374 | if (found->flags & IORESOURCE_PREFETCH) | ||
| 375 | prot &= ~_PAGE_GUARDED; | ||
| 376 | pci_dev_put(pdev); | ||
| 377 | } | ||
| 378 | |||
| 379 | DBG("non-PCI map for %lx, prot: %lx\n", offset, prot); | ||
| 380 | |||
| 381 | return __pgprot(prot); | ||
| 382 | } | ||
| 383 | |||
| 384 | |||
| 385 | /* | ||
| 386 | * Perform the actual remap of the pages for a PCI device mapping, as | ||
| 387 | * appropriate for this architecture. The region in the process to map | ||
| 388 | * is described by vm_start and vm_end members of VMA, the base physical | ||
| 389 | * address is found in vm_pgoff. | ||
| 390 | * The pci device structure is provided so that architectures may make mapping | ||
| 391 | * decisions on a per-device or per-bus basis. | ||
| 392 | * | ||
| 393 | * Returns a negative error code on failure, zero on success. | ||
| 394 | */ | ||
| 395 | int pci_mmap_page_range(struct pci_dev *dev, struct vm_area_struct *vma, | ||
| 396 | enum pci_mmap_state mmap_state, int write_combine) | ||
| 397 | { | ||
| 398 | resource_size_t offset = vma->vm_pgoff << PAGE_SHIFT; | ||
| 399 | struct resource *rp; | ||
| 400 | int ret; | ||
| 401 | |||
| 402 | rp = __pci_mmap_make_offset(dev, &offset, mmap_state); | ||
| 403 | if (rp == NULL) | ||
| 404 | return -EINVAL; | ||
| 405 | |||
| 406 | vma->vm_pgoff = offset >> PAGE_SHIFT; | ||
| 407 | vma->vm_page_prot = __pci_mmap_set_pgprot(dev, rp, | ||
| 408 | vma->vm_page_prot, | ||
| 409 | mmap_state, write_combine); | ||
| 410 | |||
| 411 | ret = remap_pfn_range(vma, vma->vm_start, vma->vm_pgoff, | ||
| 412 | vma->vm_end - vma->vm_start, vma->vm_page_prot); | ||
| 413 | |||
| 414 | return ret; | ||
| 415 | } | ||
| 416 | |||
| 417 | void pci_resource_to_user(const struct pci_dev *dev, int bar, | ||
| 418 | const struct resource *rsrc, | ||
| 419 | resource_size_t *start, resource_size_t *end) | ||
| 420 | { | ||
| 421 | struct pci_controller *hose = pci_bus_to_host(dev->bus); | ||
| 422 | resource_size_t offset = 0; | ||
| 423 | |||
| 424 | if (hose == NULL) | ||
| 425 | return; | ||
| 426 | |||
| 427 | if (rsrc->flags & IORESOURCE_IO) | ||
| 428 | offset = (unsigned long)hose->io_base_virt - _IO_BASE; | ||
| 429 | |||
| 430 | /* We pass a fully fixed up address to userland for MMIO instead of | ||
| 431 | * a BAR value because X is lame and expects to be able to use that | ||
| 432 | * to pass to /dev/mem ! | ||
| 433 | * | ||
| 434 | * That means that we'll have potentially 64 bits values where some | ||
| 435 | * userland apps only expect 32 (like X itself since it thinks only | ||
| 436 | * Sparc has 64 bits MMIO) but if we don't do that, we break it on | ||
| 437 | * 32 bits CHRPs :-( | ||
| 438 | * | ||
| 439 | * Hopefully, the sysfs insterface is immune to that gunk. Once X | ||
| 440 | * has been fixed (and the fix spread enough), we can re-enable the | ||
| 441 | * 2 lines below and pass down a BAR value to userland. In that case | ||
| 442 | * we'll also have to re-enable the matching code in | ||
| 443 | * __pci_mmap_make_offset(). | ||
| 444 | * | ||
| 445 | * BenH. | ||
| 446 | */ | ||
| 447 | #if 0 | ||
| 448 | else if (rsrc->flags & IORESOURCE_MEM) | ||
| 449 | offset = hose->pci_mem_offset; | ||
| 450 | #endif | ||
| 451 | |||
| 452 | *start = rsrc->start - offset; | ||
| 453 | *end = rsrc->end - offset; | ||
| 454 | } | ||
diff --git a/arch/powerpc/kernel/pci_32.c b/arch/powerpc/kernel/pci_32.c index e66064b5093a..0adf077f3f3a 100644 --- a/arch/powerpc/kernel/pci_32.c +++ b/arch/powerpc/kernel/pci_32.c | |||
| @@ -55,8 +55,7 @@ static u8* pci_to_OF_bus_map; | |||
| 55 | */ | 55 | */ |
| 56 | int pci_assign_all_buses; | 56 | int pci_assign_all_buses; |
| 57 | 57 | ||
| 58 | struct pci_controller* hose_head; | 58 | LIST_HEAD(hose_list); |
| 59 | struct pci_controller** hose_tail = &hose_head; | ||
| 60 | 59 | ||
| 61 | static int pci_bus_count; | 60 | static int pci_bus_count; |
| 62 | 61 | ||
| @@ -573,58 +572,6 @@ pcibios_assign_resources(void) | |||
| 573 | } | 572 | } |
| 574 | } | 573 | } |
| 575 | 574 | ||
| 576 | |||
| 577 | int | ||
| 578 | pcibios_enable_resources(struct pci_dev *dev, int mask) | ||
| 579 | { | ||
| 580 | u16 cmd, old_cmd; | ||
| 581 | int idx; | ||
| 582 | struct resource *r; | ||
| 583 | |||
| 584 | pci_read_config_word(dev, PCI_COMMAND, &cmd); | ||
| 585 | old_cmd = cmd; | ||
| 586 | for (idx=0; idx<6; idx++) { | ||
| 587 | /* Only set up the requested stuff */ | ||
| 588 | if (!(mask & (1<<idx))) | ||
| 589 | continue; | ||
| 590 | |||
| 591 | r = &dev->resource[idx]; | ||
| 592 | if (r->flags & IORESOURCE_UNSET) { | ||
| 593 | printk(KERN_ERR "PCI: Device %s not available because of resource collisions\n", pci_name(dev)); | ||
| 594 | return -EINVAL; | ||
| 595 | } | ||
| 596 | if (r->flags & IORESOURCE_IO) | ||
| 597 | cmd |= PCI_COMMAND_IO; | ||
| 598 | if (r->flags & IORESOURCE_MEM) | ||
| 599 | cmd |= PCI_COMMAND_MEMORY; | ||
| 600 | } | ||
| 601 | if (dev->resource[PCI_ROM_RESOURCE].start) | ||
| 602 | cmd |= PCI_COMMAND_MEMORY; | ||
| 603 | if (cmd != old_cmd) { | ||
| 604 | printk("PCI: Enabling device %s (%04x -> %04x)\n", pci_name(dev), old_cmd, cmd); | ||
| 605 | pci_write_config_word(dev, PCI_COMMAND, cmd); | ||
| 606 | } | ||
| 607 | return 0; | ||
| 608 | } | ||
| 609 | |||
| 610 | static int next_controller_index; | ||
| 611 | |||
| 612 | struct pci_controller * __init | ||
| 613 | pcibios_alloc_controller(void) | ||
| 614 | { | ||
| 615 | struct pci_controller *hose; | ||
| 616 | |||
| 617 | hose = (struct pci_controller *)alloc_bootmem(sizeof(*hose)); | ||
| 618 | memset(hose, 0, sizeof(struct pci_controller)); | ||
| 619 | |||
| 620 | *hose_tail = hose; | ||
| 621 | hose_tail = &hose->next; | ||
| 622 | |||
| 623 | hose->index = next_controller_index++; | ||
| 624 | |||
| 625 | return hose; | ||
| 626 | } | ||
| 627 | |||
| 628 | #ifdef CONFIG_PPC_OF | 575 | #ifdef CONFIG_PPC_OF |
| 629 | /* | 576 | /* |
| 630 | * Functions below are used on OpenFirmware machines. | 577 | * Functions below are used on OpenFirmware machines. |
| @@ -670,7 +617,7 @@ void | |||
| 670 | pcibios_make_OF_bus_map(void) | 617 | pcibios_make_OF_bus_map(void) |
| 671 | { | 618 | { |
| 672 | int i; | 619 | int i; |
| 673 | struct pci_controller* hose; | 620 | struct pci_controller *hose, *tmp; |
| 674 | struct property *map_prop; | 621 | struct property *map_prop; |
| 675 | struct device_node *dn; | 622 | struct device_node *dn; |
| 676 | 623 | ||
| @@ -687,7 +634,7 @@ pcibios_make_OF_bus_map(void) | |||
| 687 | pci_to_OF_bus_map[i] = 0xff; | 634 | pci_to_OF_bus_map[i] = 0xff; |
| 688 | 635 | ||
| 689 | /* For each hose, we begin searching bridges */ | 636 | /* For each hose, we begin searching bridges */ |
| 690 | for(hose=hose_head; hose; hose=hose->next) { | 637 | list_for_each_entry_safe(hose, tmp, &hose_list, list_node) { |
| 691 | struct device_node* node; | 638 | struct device_node* node; |
| 692 | node = (struct device_node *)hose->arch_data; | 639 | node = (struct device_node *)hose->arch_data; |
| 693 | if (!node) | 640 | if (!node) |
| @@ -765,7 +712,7 @@ static struct device_node *scan_OF_for_pci_bus(struct pci_bus *bus) | |||
| 765 | 712 | ||
| 766 | /* Are we a root bus ? */ | 713 | /* Are we a root bus ? */ |
| 767 | if (bus->self == NULL || bus->parent == NULL) { | 714 | if (bus->self == NULL || bus->parent == NULL) { |
| 768 | struct pci_controller *hose = pci_bus_to_hose(bus->number); | 715 | struct pci_controller *hose = pci_bus_to_host(bus); |
| 769 | if (hose == NULL) | 716 | if (hose == NULL) |
| 770 | return NULL; | 717 | return NULL; |
| 771 | return of_node_get(hose->arch_data); | 718 | return of_node_get(hose->arch_data); |
| @@ -818,27 +765,6 @@ pci_device_to_OF_node(struct pci_dev *dev) | |||
| 818 | } | 765 | } |
| 819 | EXPORT_SYMBOL(pci_device_to_OF_node); | 766 | EXPORT_SYMBOL(pci_device_to_OF_node); |
| 820 | 767 | ||
| 821 | /* This routine is meant to be used early during boot, when the | ||
| 822 | * PCI bus numbers have not yet been assigned, and you need to | ||
| 823 | * issue PCI config cycles to an OF device. | ||
| 824 | * It could also be used to "fix" RTAS config cycles if you want | ||
| 825 | * to set pci_assign_all_buses to 1 and still use RTAS for PCI | ||
| 826 | * config cycles. | ||
| 827 | */ | ||
| 828 | struct pci_controller* pci_find_hose_for_OF_device(struct device_node* node) | ||
| 829 | { | ||
| 830 | if (!have_of) | ||
| 831 | return NULL; | ||
| 832 | while(node) { | ||
| 833 | struct pci_controller* hose; | ||
| 834 | for (hose=hose_head;hose;hose=hose->next) | ||
| 835 | if (hose->arch_data == node) | ||
| 836 | return hose; | ||
| 837 | node=node->parent; | ||
| 838 | } | ||
| 839 | return NULL; | ||
| 840 | } | ||
| 841 | |||
| 842 | static int | 768 | static int |
| 843 | find_OF_pci_device_filter(struct device_node* node, void* data) | 769 | find_OF_pci_device_filter(struct device_node* node, void* data) |
| 844 | { | 770 | { |
| @@ -1027,34 +953,12 @@ pci_create_OF_bus_map(void) | |||
| 1027 | } | 953 | } |
| 1028 | } | 954 | } |
| 1029 | 955 | ||
| 1030 | static ssize_t pci_show_devspec(struct device *dev, struct device_attribute *attr, char *buf) | ||
| 1031 | { | ||
| 1032 | struct pci_dev *pdev; | ||
| 1033 | struct device_node *np; | ||
| 1034 | |||
| 1035 | pdev = to_pci_dev (dev); | ||
| 1036 | np = pci_device_to_OF_node(pdev); | ||
| 1037 | if (np == NULL || np->full_name == NULL) | ||
| 1038 | return 0; | ||
| 1039 | return sprintf(buf, "%s", np->full_name); | ||
| 1040 | } | ||
| 1041 | static DEVICE_ATTR(devspec, S_IRUGO, pci_show_devspec, NULL); | ||
| 1042 | |||
| 1043 | #else /* CONFIG_PPC_OF */ | 956 | #else /* CONFIG_PPC_OF */ |
| 1044 | void pcibios_make_OF_bus_map(void) | 957 | void pcibios_make_OF_bus_map(void) |
| 1045 | { | 958 | { |
| 1046 | } | 959 | } |
| 1047 | #endif /* CONFIG_PPC_OF */ | 960 | #endif /* CONFIG_PPC_OF */ |
| 1048 | 961 | ||
| 1049 | /* Add sysfs properties */ | ||
| 1050 | void pcibios_add_platform_entries(struct pci_dev *pdev) | ||
| 1051 | { | ||
| 1052 | #ifdef CONFIG_PPC_OF | ||
| 1053 | device_create_file(&pdev->dev, &dev_attr_devspec); | ||
| 1054 | #endif /* CONFIG_PPC_OF */ | ||
| 1055 | } | ||
| 1056 | |||
| 1057 | |||
| 1058 | #ifdef CONFIG_PPC_PMAC | 962 | #ifdef CONFIG_PPC_PMAC |
| 1059 | /* | 963 | /* |
| 1060 | * This set of routines checks for PCI<->PCI bridges that have closed | 964 | * This set of routines checks for PCI<->PCI bridges that have closed |
| @@ -1269,14 +1173,14 @@ pcibios_fixup_p2p_bridges(void) | |||
| 1269 | static int __init | 1173 | static int __init |
| 1270 | pcibios_init(void) | 1174 | pcibios_init(void) |
| 1271 | { | 1175 | { |
| 1272 | struct pci_controller *hose; | 1176 | struct pci_controller *hose, *tmp; |
| 1273 | struct pci_bus *bus; | 1177 | struct pci_bus *bus; |
| 1274 | int next_busno; | 1178 | int next_busno = 0; |
| 1275 | 1179 | ||
| 1276 | printk(KERN_INFO "PCI: Probing PCI hardware\n"); | 1180 | printk(KERN_INFO "PCI: Probing PCI hardware\n"); |
| 1277 | 1181 | ||
| 1278 | /* Scan all of the recorded PCI controllers. */ | 1182 | /* Scan all of the recorded PCI controllers. */ |
| 1279 | for (next_busno = 0, hose = hose_head; hose; hose = hose->next) { | 1183 | list_for_each_entry_safe(hose, tmp, &hose_list, list_node) { |
| 1280 | if (pci_assign_all_buses) | 1184 | if (pci_assign_all_buses) |
| 1281 | hose->first_busno = next_busno; | 1185 | hose->first_busno = next_busno; |
| 1282 | hose->last_busno = 0xff; | 1186 | hose->last_busno = 0xff; |
| @@ -1319,12 +1223,6 @@ pcibios_init(void) | |||
| 1319 | 1223 | ||
| 1320 | subsys_initcall(pcibios_init); | 1224 | subsys_initcall(pcibios_init); |
| 1321 | 1225 | ||
| 1322 | unsigned long resource_fixup(struct pci_dev * dev, struct resource * res, | ||
| 1323 | unsigned long start, unsigned long size) | ||
| 1324 | { | ||
| 1325 | return start; | ||
| 1326 | } | ||
| 1327 | |||
| 1328 | void __init pcibios_fixup_bus(struct pci_bus *bus) | 1226 | void __init pcibios_fixup_bus(struct pci_bus *bus) |
| 1329 | { | 1227 | { |
| 1330 | struct pci_controller *hose = (struct pci_controller *) bus->sysdata; | 1228 | struct pci_controller *hose = (struct pci_controller *) bus->sysdata; |
| @@ -1342,7 +1240,7 @@ void __init pcibios_fixup_bus(struct pci_bus *bus) | |||
| 1342 | if (!res->flags) { | 1240 | if (!res->flags) { |
| 1343 | if (io_offset) | 1241 | if (io_offset) |
| 1344 | printk(KERN_ERR "I/O resource not set for host" | 1242 | printk(KERN_ERR "I/O resource not set for host" |
| 1345 | " bridge %d\n", hose->index); | 1243 | " bridge %d\n", hose->global_number); |
| 1346 | res->start = 0; | 1244 | res->start = 0; |
| 1347 | res->end = IO_SPACE_LIMIT; | 1245 | res->end = IO_SPACE_LIMIT; |
| 1348 | res->flags = IORESOURCE_IO; | 1246 | res->flags = IORESOURCE_IO; |
| @@ -1356,7 +1254,7 @@ void __init pcibios_fixup_bus(struct pci_bus *bus) | |||
| 1356 | if (i > 0) | 1254 | if (i > 0) |
| 1357 | continue; | 1255 | continue; |
| 1358 | printk(KERN_ERR "Memory resource not set for " | 1256 | printk(KERN_ERR "Memory resource not set for " |
| 1359 | "host bridge %d\n", hose->index); | 1257 | "host bridge %d\n", hose->global_number); |
| 1360 | res->start = hose->pci_mem_offset; | 1258 | res->start = hose->pci_mem_offset; |
| 1361 | res->end = ~0U; | 1259 | res->end = ~0U; |
| 1362 | res->flags = IORESOURCE_MEM; | 1260 | res->flags = IORESOURCE_MEM; |
| @@ -1370,7 +1268,7 @@ void __init pcibios_fixup_bus(struct pci_bus *bus) | |||
| 1370 | for (i = 0; i < 4; ++i) { | 1268 | for (i = 0; i < 4; ++i) { |
| 1371 | if ((res = bus->resource[i]) == NULL) | 1269 | if ((res = bus->resource[i]) == NULL) |
| 1372 | continue; | 1270 | continue; |
| 1373 | if (!res->flags) | 1271 | if (!res->flags || bus->self->transparent) |
| 1374 | continue; | 1272 | continue; |
| 1375 | if (io_offset && (res->flags & IORESOURCE_IO)) { | 1273 | if (io_offset && (res->flags & IORESOURCE_IO)) { |
| 1376 | res->start += io_offset; | 1274 | res->start += io_offset; |
| @@ -1395,11 +1293,6 @@ void __init pcibios_fixup_bus(struct pci_bus *bus) | |||
| 1395 | } | 1293 | } |
| 1396 | } | 1294 | } |
| 1397 | 1295 | ||
| 1398 | char __init *pcibios_setup(char *str) | ||
| 1399 | { | ||
| 1400 | return str; | ||
| 1401 | } | ||
| 1402 | |||
| 1403 | /* the next one is stolen from the alpha port... */ | 1296 | /* the next one is stolen from the alpha port... */ |
| 1404 | void __init | 1297 | void __init |
| 1405 | pcibios_update_irq(struct pci_dev *dev, int irq) | 1298 | pcibios_update_irq(struct pci_dev *dev, int irq) |
| @@ -1408,64 +1301,6 @@ pcibios_update_irq(struct pci_dev *dev, int irq) | |||
| 1408 | /* XXX FIXME - update OF device tree node interrupt property */ | 1301 | /* XXX FIXME - update OF device tree node interrupt property */ |
| 1409 | } | 1302 | } |
| 1410 | 1303 | ||
| 1411 | #ifdef CONFIG_PPC_MERGE | ||
| 1412 | /* XXX This is a copy of the ppc64 version. This is temporary until we start | ||
| 1413 | * merging the 2 PCI layers | ||
| 1414 | */ | ||
| 1415 | /* | ||
| 1416 | * Reads the interrupt pin to determine if interrupt is use by card. | ||
| 1417 | * If the interrupt is used, then gets the interrupt line from the | ||
| 1418 | * openfirmware and sets it in the pci_dev and pci_config line. | ||
| 1419 | */ | ||
| 1420 | int pci_read_irq_line(struct pci_dev *pci_dev) | ||
| 1421 | { | ||
| 1422 | struct of_irq oirq; | ||
| 1423 | unsigned int virq; | ||
| 1424 | |||
| 1425 | DBG("Try to map irq for %s...\n", pci_name(pci_dev)); | ||
| 1426 | |||
| 1427 | /* Try to get a mapping from the device-tree */ | ||
| 1428 | if (of_irq_map_pci(pci_dev, &oirq)) { | ||
| 1429 | u8 line, pin; | ||
| 1430 | |||
| 1431 | /* If that fails, lets fallback to what is in the config | ||
| 1432 | * space and map that through the default controller. We | ||
| 1433 | * also set the type to level low since that's what PCI | ||
| 1434 | * interrupts are. If your platform does differently, then | ||
| 1435 | * either provide a proper interrupt tree or don't use this | ||
| 1436 | * function. | ||
| 1437 | */ | ||
| 1438 | if (pci_read_config_byte(pci_dev, PCI_INTERRUPT_PIN, &pin)) | ||
| 1439 | return -1; | ||
| 1440 | if (pin == 0) | ||
| 1441 | return -1; | ||
| 1442 | if (pci_read_config_byte(pci_dev, PCI_INTERRUPT_LINE, &line) || | ||
| 1443 | line == 0xff) { | ||
| 1444 | return -1; | ||
| 1445 | } | ||
| 1446 | DBG(" -> no map ! Using irq line %d from PCI config\n", line); | ||
| 1447 | |||
| 1448 | virq = irq_create_mapping(NULL, line); | ||
| 1449 | if (virq != NO_IRQ) | ||
| 1450 | set_irq_type(virq, IRQ_TYPE_LEVEL_LOW); | ||
| 1451 | } else { | ||
| 1452 | DBG(" -> got one, spec %d cells (0x%08x...) on %s\n", | ||
| 1453 | oirq.size, oirq.specifier[0], oirq.controller->full_name); | ||
| 1454 | |||
| 1455 | virq = irq_create_of_mapping(oirq.controller, oirq.specifier, | ||
| 1456 | oirq.size); | ||
| 1457 | } | ||
| 1458 | if(virq == NO_IRQ) { | ||
| 1459 | DBG(" -> failed to map !\n"); | ||
| 1460 | return -1; | ||
| 1461 | } | ||
| 1462 | pci_dev->irq = virq; | ||
| 1463 | |||
| 1464 | return 0; | ||
| 1465 | } | ||
| 1466 | EXPORT_SYMBOL(pci_read_irq_line); | ||
| 1467 | #endif /* CONFIG_PPC_MERGE */ | ||
| 1468 | |||
| 1469 | int pcibios_enable_device(struct pci_dev *dev, int mask) | 1304 | int pcibios_enable_device(struct pci_dev *dev, int mask) |
| 1470 | { | 1305 | { |
| 1471 | u16 cmd, old_cmd; | 1306 | u16 cmd, old_cmd; |
| @@ -1497,281 +1332,17 @@ int pcibios_enable_device(struct pci_dev *dev, int mask) | |||
| 1497 | return 0; | 1332 | return 0; |
| 1498 | } | 1333 | } |
| 1499 | 1334 | ||
| 1500 | struct pci_controller* | 1335 | static struct pci_controller* |
| 1501 | pci_bus_to_hose(int bus) | 1336 | pci_bus_to_hose(int bus) |
| 1502 | { | 1337 | { |
| 1503 | struct pci_controller* hose = hose_head; | 1338 | struct pci_controller *hose, *tmp; |
| 1504 | 1339 | ||
| 1505 | for (; hose; hose = hose->next) | 1340 | list_for_each_entry_safe(hose, tmp, &hose_list, list_node) |
| 1506 | if (bus >= hose->first_busno && bus <= hose->last_busno) | 1341 | if (bus >= hose->first_busno && bus <= hose->last_busno) |
| 1507 | return hose; | 1342 | return hose; |
| 1508 | return NULL; | 1343 | return NULL; |
| 1509 | } | 1344 | } |
| 1510 | 1345 | ||
| 1511 | void __iomem * | ||
| 1512 | pci_bus_io_base(unsigned int bus) | ||
| 1513 | { | ||
| 1514 | struct pci_controller *hose; | ||
| 1515 | |||
| 1516 | hose = pci_bus_to_hose(bus); | ||
| 1517 | if (!hose) | ||
| 1518 | return NULL; | ||
| 1519 | return hose->io_base_virt; | ||
| 1520 | } | ||
| 1521 | |||
| 1522 | unsigned long | ||
| 1523 | pci_bus_io_base_phys(unsigned int bus) | ||
| 1524 | { | ||
| 1525 | struct pci_controller *hose; | ||
| 1526 | |||
| 1527 | hose = pci_bus_to_hose(bus); | ||
| 1528 | if (!hose) | ||
| 1529 | return 0; | ||
| 1530 | return hose->io_base_phys; | ||
| 1531 | } | ||
| 1532 | |||
| 1533 | unsigned long | ||
| 1534 | pci_bus_mem_base_phys(unsigned int bus) | ||
| 1535 | { | ||
| 1536 | struct pci_controller *hose; | ||
| 1537 | |||
| 1538 | hose = pci_bus_to_hose(bus); | ||
| 1539 | if (!hose) | ||
| 1540 | return 0; | ||
| 1541 | return hose->pci_mem_offset; | ||
| 1542 | } | ||
| 1543 | |||
| 1544 | unsigned long | ||
| 1545 | pci_resource_to_bus(struct pci_dev *pdev, struct resource *res) | ||
| 1546 | { | ||
| 1547 | /* Hack alert again ! See comments in chrp_pci.c | ||
| 1548 | */ | ||
| 1549 | struct pci_controller* hose = | ||
| 1550 | (struct pci_controller *)pdev->sysdata; | ||
| 1551 | if (hose && res->flags & IORESOURCE_MEM) | ||
| 1552 | return res->start - hose->pci_mem_offset; | ||
| 1553 | /* We may want to do something with IOs here... */ | ||
| 1554 | return res->start; | ||
| 1555 | } | ||
| 1556 | |||
| 1557 | |||
| 1558 | static struct resource *__pci_mmap_make_offset(struct pci_dev *dev, | ||
| 1559 | resource_size_t *offset, | ||
| 1560 | enum pci_mmap_state mmap_state) | ||
| 1561 | { | ||
| 1562 | struct pci_controller *hose = pci_bus_to_hose(dev->bus->number); | ||
| 1563 | unsigned long io_offset = 0; | ||
| 1564 | int i, res_bit; | ||
| 1565 | |||
| 1566 | if (hose == 0) | ||
| 1567 | return NULL; /* should never happen */ | ||
| 1568 | |||
| 1569 | /* If memory, add on the PCI bridge address offset */ | ||
| 1570 | if (mmap_state == pci_mmap_mem) { | ||
| 1571 | #if 0 /* See comment in pci_resource_to_user() for why this is disabled */ | ||
| 1572 | *offset += hose->pci_mem_offset; | ||
| 1573 | #endif | ||
| 1574 | res_bit = IORESOURCE_MEM; | ||
| 1575 | } else { | ||
| 1576 | io_offset = hose->io_base_virt - (void __iomem *)_IO_BASE; | ||
| 1577 | *offset += io_offset; | ||
| 1578 | res_bit = IORESOURCE_IO; | ||
| 1579 | } | ||
| 1580 | |||
| 1581 | /* | ||
| 1582 | * Check that the offset requested corresponds to one of the | ||
| 1583 | * resources of the device. | ||
| 1584 | */ | ||
| 1585 | for (i = 0; i <= PCI_ROM_RESOURCE; i++) { | ||
| 1586 | struct resource *rp = &dev->resource[i]; | ||
| 1587 | int flags = rp->flags; | ||
| 1588 | |||
| 1589 | /* treat ROM as memory (should be already) */ | ||
| 1590 | if (i == PCI_ROM_RESOURCE) | ||
| 1591 | flags |= IORESOURCE_MEM; | ||
| 1592 | |||
| 1593 | /* Active and same type? */ | ||
| 1594 | if ((flags & res_bit) == 0) | ||
| 1595 | continue; | ||
| 1596 | |||
| 1597 | /* In the range of this resource? */ | ||
| 1598 | if (*offset < (rp->start & PAGE_MASK) || *offset > rp->end) | ||
| 1599 | continue; | ||
| 1600 | |||
| 1601 | /* found it! construct the final physical address */ | ||
| 1602 | if (mmap_state == pci_mmap_io) | ||
| 1603 | *offset += hose->io_base_phys - io_offset; | ||
| 1604 | return rp; | ||
| 1605 | } | ||
| 1606 | |||
| 1607 | return NULL; | ||
| 1608 | } | ||
| 1609 | |||
| 1610 | /* | ||
| 1611 | * Set vm_page_prot of VMA, as appropriate for this architecture, for a pci | ||
| 1612 | * device mapping. | ||
| 1613 | */ | ||
| 1614 | static pgprot_t __pci_mmap_set_pgprot(struct pci_dev *dev, struct resource *rp, | ||
| 1615 | pgprot_t protection, | ||
| 1616 | enum pci_mmap_state mmap_state, | ||
| 1617 | int write_combine) | ||
| 1618 | { | ||
| 1619 | unsigned long prot = pgprot_val(protection); | ||
| 1620 | |||
| 1621 | /* Write combine is always 0 on non-memory space mappings. On | ||
| 1622 | * memory space, if the user didn't pass 1, we check for a | ||
| 1623 | * "prefetchable" resource. This is a bit hackish, but we use | ||
| 1624 | * this to workaround the inability of /sysfs to provide a write | ||
| 1625 | * combine bit | ||
| 1626 | */ | ||
| 1627 | if (mmap_state != pci_mmap_mem) | ||
| 1628 | write_combine = 0; | ||
| 1629 | else if (write_combine == 0) { | ||
| 1630 | if (rp->flags & IORESOURCE_PREFETCH) | ||
| 1631 | write_combine = 1; | ||
| 1632 | } | ||
| 1633 | |||
| 1634 | /* XXX would be nice to have a way to ask for write-through */ | ||
| 1635 | prot |= _PAGE_NO_CACHE; | ||
| 1636 | if (write_combine) | ||
| 1637 | prot &= ~_PAGE_GUARDED; | ||
| 1638 | else | ||
| 1639 | prot |= _PAGE_GUARDED; | ||
| 1640 | |||
| 1641 | return __pgprot(prot); | ||
| 1642 | } | ||
| 1643 | |||
| 1644 | /* | ||
| 1645 | * This one is used by /dev/mem and fbdev who have no clue about the | ||
| 1646 | * PCI device, it tries to find the PCI device first and calls the | ||
| 1647 | * above routine | ||
| 1648 | */ | ||
| 1649 | pgprot_t pci_phys_mem_access_prot(struct file *file, | ||
| 1650 | unsigned long pfn, | ||
| 1651 | unsigned long size, | ||
| 1652 | pgprot_t protection) | ||
| 1653 | { | ||
| 1654 | struct pci_dev *pdev = NULL; | ||
| 1655 | struct resource *found = NULL; | ||
| 1656 | unsigned long prot = pgprot_val(protection); | ||
| 1657 | unsigned long offset = pfn << PAGE_SHIFT; | ||
| 1658 | int i; | ||
| 1659 | |||
| 1660 | if (page_is_ram(pfn)) | ||
| 1661 | return __pgprot(prot); | ||
| 1662 | |||
| 1663 | prot |= _PAGE_NO_CACHE | _PAGE_GUARDED; | ||
| 1664 | |||
| 1665 | for_each_pci_dev(pdev) { | ||
| 1666 | for (i = 0; i <= PCI_ROM_RESOURCE; i++) { | ||
| 1667 | struct resource *rp = &pdev->resource[i]; | ||
| 1668 | int flags = rp->flags; | ||
| 1669 | |||
| 1670 | /* Active and same type? */ | ||
| 1671 | if ((flags & IORESOURCE_MEM) == 0) | ||
| 1672 | continue; | ||
| 1673 | /* In the range of this resource? */ | ||
| 1674 | if (offset < (rp->start & PAGE_MASK) || | ||
| 1675 | offset > rp->end) | ||
| 1676 | continue; | ||
| 1677 | found = rp; | ||
| 1678 | break; | ||
| 1679 | } | ||
| 1680 | if (found) | ||
| 1681 | break; | ||
| 1682 | } | ||
| 1683 | if (found) { | ||
| 1684 | if (found->flags & IORESOURCE_PREFETCH) | ||
| 1685 | prot &= ~_PAGE_GUARDED; | ||
| 1686 | pci_dev_put(pdev); | ||
| 1687 | } | ||
| 1688 | |||
| 1689 | DBG("non-PCI map for %lx, prot: %lx\n", offset, prot); | ||
| 1690 | |||
| 1691 | return __pgprot(prot); | ||
| 1692 | } | ||
| 1693 | |||
| 1694 | |||
| 1695 | /* | ||
| 1696 | * Perform the actual remap of the pages for a PCI device mapping, as | ||
| 1697 | * appropriate for this architecture. The region in the process to map | ||
| 1698 | * is described by vm_start and vm_end members of VMA, the base physical | ||
| 1699 | * address is found in vm_pgoff. | ||
| 1700 | * The pci device structure is provided so that architectures may make mapping | ||
| 1701 | * decisions on a per-device or per-bus basis. | ||
| 1702 | * | ||
| 1703 | * Returns a negative error code on failure, zero on success. | ||
| 1704 | */ | ||
| 1705 | int pci_mmap_page_range(struct pci_dev *dev, struct vm_area_struct *vma, | ||
| 1706 | enum pci_mmap_state mmap_state, | ||
| 1707 | int write_combine) | ||
| 1708 | { | ||
| 1709 | resource_size_t offset = vma->vm_pgoff << PAGE_SHIFT; | ||
| 1710 | struct resource *rp; | ||
| 1711 | int ret; | ||
| 1712 | |||
| 1713 | rp = __pci_mmap_make_offset(dev, &offset, mmap_state); | ||
| 1714 | if (rp == NULL) | ||
| 1715 | return -EINVAL; | ||
| 1716 | |||
| 1717 | vma->vm_pgoff = offset >> PAGE_SHIFT; | ||
| 1718 | vma->vm_page_prot = __pci_mmap_set_pgprot(dev, rp, | ||
| 1719 | vma->vm_page_prot, | ||
| 1720 | mmap_state, write_combine); | ||
| 1721 | |||
| 1722 | ret = remap_pfn_range(vma, vma->vm_start, vma->vm_pgoff, | ||
| 1723 | vma->vm_end - vma->vm_start, vma->vm_page_prot); | ||
| 1724 | |||
| 1725 | return ret; | ||
| 1726 | } | ||
| 1727 | |||
| 1728 | /* Obsolete functions. Should be removed once the symbios driver | ||
| 1729 | * is fixed | ||
| 1730 | */ | ||
| 1731 | unsigned long | ||
| 1732 | phys_to_bus(unsigned long pa) | ||
| 1733 | { | ||
| 1734 | struct pci_controller *hose; | ||
| 1735 | int i; | ||
| 1736 | |||
| 1737 | for (hose = hose_head; hose; hose = hose->next) { | ||
| 1738 | for (i = 0; i < 3; ++i) { | ||
| 1739 | if (pa >= hose->mem_resources[i].start | ||
| 1740 | && pa <= hose->mem_resources[i].end) { | ||
| 1741 | /* | ||
| 1742 | * XXX the hose->pci_mem_offset really | ||
| 1743 | * only applies to mem_resources[0]. | ||
| 1744 | * We need a way to store an offset for | ||
| 1745 | * the others. -- paulus | ||
| 1746 | */ | ||
| 1747 | if (i == 0) | ||
| 1748 | pa -= hose->pci_mem_offset; | ||
| 1749 | return pa; | ||
| 1750 | } | ||
| 1751 | } | ||
| 1752 | } | ||
| 1753 | /* hmmm, didn't find it */ | ||
| 1754 | return 0; | ||
| 1755 | } | ||
| 1756 | |||
| 1757 | unsigned long | ||
| 1758 | pci_phys_to_bus(unsigned long pa, int busnr) | ||
| 1759 | { | ||
| 1760 | struct pci_controller* hose = pci_bus_to_hose(busnr); | ||
| 1761 | if (!hose) | ||
| 1762 | return pa; | ||
| 1763 | return pa - hose->pci_mem_offset; | ||
| 1764 | } | ||
| 1765 | |||
| 1766 | unsigned long | ||
| 1767 | pci_bus_to_phys(unsigned int ba, int busnr) | ||
| 1768 | { | ||
| 1769 | struct pci_controller* hose = pci_bus_to_hose(busnr); | ||
| 1770 | if (!hose) | ||
| 1771 | return ba; | ||
| 1772 | return ba + hose->pci_mem_offset; | ||
| 1773 | } | ||
| 1774 | |||
| 1775 | /* Provide information on locations of various I/O regions in physical | 1346 | /* Provide information on locations of various I/O regions in physical |
| 1776 | * memory. Do this on a per-card basis so that we choose the right | 1347 | * memory. Do this on a per-card basis so that we choose the right |
| 1777 | * root bridge. | 1348 | * root bridge. |
| @@ -1814,62 +1385,11 @@ long sys_pciconfig_iobase(long which, unsigned long bus, unsigned long devfn) | |||
| 1814 | return result; | 1385 | return result; |
| 1815 | } | 1386 | } |
| 1816 | 1387 | ||
| 1817 | void pci_resource_to_user(const struct pci_dev *dev, int bar, | ||
| 1818 | const struct resource *rsrc, | ||
| 1819 | resource_size_t *start, resource_size_t *end) | ||
| 1820 | { | ||
| 1821 | struct pci_controller *hose = pci_bus_to_hose(dev->bus->number); | ||
| 1822 | resource_size_t offset = 0; | ||
| 1823 | |||
| 1824 | if (hose == NULL) | ||
| 1825 | return; | ||
| 1826 | |||
| 1827 | if (rsrc->flags & IORESOURCE_IO) | ||
| 1828 | offset = (unsigned long)hose->io_base_virt - _IO_BASE; | ||
| 1829 | |||
| 1830 | /* We pass a fully fixed up address to userland for MMIO instead of | ||
| 1831 | * a BAR value because X is lame and expects to be able to use that | ||
| 1832 | * to pass to /dev/mem ! | ||
| 1833 | * | ||
| 1834 | * That means that we'll have potentially 64 bits values where some | ||
| 1835 | * userland apps only expect 32 (like X itself since it thinks only | ||
| 1836 | * Sparc has 64 bits MMIO) but if we don't do that, we break it on | ||
| 1837 | * 32 bits CHRPs :-( | ||
| 1838 | * | ||
| 1839 | * Hopefully, the sysfs insterface is immune to that gunk. Once X | ||
| 1840 | * has been fixed (and the fix spread enough), we can re-enable the | ||
| 1841 | * 2 lines below and pass down a BAR value to userland. In that case | ||
| 1842 | * we'll also have to re-enable the matching code in | ||
| 1843 | * __pci_mmap_make_offset(). | ||
| 1844 | * | ||
| 1845 | * BenH. | ||
| 1846 | */ | ||
| 1847 | #if 0 | ||
| 1848 | else if (rsrc->flags & IORESOURCE_MEM) | ||
| 1849 | offset = hose->pci_mem_offset; | ||
| 1850 | #endif | ||
| 1851 | |||
| 1852 | *start = rsrc->start - offset; | ||
| 1853 | *end = rsrc->end - offset; | ||
| 1854 | } | ||
| 1855 | |||
| 1856 | void __init pci_init_resource(struct resource *res, resource_size_t start, | ||
| 1857 | resource_size_t end, int flags, char *name) | ||
| 1858 | { | ||
| 1859 | res->start = start; | ||
| 1860 | res->end = end; | ||
| 1861 | res->flags = flags; | ||
| 1862 | res->name = name; | ||
| 1863 | res->parent = NULL; | ||
| 1864 | res->sibling = NULL; | ||
| 1865 | res->child = NULL; | ||
| 1866 | } | ||
| 1867 | |||
| 1868 | unsigned long pci_address_to_pio(phys_addr_t address) | 1388 | unsigned long pci_address_to_pio(phys_addr_t address) |
| 1869 | { | 1389 | { |
| 1870 | struct pci_controller* hose = hose_head; | 1390 | struct pci_controller *hose, *tmp; |
| 1871 | 1391 | ||
| 1872 | for (; hose; hose = hose->next) { | 1392 | list_for_each_entry_safe(hose, tmp, &hose_list, list_node) { |
| 1873 | unsigned int size = hose->io_resource.end - | 1393 | unsigned int size = hose->io_resource.end - |
| 1874 | hose->io_resource.start + 1; | 1394 | hose->io_resource.start + 1; |
| 1875 | if (address >= hose->io_base_phys && | 1395 | if (address >= hose->io_base_phys && |
diff --git a/arch/powerpc/kernel/pci_64.c b/arch/powerpc/kernel/pci_64.c index 249cca27a9b8..93b2920effc5 100644 --- a/arch/powerpc/kernel/pci_64.c +++ b/arch/powerpc/kernel/pci_64.c | |||
| @@ -22,6 +22,7 @@ | |||
| 22 | #include <linux/list.h> | 22 | #include <linux/list.h> |
| 23 | #include <linux/syscalls.h> | 23 | #include <linux/syscalls.h> |
| 24 | #include <linux/irq.h> | 24 | #include <linux/irq.h> |
| 25 | #include <linux/vmalloc.h> | ||
| 25 | 26 | ||
| 26 | #include <asm/processor.h> | 27 | #include <asm/processor.h> |
| 27 | #include <asm/io.h> | 28 | #include <asm/io.h> |
| @@ -41,35 +42,23 @@ | |||
| 41 | 42 | ||
| 42 | unsigned long pci_probe_only = 1; | 43 | unsigned long pci_probe_only = 1; |
| 43 | int pci_assign_all_buses = 0; | 44 | int pci_assign_all_buses = 0; |
| 44 | static int pci_initial_scan_done; | ||
| 45 | 45 | ||
| 46 | static void fixup_resource(struct resource *res, struct pci_dev *dev); | 46 | static void fixup_resource(struct resource *res, struct pci_dev *dev); |
| 47 | static void do_bus_setup(struct pci_bus *bus); | 47 | static void do_bus_setup(struct pci_bus *bus); |
| 48 | static void phbs_remap_io(void); | ||
| 49 | 48 | ||
| 50 | /* pci_io_base -- the base address from which io bars are offsets. | 49 | /* pci_io_base -- the base address from which io bars are offsets. |
| 51 | * This is the lowest I/O base address (so bar values are always positive), | 50 | * This is the lowest I/O base address (so bar values are always positive), |
| 52 | * and it *must* be the start of ISA space if an ISA bus exists because | 51 | * and it *must* be the start of ISA space if an ISA bus exists because |
| 53 | * ISA drivers use hard coded offsets. If no ISA bus exists a dummy | 52 | * ISA drivers use hard coded offsets. If no ISA bus exists nothing |
| 54 | * page is mapped and isa_io_limit prevents access to it. | 53 | * is mapped on the first 64K of IO space |
| 55 | */ | 54 | */ |
| 56 | unsigned long isa_io_base; /* NULL if no ISA bus */ | 55 | unsigned long pci_io_base = ISA_IO_BASE; |
| 57 | EXPORT_SYMBOL(isa_io_base); | ||
| 58 | unsigned long pci_io_base; | ||
| 59 | EXPORT_SYMBOL(pci_io_base); | 56 | EXPORT_SYMBOL(pci_io_base); |
| 60 | 57 | ||
| 61 | void iSeries_pcibios_init(void); | ||
| 62 | |||
| 63 | LIST_HEAD(hose_list); | 58 | LIST_HEAD(hose_list); |
| 64 | 59 | ||
| 65 | static struct dma_mapping_ops *pci_dma_ops; | 60 | static struct dma_mapping_ops *pci_dma_ops; |
| 66 | 61 | ||
| 67 | int global_phb_number; /* Global phb counter */ | ||
| 68 | |||
| 69 | /* Cached ISA bridge dev. */ | ||
| 70 | struct pci_dev *ppc64_isabridge_dev = NULL; | ||
| 71 | EXPORT_SYMBOL_GPL(ppc64_isabridge_dev); | ||
| 72 | |||
| 73 | void set_pci_dma_ops(struct dma_mapping_ops *dma_ops) | 62 | void set_pci_dma_ops(struct dma_mapping_ops *dma_ops) |
| 74 | { | 63 | { |
| 75 | pci_dma_ops = dma_ops; | 64 | pci_dma_ops = dma_ops; |
| @@ -100,7 +89,7 @@ void pcibios_resource_to_bus(struct pci_dev *dev, struct pci_bus_region *region | |||
| 100 | return; | 89 | return; |
| 101 | 90 | ||
| 102 | if (res->flags & IORESOURCE_IO) | 91 | if (res->flags & IORESOURCE_IO) |
| 103 | offset = (unsigned long)hose->io_base_virt - pci_io_base; | 92 | offset = (unsigned long)hose->io_base_virt - _IO_BASE; |
| 104 | 93 | ||
| 105 | if (res->flags & IORESOURCE_MEM) | 94 | if (res->flags & IORESOURCE_MEM) |
| 106 | offset = hose->pci_mem_offset; | 95 | offset = hose->pci_mem_offset; |
| @@ -119,7 +108,7 @@ void pcibios_bus_to_resource(struct pci_dev *dev, struct resource *res, | |||
| 119 | return; | 108 | return; |
| 120 | 109 | ||
| 121 | if (res->flags & IORESOURCE_IO) | 110 | if (res->flags & IORESOURCE_IO) |
| 122 | offset = (unsigned long)hose->io_base_virt - pci_io_base; | 111 | offset = (unsigned long)hose->io_base_virt - _IO_BASE; |
| 123 | 112 | ||
| 124 | if (res->flags & IORESOURCE_MEM) | 113 | if (res->flags & IORESOURCE_MEM) |
| 125 | offset = hose->pci_mem_offset; | 114 | offset = hose->pci_mem_offset; |
| @@ -156,7 +145,7 @@ void pcibios_align_resource(void *data, struct resource *res, | |||
| 156 | 145 | ||
| 157 | if (res->flags & IORESOURCE_IO) { | 146 | if (res->flags & IORESOURCE_IO) { |
| 158 | unsigned long offset = (unsigned long)hose->io_base_virt - | 147 | unsigned long offset = (unsigned long)hose->io_base_virt - |
| 159 | pci_io_base; | 148 | _IO_BASE; |
| 160 | /* Make sure we start at our min on all hoses */ | 149 | /* Make sure we start at our min on all hoses */ |
| 161 | if (start - offset < PCIBIOS_MIN_IO) | 150 | if (start - offset < PCIBIOS_MIN_IO) |
| 162 | start = PCIBIOS_MIN_IO + offset; | 151 | start = PCIBIOS_MIN_IO + offset; |
| @@ -180,55 +169,6 @@ void pcibios_align_resource(void *data, struct resource *res, | |||
| 180 | res->start = start; | 169 | res->start = start; |
| 181 | } | 170 | } |
| 182 | 171 | ||
| 183 | static DEFINE_SPINLOCK(hose_spinlock); | ||
| 184 | |||
| 185 | /* | ||
| 186 | * pci_controller(phb) initialized common variables. | ||
| 187 | */ | ||
| 188 | static void __devinit pci_setup_pci_controller(struct pci_controller *hose) | ||
| 189 | { | ||
| 190 | memset(hose, 0, sizeof(struct pci_controller)); | ||
| 191 | |||
| 192 | spin_lock(&hose_spinlock); | ||
| 193 | hose->global_number = global_phb_number++; | ||
| 194 | list_add_tail(&hose->list_node, &hose_list); | ||
| 195 | spin_unlock(&hose_spinlock); | ||
| 196 | } | ||
| 197 | |||
| 198 | struct pci_controller * pcibios_alloc_controller(struct device_node *dev) | ||
| 199 | { | ||
| 200 | struct pci_controller *phb; | ||
| 201 | |||
| 202 | if (mem_init_done) | ||
| 203 | phb = kmalloc(sizeof(struct pci_controller), GFP_KERNEL); | ||
| 204 | else | ||
| 205 | phb = alloc_bootmem(sizeof (struct pci_controller)); | ||
| 206 | if (phb == NULL) | ||
| 207 | return NULL; | ||
| 208 | pci_setup_pci_controller(phb); | ||
| 209 | phb->arch_data = dev; | ||
| 210 | phb->is_dynamic = mem_init_done; | ||
| 211 | if (dev) { | ||
| 212 | int nid = of_node_to_nid(dev); | ||
| 213 | |||
| 214 | if (nid < 0 || !node_online(nid)) | ||
| 215 | nid = -1; | ||
| 216 | |||
| 217 | PHB_SET_NODE(phb, nid); | ||
| 218 | } | ||
| 219 | return phb; | ||
| 220 | } | ||
| 221 | |||
| 222 | void pcibios_free_controller(struct pci_controller *phb) | ||
| 223 | { | ||
| 224 | spin_lock(&hose_spinlock); | ||
| 225 | list_del(&phb->list_node); | ||
| 226 | spin_unlock(&hose_spinlock); | ||
| 227 | |||
| 228 | if (phb->is_dynamic) | ||
| 229 | kfree(phb); | ||
| 230 | } | ||
| 231 | |||
| 232 | void __devinit pcibios_claim_one_bus(struct pci_bus *b) | 172 | void __devinit pcibios_claim_one_bus(struct pci_bus *b) |
| 233 | { | 173 | { |
| 234 | struct pci_dev *dev; | 174 | struct pci_dev *dev; |
| @@ -291,7 +231,6 @@ static unsigned int pci_parse_of_flags(u32 addr0) | |||
| 291 | return flags; | 231 | return flags; |
| 292 | } | 232 | } |
| 293 | 233 | ||
| 294 | #define GET_64BIT(prop, i) ((((u64) (prop)[(i)]) << 32) | (prop)[(i)+1]) | ||
| 295 | 234 | ||
| 296 | static void pci_parse_of_addrs(struct device_node *node, struct pci_dev *dev) | 235 | static void pci_parse_of_addrs(struct device_node *node, struct pci_dev *dev) |
| 297 | { | 236 | { |
| @@ -310,8 +249,8 @@ static void pci_parse_of_addrs(struct device_node *node, struct pci_dev *dev) | |||
| 310 | flags = pci_parse_of_flags(addrs[0]); | 249 | flags = pci_parse_of_flags(addrs[0]); |
| 311 | if (!flags) | 250 | if (!flags) |
| 312 | continue; | 251 | continue; |
| 313 | base = GET_64BIT(addrs, 1); | 252 | base = of_read_number(&addrs[1], 2); |
| 314 | size = GET_64BIT(addrs, 3); | 253 | size = of_read_number(&addrs[3], 2); |
| 315 | if (!size) | 254 | if (!size) |
| 316 | continue; | 255 | continue; |
| 317 | i = addrs[0] & 0xff; | 256 | i = addrs[0] & 0xff; |
| @@ -477,7 +416,7 @@ void __devinit of_scan_pci_bridge(struct device_node *node, | |||
| 477 | i = 1; | 416 | i = 1; |
| 478 | for (; len >= 32; len -= 32, ranges += 8) { | 417 | for (; len >= 32; len -= 32, ranges += 8) { |
| 479 | flags = pci_parse_of_flags(ranges[0]); | 418 | flags = pci_parse_of_flags(ranges[0]); |
| 480 | size = GET_64BIT(ranges, 6); | 419 | size = of_read_number(&ranges[6], 2); |
| 481 | if (flags == 0 || size == 0) | 420 | if (flags == 0 || size == 0) |
| 482 | continue; | 421 | continue; |
| 483 | if (flags & IORESOURCE_IO) { | 422 | if (flags & IORESOURCE_IO) { |
| @@ -496,7 +435,7 @@ void __devinit of_scan_pci_bridge(struct device_node *node, | |||
| 496 | res = bus->resource[i]; | 435 | res = bus->resource[i]; |
| 497 | ++i; | 436 | ++i; |
| 498 | } | 437 | } |
| 499 | res->start = GET_64BIT(ranges, 1); | 438 | res->start = of_read_number(&ranges[1], 2); |
| 500 | res->end = res->start + size - 1; | 439 | res->end = res->start + size - 1; |
| 501 | res->flags = flags; | 440 | res->flags = flags; |
| 502 | fixup_resource(res, dev); | 441 | fixup_resource(res, dev); |
| @@ -535,10 +474,16 @@ void __devinit scan_phb(struct pci_controller *hose) | |||
| 535 | bus->secondary = hose->first_busno; | 474 | bus->secondary = hose->first_busno; |
| 536 | hose->bus = bus; | 475 | hose->bus = bus; |
| 537 | 476 | ||
| 477 | if (!firmware_has_feature(FW_FEATURE_ISERIES)) | ||
| 478 | pcibios_map_io_space(bus); | ||
| 479 | |||
| 538 | bus->resource[0] = res = &hose->io_resource; | 480 | bus->resource[0] = res = &hose->io_resource; |
| 539 | if (res->flags && request_resource(&ioport_resource, res)) | 481 | if (res->flags && request_resource(&ioport_resource, res)) { |
| 540 | printk(KERN_ERR "Failed to request PCI IO region " | 482 | printk(KERN_ERR "Failed to request PCI IO region " |
| 541 | "on PCI domain %04x\n", hose->global_number); | 483 | "on PCI domain %04x\n", hose->global_number); |
| 484 | DBG("res->start = 0x%016lx, res->end = 0x%016lx\n", | ||
| 485 | res->start, res->end); | ||
| 486 | } | ||
| 542 | 487 | ||
| 543 | for (i = 0; i < 3; ++i) { | 488 | for (i = 0; i < 3; ++i) { |
| 544 | res = &hose->mem_resources[i]; | 489 | res = &hose->mem_resources[i]; |
| @@ -596,17 +541,6 @@ static int __init pcibios_init(void) | |||
| 596 | if (ppc_md.pcibios_fixup) | 541 | if (ppc_md.pcibios_fixup) |
| 597 | ppc_md.pcibios_fixup(); | 542 | ppc_md.pcibios_fixup(); |
| 598 | 543 | ||
| 599 | /* Cache the location of the ISA bridge (if we have one) */ | ||
| 600 | ppc64_isabridge_dev = pci_get_class(PCI_CLASS_BRIDGE_ISA << 8, NULL); | ||
| 601 | if (ppc64_isabridge_dev != NULL) | ||
| 602 | printk(KERN_DEBUG "ISA bridge at %s\n", pci_name(ppc64_isabridge_dev)); | ||
| 603 | |||
| 604 | if (!firmware_has_feature(FW_FEATURE_ISERIES)) | ||
| 605 | /* map in PCI I/O space */ | ||
| 606 | phbs_remap_io(); | ||
| 607 | |||
| 608 | pci_initial_scan_done = 1; | ||
| 609 | |||
| 610 | printk(KERN_DEBUG "PCI: Probing PCI hardware done\n"); | 544 | printk(KERN_DEBUG "PCI: Probing PCI hardware done\n"); |
| 611 | 545 | ||
| 612 | return 0; | 546 | return 0; |
| @@ -614,11 +548,6 @@ static int __init pcibios_init(void) | |||
| 614 | 548 | ||
| 615 | subsys_initcall(pcibios_init); | 549 | subsys_initcall(pcibios_init); |
| 616 | 550 | ||
| 617 | char __init *pcibios_setup(char *str) | ||
| 618 | { | ||
| 619 | return str; | ||
| 620 | } | ||
| 621 | |||
| 622 | int pcibios_enable_device(struct pci_dev *dev, int mask) | 551 | int pcibios_enable_device(struct pci_dev *dev, int mask) |
| 623 | { | 552 | { |
| 624 | u16 cmd, oldcmd; | 553 | u16 cmd, oldcmd; |
| @@ -649,22 +578,6 @@ int pcibios_enable_device(struct pci_dev *dev, int mask) | |||
| 649 | return 0; | 578 | return 0; |
| 650 | } | 579 | } |
| 651 | 580 | ||
| 652 | /* | ||
| 653 | * Return the domain number for this bus. | ||
| 654 | */ | ||
| 655 | int pci_domain_nr(struct pci_bus *bus) | ||
| 656 | { | ||
| 657 | if (firmware_has_feature(FW_FEATURE_ISERIES)) | ||
| 658 | return 0; | ||
| 659 | else { | ||
| 660 | struct pci_controller *hose = pci_bus_to_host(bus); | ||
| 661 | |||
| 662 | return hose->global_number; | ||
| 663 | } | ||
| 664 | } | ||
| 665 | |||
| 666 | EXPORT_SYMBOL(pci_domain_nr); | ||
| 667 | |||
| 668 | /* Decide whether to display the domain number in /proc */ | 581 | /* Decide whether to display the domain number in /proc */ |
| 669 | int pci_proc_domain(struct pci_bus *bus) | 582 | int pci_proc_domain(struct pci_bus *bus) |
| 670 | { | 583 | { |
| @@ -676,281 +589,6 @@ int pci_proc_domain(struct pci_bus *bus) | |||
| 676 | } | 589 | } |
| 677 | } | 590 | } |
| 678 | 591 | ||
| 679 | /* | ||
| 680 | * Platform support for /proc/bus/pci/X/Y mmap()s, | ||
| 681 | * modelled on the sparc64 implementation by Dave Miller. | ||
| 682 | * -- paulus. | ||
| 683 | */ | ||
| 684 | |||
| 685 | /* | ||
| 686 | * Adjust vm_pgoff of VMA such that it is the physical page offset | ||
| 687 | * corresponding to the 32-bit pci bus offset for DEV requested by the user. | ||
| 688 | * | ||
| 689 | * Basically, the user finds the base address for his device which he wishes | ||
| 690 | * to mmap. They read the 32-bit value from the config space base register, | ||
| 691 | * add whatever PAGE_SIZE multiple offset they wish, and feed this into the | ||
| 692 | * offset parameter of mmap on /proc/bus/pci/XXX for that device. | ||
| 693 | * | ||
| 694 | * Returns negative error code on failure, zero on success. | ||
| 695 | */ | ||
| 696 | static struct resource *__pci_mmap_make_offset(struct pci_dev *dev, | ||
| 697 | resource_size_t *offset, | ||
| 698 | enum pci_mmap_state mmap_state) | ||
| 699 | { | ||
| 700 | struct pci_controller *hose = pci_bus_to_host(dev->bus); | ||
| 701 | unsigned long io_offset = 0; | ||
| 702 | int i, res_bit; | ||
| 703 | |||
| 704 | if (hose == 0) | ||
| 705 | return NULL; /* should never happen */ | ||
| 706 | |||
| 707 | /* If memory, add on the PCI bridge address offset */ | ||
| 708 | if (mmap_state == pci_mmap_mem) { | ||
| 709 | #if 0 /* See comment in pci_resource_to_user() for why this is disabled */ | ||
| 710 | *offset += hose->pci_mem_offset; | ||
| 711 | #endif | ||
| 712 | res_bit = IORESOURCE_MEM; | ||
| 713 | } else { | ||
| 714 | io_offset = (unsigned long)hose->io_base_virt - pci_io_base; | ||
| 715 | *offset += io_offset; | ||
| 716 | res_bit = IORESOURCE_IO; | ||
| 717 | } | ||
| 718 | |||
| 719 | /* | ||
| 720 | * Check that the offset requested corresponds to one of the | ||
| 721 | * resources of the device. | ||
| 722 | */ | ||
| 723 | for (i = 0; i <= PCI_ROM_RESOURCE; i++) { | ||
| 724 | struct resource *rp = &dev->resource[i]; | ||
| 725 | int flags = rp->flags; | ||
| 726 | |||
| 727 | /* treat ROM as memory (should be already) */ | ||
| 728 | if (i == PCI_ROM_RESOURCE) | ||
| 729 | flags |= IORESOURCE_MEM; | ||
| 730 | |||
| 731 | /* Active and same type? */ | ||
| 732 | if ((flags & res_bit) == 0) | ||
| 733 | continue; | ||
| 734 | |||
| 735 | /* In the range of this resource? */ | ||
| 736 | if (*offset < (rp->start & PAGE_MASK) || *offset > rp->end) | ||
| 737 | continue; | ||
| 738 | |||
| 739 | /* found it! construct the final physical address */ | ||
| 740 | if (mmap_state == pci_mmap_io) | ||
| 741 | *offset += hose->io_base_phys - io_offset; | ||
| 742 | return rp; | ||
| 743 | } | ||
| 744 | |||
| 745 | return NULL; | ||
| 746 | } | ||
| 747 | |||
| 748 | /* | ||
| 749 | * Set vm_page_prot of VMA, as appropriate for this architecture, for a pci | ||
| 750 | * device mapping. | ||
| 751 | */ | ||
| 752 | static pgprot_t __pci_mmap_set_pgprot(struct pci_dev *dev, struct resource *rp, | ||
| 753 | pgprot_t protection, | ||
| 754 | enum pci_mmap_state mmap_state, | ||
| 755 | int write_combine) | ||
| 756 | { | ||
| 757 | unsigned long prot = pgprot_val(protection); | ||
| 758 | |||
| 759 | /* Write combine is always 0 on non-memory space mappings. On | ||
| 760 | * memory space, if the user didn't pass 1, we check for a | ||
| 761 | * "prefetchable" resource. This is a bit hackish, but we use | ||
| 762 | * this to workaround the inability of /sysfs to provide a write | ||
| 763 | * combine bit | ||
| 764 | */ | ||
| 765 | if (mmap_state != pci_mmap_mem) | ||
| 766 | write_combine = 0; | ||
| 767 | else if (write_combine == 0) { | ||
| 768 | if (rp->flags & IORESOURCE_PREFETCH) | ||
| 769 | write_combine = 1; | ||
| 770 | } | ||
| 771 | |||
| 772 | /* XXX would be nice to have a way to ask for write-through */ | ||
| 773 | prot |= _PAGE_NO_CACHE; | ||
| 774 | if (write_combine) | ||
| 775 | prot &= ~_PAGE_GUARDED; | ||
| 776 | else | ||
| 777 | prot |= _PAGE_GUARDED; | ||
| 778 | |||
| 779 | return __pgprot(prot); | ||
| 780 | } | ||
| 781 | |||
| 782 | /* | ||
| 783 | * This one is used by /dev/mem and fbdev who have no clue about the | ||
| 784 | * PCI device, it tries to find the PCI device first and calls the | ||
| 785 | * above routine | ||
| 786 | */ | ||
| 787 | pgprot_t pci_phys_mem_access_prot(struct file *file, | ||
| 788 | unsigned long pfn, | ||
| 789 | unsigned long size, | ||
| 790 | pgprot_t protection) | ||
| 791 | { | ||
| 792 | struct pci_dev *pdev = NULL; | ||
| 793 | struct resource *found = NULL; | ||
| 794 | unsigned long prot = pgprot_val(protection); | ||
| 795 | unsigned long offset = pfn << PAGE_SHIFT; | ||
| 796 | int i; | ||
| 797 | |||
| 798 | if (page_is_ram(pfn)) | ||
| 799 | return __pgprot(prot); | ||
| 800 | |||
| 801 | prot |= _PAGE_NO_CACHE | _PAGE_GUARDED; | ||
| 802 | |||
| 803 | for_each_pci_dev(pdev) { | ||
| 804 | for (i = 0; i <= PCI_ROM_RESOURCE; i++) { | ||
| 805 | struct resource *rp = &pdev->resource[i]; | ||
| 806 | int flags = rp->flags; | ||
| 807 | |||
| 808 | /* Active and same type? */ | ||
| 809 | if ((flags & IORESOURCE_MEM) == 0) | ||
| 810 | continue; | ||
| 811 | /* In the range of this resource? */ | ||
| 812 | if (offset < (rp->start & PAGE_MASK) || | ||
| 813 | offset > rp->end) | ||
| 814 | continue; | ||
| 815 | found = rp; | ||
| 816 | break; | ||
| 817 | } | ||
| 818 | if (found) | ||
| 819 | break; | ||
| 820 | } | ||
| 821 | if (found) { | ||
| 822 | if (found->flags & IORESOURCE_PREFETCH) | ||
| 823 | prot &= ~_PAGE_GUARDED; | ||
| 824 | pci_dev_put(pdev); | ||
| 825 | } | ||
| 826 | |||
| 827 | DBG("non-PCI map for %lx, prot: %lx\n", offset, prot); | ||
| 828 | |||
| 829 | return __pgprot(prot); | ||
| 830 | } | ||
| 831 | |||
| 832 | |||
| 833 | /* | ||
| 834 | * Perform the actual remap of the pages for a PCI device mapping, as | ||
| 835 | * appropriate for this architecture. The region in the process to map | ||
| 836 | * is described by vm_start and vm_end members of VMA, the base physical | ||
| 837 | * address is found in vm_pgoff. | ||
| 838 | * The pci device structure is provided so that architectures may make mapping | ||
| 839 | * decisions on a per-device or per-bus basis. | ||
| 840 | * | ||
| 841 | * Returns a negative error code on failure, zero on success. | ||
| 842 | */ | ||
| 843 | int pci_mmap_page_range(struct pci_dev *dev, struct vm_area_struct *vma, | ||
| 844 | enum pci_mmap_state mmap_state, int write_combine) | ||
| 845 | { | ||
| 846 | resource_size_t offset = vma->vm_pgoff << PAGE_SHIFT; | ||
| 847 | struct resource *rp; | ||
| 848 | int ret; | ||
| 849 | |||
| 850 | rp = __pci_mmap_make_offset(dev, &offset, mmap_state); | ||
| 851 | if (rp == NULL) | ||
| 852 | return -EINVAL; | ||
| 853 | |||
| 854 | vma->vm_pgoff = offset >> PAGE_SHIFT; | ||
| 855 | vma->vm_page_prot = __pci_mmap_set_pgprot(dev, rp, | ||
| 856 | vma->vm_page_prot, | ||
| 857 | mmap_state, write_combine); | ||
| 858 | |||
| 859 | ret = remap_pfn_range(vma, vma->vm_start, vma->vm_pgoff, | ||
| 860 | vma->vm_end - vma->vm_start, vma->vm_page_prot); | ||
| 861 | |||
| 862 | return ret; | ||
| 863 | } | ||
| 864 | |||
| 865 | static ssize_t pci_show_devspec(struct device *dev, | ||
| 866 | struct device_attribute *attr, char *buf) | ||
| 867 | { | ||
| 868 | struct pci_dev *pdev; | ||
| 869 | struct device_node *np; | ||
| 870 | |||
| 871 | pdev = to_pci_dev (dev); | ||
| 872 | np = pci_device_to_OF_node(pdev); | ||
| 873 | if (np == NULL || np->full_name == NULL) | ||
| 874 | return 0; | ||
| 875 | return sprintf(buf, "%s", np->full_name); | ||
| 876 | } | ||
| 877 | static DEVICE_ATTR(devspec, S_IRUGO, pci_show_devspec, NULL); | ||
| 878 | |||
| 879 | void pcibios_add_platform_entries(struct pci_dev *pdev) | ||
| 880 | { | ||
| 881 | device_create_file(&pdev->dev, &dev_attr_devspec); | ||
| 882 | } | ||
| 883 | |||
| 884 | #define ISA_SPACE_MASK 0x1 | ||
| 885 | #define ISA_SPACE_IO 0x1 | ||
| 886 | |||
| 887 | static void __devinit pci_process_ISA_OF_ranges(struct device_node *isa_node, | ||
| 888 | unsigned long phb_io_base_phys, | ||
| 889 | void __iomem * phb_io_base_virt) | ||
| 890 | { | ||
| 891 | /* Remove these asap */ | ||
| 892 | |||
| 893 | struct pci_address { | ||
| 894 | u32 a_hi; | ||
| 895 | u32 a_mid; | ||
| 896 | u32 a_lo; | ||
| 897 | }; | ||
| 898 | |||
| 899 | struct isa_address { | ||
| 900 | u32 a_hi; | ||
| 901 | u32 a_lo; | ||
| 902 | }; | ||
| 903 | |||
| 904 | struct isa_range { | ||
| 905 | struct isa_address isa_addr; | ||
| 906 | struct pci_address pci_addr; | ||
| 907 | unsigned int size; | ||
| 908 | }; | ||
| 909 | |||
| 910 | const struct isa_range *range; | ||
| 911 | unsigned long pci_addr; | ||
| 912 | unsigned int isa_addr; | ||
| 913 | unsigned int size; | ||
| 914 | int rlen = 0; | ||
| 915 | |||
| 916 | range = of_get_property(isa_node, "ranges", &rlen); | ||
| 917 | if (range == NULL || (rlen < sizeof(struct isa_range))) { | ||
| 918 | printk(KERN_ERR "no ISA ranges or unexpected isa range size," | ||
| 919 | "mapping 64k\n"); | ||
| 920 | __ioremap_explicit(phb_io_base_phys, | ||
| 921 | (unsigned long)phb_io_base_virt, | ||
| 922 | 0x10000, _PAGE_NO_CACHE | _PAGE_GUARDED); | ||
| 923 | return; | ||
| 924 | } | ||
| 925 | |||
| 926 | /* From "ISA Binding to 1275" | ||
| 927 | * The ranges property is laid out as an array of elements, | ||
| 928 | * each of which comprises: | ||
| 929 | * cells 0 - 1: an ISA address | ||
| 930 | * cells 2 - 4: a PCI address | ||
| 931 | * (size depending on dev->n_addr_cells) | ||
| 932 | * cell 5: the size of the range | ||
| 933 | */ | ||
| 934 | if ((range->isa_addr.a_hi && ISA_SPACE_MASK) == ISA_SPACE_IO) { | ||
| 935 | isa_addr = range->isa_addr.a_lo; | ||
| 936 | pci_addr = (unsigned long) range->pci_addr.a_mid << 32 | | ||
| 937 | range->pci_addr.a_lo; | ||
| 938 | |||
| 939 | /* Assume these are both zero */ | ||
| 940 | if ((pci_addr != 0) || (isa_addr != 0)) { | ||
| 941 | printk(KERN_ERR "unexpected isa to pci mapping: %s\n", | ||
| 942 | __FUNCTION__); | ||
| 943 | return; | ||
| 944 | } | ||
| 945 | |||
| 946 | size = PAGE_ALIGN(range->size); | ||
| 947 | |||
| 948 | __ioremap_explicit(phb_io_base_phys, | ||
| 949 | (unsigned long) phb_io_base_virt, | ||
| 950 | size, _PAGE_NO_CACHE | _PAGE_GUARDED); | ||
| 951 | } | ||
| 952 | } | ||
| 953 | |||
| 954 | void __devinit pci_process_bridge_OF_ranges(struct pci_controller *hose, | 592 | void __devinit pci_process_bridge_OF_ranges(struct pci_controller *hose, |
| 955 | struct device_node *dev, int prim) | 593 | struct device_node *dev, int prim) |
| 956 | { | 594 | { |
| @@ -1045,155 +683,122 @@ void __devinit pci_process_bridge_OF_ranges(struct pci_controller *hose, | |||
| 1045 | } | 683 | } |
| 1046 | } | 684 | } |
| 1047 | 685 | ||
| 1048 | void __devinit pci_setup_phb_io(struct pci_controller *hose, int primary) | 686 | #ifdef CONFIG_HOTPLUG |
| 687 | |||
| 688 | int pcibios_unmap_io_space(struct pci_bus *bus) | ||
| 1049 | { | 689 | { |
| 1050 | unsigned long size = hose->pci_io_size; | 690 | struct pci_controller *hose; |
| 1051 | unsigned long io_virt_offset; | ||
| 1052 | struct resource *res; | ||
| 1053 | struct device_node *isa_dn; | ||
| 1054 | 691 | ||
| 1055 | if (size == 0) | 692 | WARN_ON(bus == NULL); |
| 1056 | return; | ||
| 1057 | 693 | ||
| 1058 | hose->io_base_virt = reserve_phb_iospace(size); | 694 | /* If this is not a PHB, we only flush the hash table over |
| 1059 | DBG("phb%d io_base_phys 0x%lx io_base_virt 0x%lx\n", | 695 | * the area mapped by this bridge. We don't play with the PTE |
| 1060 | hose->global_number, hose->io_base_phys, | 696 | * mappings since we might have to deal with sub-page alignemnts |
| 1061 | (unsigned long) hose->io_base_virt); | 697 | * so flushing the hash table is the only sane way to make sure |
| 1062 | 698 | * that no hash entries are covering that removed bridge area | |
| 1063 | if (primary) { | 699 | * while still allowing other busses overlapping those pages |
| 1064 | pci_io_base = (unsigned long)hose->io_base_virt; | 700 | */ |
| 1065 | isa_dn = of_find_node_by_type(NULL, "isa"); | 701 | if (bus->self) { |
| 1066 | if (isa_dn) { | 702 | struct resource *res = bus->resource[0]; |
| 1067 | isa_io_base = pci_io_base; | ||
| 1068 | pci_process_ISA_OF_ranges(isa_dn, hose->io_base_phys, | ||
| 1069 | hose->io_base_virt); | ||
| 1070 | of_node_put(isa_dn); | ||
| 1071 | } | ||
| 1072 | } | ||
| 1073 | 703 | ||
| 1074 | io_virt_offset = (unsigned long)hose->io_base_virt - pci_io_base; | 704 | DBG("IO unmapping for PCI-PCI bridge %s\n", |
| 1075 | res = &hose->io_resource; | 705 | pci_name(bus->self)); |
| 1076 | res->start += io_virt_offset; | ||
| 1077 | res->end += io_virt_offset; | ||
| 1078 | 706 | ||
| 1079 | /* If this is called after the initial PCI scan, then we need to | 707 | __flush_hash_table_range(&init_mm, res->start + _IO_BASE, |
| 1080 | * proceed to IO mappings now | 708 | res->end - res->start + 1); |
| 1081 | */ | 709 | return 0; |
| 1082 | if (pci_initial_scan_done) | 710 | } |
| 1083 | __ioremap_explicit(hose->io_base_phys, | ||
| 1084 | (unsigned long)hose->io_base_virt, | ||
| 1085 | hose->pci_io_size, | ||
| 1086 | _PAGE_NO_CACHE | _PAGE_GUARDED); | ||
| 1087 | } | ||
| 1088 | 711 | ||
| 1089 | void __devinit pci_setup_phb_io_dynamic(struct pci_controller *hose, | 712 | /* Get the host bridge */ |
| 1090 | int primary) | 713 | hose = pci_bus_to_host(bus); |
| 1091 | { | ||
| 1092 | unsigned long size = hose->pci_io_size; | ||
| 1093 | unsigned long io_virt_offset; | ||
| 1094 | struct resource *res; | ||
| 1095 | 714 | ||
| 1096 | if (size == 0) | 715 | /* Check if we have IOs allocated */ |
| 1097 | return; | 716 | if (hose->io_base_alloc == 0) |
| 717 | return 0; | ||
| 1098 | 718 | ||
| 1099 | hose->io_base_virt = __ioremap(hose->io_base_phys, size, | 719 | DBG("IO unmapping for PHB %s\n", |
| 1100 | _PAGE_NO_CACHE | _PAGE_GUARDED); | 720 | ((struct device_node *)hose->arch_data)->full_name); |
| 1101 | DBG("phb%d io_base_phys 0x%lx io_base_virt 0x%lx\n", | 721 | DBG(" alloc=0x%p\n", hose->io_base_alloc); |
| 1102 | hose->global_number, hose->io_base_phys, | ||
| 1103 | (unsigned long) hose->io_base_virt); | ||
| 1104 | 722 | ||
| 1105 | if (primary) | 723 | /* This is a PHB, we fully unmap the IO area */ |
| 1106 | pci_io_base = (unsigned long)hose->io_base_virt; | 724 | vunmap(hose->io_base_alloc); |
| 1107 | 725 | ||
| 1108 | io_virt_offset = (unsigned long)hose->io_base_virt - pci_io_base; | 726 | return 0; |
| 1109 | res = &hose->io_resource; | ||
| 1110 | res->start += io_virt_offset; | ||
| 1111 | res->end += io_virt_offset; | ||
| 1112 | } | 727 | } |
| 728 | EXPORT_SYMBOL_GPL(pcibios_unmap_io_space); | ||
| 1113 | 729 | ||
| 730 | #endif /* CONFIG_HOTPLUG */ | ||
| 1114 | 731 | ||
| 1115 | static int get_bus_io_range(struct pci_bus *bus, unsigned long *start_phys, | 732 | int __devinit pcibios_map_io_space(struct pci_bus *bus) |
| 1116 | unsigned long *start_virt, unsigned long *size) | ||
| 1117 | { | 733 | { |
| 1118 | struct pci_controller *hose = pci_bus_to_host(bus); | 734 | struct vm_struct *area; |
| 1119 | struct resource *res; | 735 | unsigned long phys_page; |
| 1120 | 736 | unsigned long size_page; | |
| 1121 | if (bus->self) | 737 | unsigned long io_virt_offset; |
| 1122 | res = bus->resource[0]; | 738 | struct pci_controller *hose; |
| 1123 | else | ||
| 1124 | /* Root Bus */ | ||
| 1125 | res = &hose->io_resource; | ||
| 1126 | |||
| 1127 | if (res->end == 0 && res->start == 0) | ||
| 1128 | return 1; | ||
| 1129 | 739 | ||
| 1130 | *start_virt = pci_io_base + res->start; | 740 | WARN_ON(bus == NULL); |
| 1131 | *start_phys = *start_virt + hose->io_base_phys | ||
| 1132 | - (unsigned long) hose->io_base_virt; | ||
| 1133 | 741 | ||
| 1134 | if (res->end > res->start) | 742 | /* If this not a PHB, nothing to do, page tables still exist and |
| 1135 | *size = res->end - res->start + 1; | 743 | * thus HPTEs will be faulted in when needed |
| 1136 | else { | 744 | */ |
| 1137 | printk("%s(): unexpected region 0x%lx->0x%lx\n", | 745 | if (bus->self) { |
| 1138 | __FUNCTION__, res->start, res->end); | 746 | DBG("IO mapping for PCI-PCI bridge %s\n", |
| 1139 | return 1; | 747 | pci_name(bus->self)); |
| 748 | DBG(" virt=0x%016lx...0x%016lx\n", | ||
| 749 | bus->resource[0]->start + _IO_BASE, | ||
| 750 | bus->resource[0]->end + _IO_BASE); | ||
| 751 | return 0; | ||
| 1140 | } | 752 | } |
| 1141 | 753 | ||
| 1142 | return 0; | 754 | /* Get the host bridge */ |
| 1143 | } | 755 | hose = pci_bus_to_host(bus); |
| 1144 | 756 | phys_page = _ALIGN_DOWN(hose->io_base_phys, PAGE_SIZE); | |
| 1145 | int unmap_bus_range(struct pci_bus *bus) | 757 | size_page = _ALIGN_UP(hose->pci_io_size, PAGE_SIZE); |
| 1146 | { | ||
| 1147 | unsigned long start_phys; | ||
| 1148 | unsigned long start_virt; | ||
| 1149 | unsigned long size; | ||
| 1150 | 758 | ||
| 1151 | if (!bus) { | 759 | /* Make sure IO area address is clear */ |
| 1152 | printk(KERN_ERR "%s() expected bus\n", __FUNCTION__); | 760 | hose->io_base_alloc = NULL; |
| 1153 | return 1; | ||
| 1154 | } | ||
| 1155 | |||
| 1156 | if (get_bus_io_range(bus, &start_phys, &start_virt, &size)) | ||
| 1157 | return 1; | ||
| 1158 | if (__iounmap_explicit((void __iomem *) start_virt, size)) | ||
| 1159 | return 1; | ||
| 1160 | |||
| 1161 | return 0; | ||
| 1162 | } | ||
| 1163 | EXPORT_SYMBOL(unmap_bus_range); | ||
| 1164 | 761 | ||
| 1165 | int remap_bus_range(struct pci_bus *bus) | 762 | /* If there's no IO to map on that bus, get away too */ |
| 1166 | { | 763 | if (hose->pci_io_size == 0 || hose->io_base_phys == 0) |
| 1167 | unsigned long start_phys; | 764 | return 0; |
| 1168 | unsigned long start_virt; | ||
| 1169 | unsigned long size; | ||
| 1170 | 765 | ||
| 1171 | if (!bus) { | 766 | /* Let's allocate some IO space for that guy. We don't pass |
| 1172 | printk(KERN_ERR "%s() expected bus\n", __FUNCTION__); | 767 | * VM_IOREMAP because we don't care about alignment tricks that |
| 1173 | return 1; | 768 | * the core does in that case. Maybe we should due to stupid card |
| 1174 | } | 769 | * with incomplete address decoding but I'd rather not deal with |
| 1175 | 770 | * those outside of the reserved 64K legacy region. | |
| 1176 | 771 | */ | |
| 1177 | if (get_bus_io_range(bus, &start_phys, &start_virt, &size)) | 772 | area = __get_vm_area(size_page, 0, PHB_IO_BASE, PHB_IO_END); |
| 1178 | return 1; | 773 | if (area == NULL) |
| 1179 | if (start_phys == 0) | 774 | return -ENOMEM; |
| 1180 | return 1; | 775 | hose->io_base_alloc = area->addr; |
| 1181 | printk(KERN_DEBUG "mapping IO %lx -> %lx, size: %lx\n", start_phys, start_virt, size); | 776 | hose->io_base_virt = (void __iomem *)(area->addr + |
| 1182 | if (__ioremap_explicit(start_phys, start_virt, size, | 777 | hose->io_base_phys - phys_page); |
| 1183 | _PAGE_NO_CACHE | _PAGE_GUARDED)) | 778 | |
| 1184 | return 1; | 779 | DBG("IO mapping for PHB %s\n", |
| 780 | ((struct device_node *)hose->arch_data)->full_name); | ||
| 781 | DBG(" phys=0x%016lx, virt=0x%p (alloc=0x%p)\n", | ||
| 782 | hose->io_base_phys, hose->io_base_virt, hose->io_base_alloc); | ||
| 783 | DBG(" size=0x%016lx (alloc=0x%016lx)\n", | ||
| 784 | hose->pci_io_size, size_page); | ||
| 785 | |||
| 786 | /* Establish the mapping */ | ||
| 787 | if (__ioremap_at(phys_page, area->addr, size_page, | ||
| 788 | _PAGE_NO_CACHE | _PAGE_GUARDED) == NULL) | ||
| 789 | return -ENOMEM; | ||
| 790 | |||
| 791 | /* Fixup hose IO resource */ | ||
| 792 | io_virt_offset = (unsigned long)hose->io_base_virt - _IO_BASE; | ||
| 793 | hose->io_resource.start += io_virt_offset; | ||
| 794 | hose->io_resource.end += io_virt_offset; | ||
| 795 | |||
| 796 | DBG(" hose->io_resource=0x%016lx...0x%016lx\n", | ||
| 797 | hose->io_resource.start, hose->io_resource.end); | ||
| 1185 | 798 | ||
| 1186 | return 0; | 799 | return 0; |
| 1187 | } | 800 | } |
| 1188 | EXPORT_SYMBOL(remap_bus_range); | 801 | EXPORT_SYMBOL_GPL(pcibios_map_io_space); |
| 1189 | |||
| 1190 | static void phbs_remap_io(void) | ||
| 1191 | { | ||
| 1192 | struct pci_controller *hose, *tmp; | ||
| 1193 | |||
| 1194 | list_for_each_entry_safe(hose, tmp, &hose_list, list_node) | ||
| 1195 | remap_bus_range(hose->bus); | ||
| 1196 | } | ||
| 1197 | 802 | ||
| 1198 | static void __devinit fixup_resource(struct resource *res, struct pci_dev *dev) | 803 | static void __devinit fixup_resource(struct resource *res, struct pci_dev *dev) |
| 1199 | { | 804 | { |
| @@ -1201,8 +806,7 @@ static void __devinit fixup_resource(struct resource *res, struct pci_dev *dev) | |||
| 1201 | unsigned long offset; | 806 | unsigned long offset; |
| 1202 | 807 | ||
| 1203 | if (res->flags & IORESOURCE_IO) { | 808 | if (res->flags & IORESOURCE_IO) { |
| 1204 | offset = (unsigned long)hose->io_base_virt - pci_io_base; | 809 | offset = (unsigned long)hose->io_base_virt - _IO_BASE; |
| 1205 | |||
| 1206 | res->start += offset; | 810 | res->start += offset; |
| 1207 | res->end += offset; | 811 | res->end += offset; |
| 1208 | } else if (res->flags & IORESOURCE_MEM) { | 812 | } else if (res->flags & IORESOURCE_MEM) { |
| @@ -1217,9 +821,20 @@ void __devinit pcibios_fixup_device_resources(struct pci_dev *dev, | |||
| 1217 | /* Update device resources. */ | 821 | /* Update device resources. */ |
| 1218 | int i; | 822 | int i; |
| 1219 | 823 | ||
| 1220 | for (i = 0; i < PCI_NUM_RESOURCES; i++) | 824 | DBG("%s: Fixup resources:\n", pci_name(dev)); |
| 1221 | if (dev->resource[i].flags) | 825 | for (i = 0; i < PCI_NUM_RESOURCES; i++) { |
| 1222 | fixup_resource(&dev->resource[i], dev); | 826 | struct resource *res = &dev->resource[i]; |
| 827 | if (!res->flags) | ||
| 828 | continue; | ||
| 829 | |||
| 830 | DBG(" 0x%02x < %08lx:0x%016lx...0x%016lx\n", | ||
| 831 | i, res->flags, res->start, res->end); | ||
| 832 | |||
| 833 | fixup_resource(res, dev); | ||
| 834 | |||
| 835 | DBG(" > %08lx:0x%016lx...0x%016lx\n", | ||
| 836 | res->flags, res->start, res->end); | ||
| 837 | } | ||
| 1223 | } | 838 | } |
| 1224 | EXPORT_SYMBOL(pcibios_fixup_device_resources); | 839 | EXPORT_SYMBOL(pcibios_fixup_device_resources); |
| 1225 | 840 | ||
| @@ -1289,119 +904,6 @@ void __devinit pcibios_fixup_bus(struct pci_bus *bus) | |||
| 1289 | } | 904 | } |
| 1290 | EXPORT_SYMBOL(pcibios_fixup_bus); | 905 | EXPORT_SYMBOL(pcibios_fixup_bus); |
| 1291 | 906 | ||
| 1292 | /* | ||
| 1293 | * Reads the interrupt pin to determine if interrupt is use by card. | ||
| 1294 | * If the interrupt is used, then gets the interrupt line from the | ||
| 1295 | * openfirmware and sets it in the pci_dev and pci_config line. | ||
| 1296 | */ | ||
| 1297 | int pci_read_irq_line(struct pci_dev *pci_dev) | ||
| 1298 | { | ||
| 1299 | struct of_irq oirq; | ||
| 1300 | unsigned int virq; | ||
| 1301 | |||
| 1302 | DBG("Try to map irq for %s...\n", pci_name(pci_dev)); | ||
| 1303 | |||
| 1304 | #ifdef DEBUG | ||
| 1305 | memset(&oirq, 0xff, sizeof(oirq)); | ||
| 1306 | #endif | ||
| 1307 | /* Try to get a mapping from the device-tree */ | ||
| 1308 | if (of_irq_map_pci(pci_dev, &oirq)) { | ||
| 1309 | u8 line, pin; | ||
| 1310 | |||
| 1311 | /* If that fails, lets fallback to what is in the config | ||
| 1312 | * space and map that through the default controller. We | ||
| 1313 | * also set the type to level low since that's what PCI | ||
| 1314 | * interrupts are. If your platform does differently, then | ||
| 1315 | * either provide a proper interrupt tree or don't use this | ||
| 1316 | * function. | ||
| 1317 | */ | ||
| 1318 | if (pci_read_config_byte(pci_dev, PCI_INTERRUPT_PIN, &pin)) | ||
| 1319 | return -1; | ||
| 1320 | if (pin == 0) | ||
| 1321 | return -1; | ||
| 1322 | if (pci_read_config_byte(pci_dev, PCI_INTERRUPT_LINE, &line) || | ||
| 1323 | line == 0xff) { | ||
| 1324 | return -1; | ||
| 1325 | } | ||
| 1326 | DBG(" -> no map ! Using irq line %d from PCI config\n", line); | ||
| 1327 | |||
| 1328 | virq = irq_create_mapping(NULL, line); | ||
| 1329 | if (virq != NO_IRQ) | ||
| 1330 | set_irq_type(virq, IRQ_TYPE_LEVEL_LOW); | ||
| 1331 | } else { | ||
| 1332 | DBG(" -> got one, spec %d cells (0x%08x 0x%08x...) on %s\n", | ||
| 1333 | oirq.size, oirq.specifier[0], oirq.specifier[1], | ||
| 1334 | oirq.controller->full_name); | ||
| 1335 | |||
| 1336 | virq = irq_create_of_mapping(oirq.controller, oirq.specifier, | ||
| 1337 | oirq.size); | ||
| 1338 | } | ||
| 1339 | if(virq == NO_IRQ) { | ||
| 1340 | DBG(" -> failed to map !\n"); | ||
| 1341 | return -1; | ||
| 1342 | } | ||
| 1343 | |||
| 1344 | DBG(" -> mapped to linux irq %d\n", virq); | ||
| 1345 | |||
| 1346 | pci_dev->irq = virq; | ||
| 1347 | |||
| 1348 | return 0; | ||
| 1349 | } | ||
| 1350 | EXPORT_SYMBOL(pci_read_irq_line); | ||
| 1351 | |||
| 1352 | void pci_resource_to_user(const struct pci_dev *dev, int bar, | ||
| 1353 | const struct resource *rsrc, | ||
| 1354 | resource_size_t *start, resource_size_t *end) | ||
| 1355 | { | ||
| 1356 | struct pci_controller *hose = pci_bus_to_host(dev->bus); | ||
| 1357 | resource_size_t offset = 0; | ||
| 1358 | |||
| 1359 | if (hose == NULL) | ||
| 1360 | return; | ||
| 1361 | |||
| 1362 | if (rsrc->flags & IORESOURCE_IO) | ||
| 1363 | offset = (unsigned long)hose->io_base_virt - pci_io_base; | ||
| 1364 | |||
| 1365 | /* We pass a fully fixed up address to userland for MMIO instead of | ||
| 1366 | * a BAR value because X is lame and expects to be able to use that | ||
| 1367 | * to pass to /dev/mem ! | ||
| 1368 | * | ||
| 1369 | * That means that we'll have potentially 64 bits values where some | ||
| 1370 | * userland apps only expect 32 (like X itself since it thinks only | ||
| 1371 | * Sparc has 64 bits MMIO) but if we don't do that, we break it on | ||
| 1372 | * 32 bits CHRPs :-( | ||
| 1373 | * | ||
| 1374 | * Hopefully, the sysfs insterface is immune to that gunk. Once X | ||
| 1375 | * has been fixed (and the fix spread enough), we can re-enable the | ||
| 1376 | * 2 lines below and pass down a BAR value to userland. In that case | ||
| 1377 | * we'll also have to re-enable the matching code in | ||
| 1378 | * __pci_mmap_make_offset(). | ||
| 1379 | * | ||
| 1380 | * BenH. | ||
| 1381 | */ | ||
| 1382 | #if 0 | ||
| 1383 | else if (rsrc->flags & IORESOURCE_MEM) | ||
| 1384 | offset = hose->pci_mem_offset; | ||
| 1385 | #endif | ||
| 1386 | |||
| 1387 | *start = rsrc->start - offset; | ||
| 1388 | *end = rsrc->end - offset; | ||
| 1389 | } | ||
| 1390 | |||
| 1391 | struct pci_controller* pci_find_hose_for_OF_device(struct device_node* node) | ||
| 1392 | { | ||
| 1393 | if (!have_of) | ||
| 1394 | return NULL; | ||
| 1395 | while(node) { | ||
| 1396 | struct pci_controller *hose, *tmp; | ||
| 1397 | list_for_each_entry_safe(hose, tmp, &hose_list, list_node) | ||
| 1398 | if (hose->arch_data == node) | ||
| 1399 | return hose; | ||
| 1400 | node = node->parent; | ||
| 1401 | } | ||
| 1402 | return NULL; | ||
| 1403 | } | ||
| 1404 | |||
| 1405 | unsigned long pci_address_to_pio(phys_addr_t address) | 907 | unsigned long pci_address_to_pio(phys_addr_t address) |
| 1406 | { | 908 | { |
| 1407 | struct pci_controller *hose, *tmp; | 909 | struct pci_controller *hose, *tmp; |
| @@ -1410,7 +912,7 @@ unsigned long pci_address_to_pio(phys_addr_t address) | |||
| 1410 | if (address >= hose->io_base_phys && | 912 | if (address >= hose->io_base_phys && |
| 1411 | address < (hose->io_base_phys + hose->pci_io_size)) { | 913 | address < (hose->io_base_phys + hose->pci_io_size)) { |
| 1412 | unsigned long base = | 914 | unsigned long base = |
| 1413 | (unsigned long)hose->io_base_virt - pci_io_base; | 915 | (unsigned long)hose->io_base_virt - _IO_BASE; |
| 1414 | return base + (address - hose->io_base_phys); | 916 | return base + (address - hose->io_base_phys); |
| 1415 | } | 917 | } |
| 1416 | } | 918 | } |
diff --git a/arch/powerpc/kernel/ppc_ksyms.c b/arch/powerpc/kernel/ppc_ksyms.c index c96fa9bd35a4..a20f1951a5ce 100644 --- a/arch/powerpc/kernel/ppc_ksyms.c +++ b/arch/powerpc/kernel/ppc_ksyms.c | |||
| @@ -67,7 +67,6 @@ EXPORT_SYMBOL(ISA_DMA_THRESHOLD); | |||
| 67 | EXPORT_SYMBOL(DMA_MODE_READ); | 67 | EXPORT_SYMBOL(DMA_MODE_READ); |
| 68 | EXPORT_SYMBOL(DMA_MODE_WRITE); | 68 | EXPORT_SYMBOL(DMA_MODE_WRITE); |
| 69 | 69 | ||
| 70 | EXPORT_SYMBOL(do_signal); | ||
| 71 | EXPORT_SYMBOL(transfer_to_handler); | 70 | EXPORT_SYMBOL(transfer_to_handler); |
| 72 | EXPORT_SYMBOL(do_IRQ); | 71 | EXPORT_SYMBOL(do_IRQ); |
| 73 | EXPORT_SYMBOL(machine_check_exception); | 72 | EXPORT_SYMBOL(machine_check_exception); |
| @@ -106,10 +105,6 @@ EXPORT_SYMBOL(isa_mem_base); | |||
| 106 | EXPORT_SYMBOL(pci_dram_offset); | 105 | EXPORT_SYMBOL(pci_dram_offset); |
| 107 | EXPORT_SYMBOL(pci_alloc_consistent); | 106 | EXPORT_SYMBOL(pci_alloc_consistent); |
| 108 | EXPORT_SYMBOL(pci_free_consistent); | 107 | EXPORT_SYMBOL(pci_free_consistent); |
| 109 | EXPORT_SYMBOL(pci_bus_io_base); | ||
| 110 | EXPORT_SYMBOL(pci_bus_io_base_phys); | ||
| 111 | EXPORT_SYMBOL(pci_bus_mem_base_phys); | ||
| 112 | EXPORT_SYMBOL(pci_bus_to_hose); | ||
| 113 | #endif /* CONFIG_PCI */ | 108 | #endif /* CONFIG_PCI */ |
| 114 | 109 | ||
| 115 | EXPORT_SYMBOL(start_thread); | 110 | EXPORT_SYMBOL(start_thread); |
diff --git a/arch/powerpc/kernel/process.c b/arch/powerpc/kernel/process.c index 6e2f03566b0d..84f000a45e36 100644 --- a/arch/powerpc/kernel/process.c +++ b/arch/powerpc/kernel/process.c | |||
| @@ -219,22 +219,26 @@ void discard_lazy_cpu_state(void) | |||
| 219 | } | 219 | } |
| 220 | #endif /* CONFIG_SMP */ | 220 | #endif /* CONFIG_SMP */ |
| 221 | 221 | ||
| 222 | #ifdef CONFIG_PPC_MERGE /* XXX for now */ | ||
| 223 | int set_dabr(unsigned long dabr) | 222 | int set_dabr(unsigned long dabr) |
| 224 | { | 223 | { |
| 224 | #ifdef CONFIG_PPC_MERGE /* XXX for now */ | ||
| 225 | if (ppc_md.set_dabr) | 225 | if (ppc_md.set_dabr) |
| 226 | return ppc_md.set_dabr(dabr); | 226 | return ppc_md.set_dabr(dabr); |
| 227 | #endif | ||
| 227 | 228 | ||
| 229 | /* XXX should we have a CPU_FTR_HAS_DABR ? */ | ||
| 230 | #if defined(CONFIG_PPC64) || defined(CONFIG_6xx) | ||
| 228 | mtspr(SPRN_DABR, dabr); | 231 | mtspr(SPRN_DABR, dabr); |
| 232 | #endif | ||
| 229 | return 0; | 233 | return 0; |
| 230 | } | 234 | } |
| 231 | #endif | ||
| 232 | 235 | ||
| 233 | #ifdef CONFIG_PPC64 | 236 | #ifdef CONFIG_PPC64 |
| 234 | DEFINE_PER_CPU(struct cpu_usage, cpu_usage_array); | 237 | DEFINE_PER_CPU(struct cpu_usage, cpu_usage_array); |
| 235 | static DEFINE_PER_CPU(unsigned long, current_dabr); | ||
| 236 | #endif | 238 | #endif |
| 237 | 239 | ||
| 240 | static DEFINE_PER_CPU(unsigned long, current_dabr); | ||
| 241 | |||
| 238 | struct task_struct *__switch_to(struct task_struct *prev, | 242 | struct task_struct *__switch_to(struct task_struct *prev, |
| 239 | struct task_struct *new) | 243 | struct task_struct *new) |
| 240 | { | 244 | { |
| @@ -299,12 +303,10 @@ struct task_struct *__switch_to(struct task_struct *prev, | |||
| 299 | 303 | ||
| 300 | #endif /* CONFIG_SMP */ | 304 | #endif /* CONFIG_SMP */ |
| 301 | 305 | ||
| 302 | #ifdef CONFIG_PPC64 /* for now */ | ||
| 303 | if (unlikely(__get_cpu_var(current_dabr) != new->thread.dabr)) { | 306 | if (unlikely(__get_cpu_var(current_dabr) != new->thread.dabr)) { |
| 304 | set_dabr(new->thread.dabr); | 307 | set_dabr(new->thread.dabr); |
| 305 | __get_cpu_var(current_dabr) = new->thread.dabr; | 308 | __get_cpu_var(current_dabr) = new->thread.dabr; |
| 306 | } | 309 | } |
| 307 | #endif /* CONFIG_PPC64 */ | ||
| 308 | 310 | ||
| 309 | new_thread = &new->thread; | 311 | new_thread = &new->thread; |
| 310 | old_thread = ¤t->thread; | 312 | old_thread = ¤t->thread; |
| @@ -473,12 +475,10 @@ void flush_thread(void) | |||
| 473 | 475 | ||
| 474 | discard_lazy_cpu_state(); | 476 | discard_lazy_cpu_state(); |
| 475 | 477 | ||
| 476 | #ifdef CONFIG_PPC64 /* for now */ | ||
| 477 | if (current->thread.dabr) { | 478 | if (current->thread.dabr) { |
| 478 | current->thread.dabr = 0; | 479 | current->thread.dabr = 0; |
| 479 | set_dabr(0); | 480 | set_dabr(0); |
| 480 | } | 481 | } |
| 481 | #endif | ||
| 482 | } | 482 | } |
| 483 | 483 | ||
| 484 | void | 484 | void |
diff --git a/arch/powerpc/kernel/prom.c b/arch/powerpc/kernel/prom.c index af42ddab3ab4..37ff99bd98b4 100644 --- a/arch/powerpc/kernel/prom.c +++ b/arch/powerpc/kernel/prom.c | |||
| @@ -52,6 +52,7 @@ | |||
| 52 | #include <asm/pSeries_reconfig.h> | 52 | #include <asm/pSeries_reconfig.h> |
| 53 | #include <asm/pci-bridge.h> | 53 | #include <asm/pci-bridge.h> |
| 54 | #include <asm/kexec.h> | 54 | #include <asm/kexec.h> |
| 55 | #include <asm/system.h> | ||
| 55 | 56 | ||
| 56 | #ifdef DEBUG | 57 | #ifdef DEBUG |
| 57 | #define DBG(fmt...) printk(KERN_ERR fmt) | 58 | #define DBG(fmt...) printk(KERN_ERR fmt) |
| @@ -1005,7 +1006,7 @@ static void __init early_reserve_mem(void) | |||
| 1005 | 1006 | ||
| 1006 | void __init early_init_devtree(void *params) | 1007 | void __init early_init_devtree(void *params) |
| 1007 | { | 1008 | { |
| 1008 | DBG(" -> early_init_devtree()\n"); | 1009 | DBG(" -> early_init_devtree(%p)\n", params); |
| 1009 | 1010 | ||
| 1010 | /* Setup flat device-tree pointer */ | 1011 | /* Setup flat device-tree pointer */ |
| 1011 | initial_boot_params = params; | 1012 | initial_boot_params = params; |
| @@ -1055,8 +1056,6 @@ void __init early_init_devtree(void *params) | |||
| 1055 | DBG(" <- early_init_devtree()\n"); | 1056 | DBG(" <- early_init_devtree()\n"); |
| 1056 | } | 1057 | } |
| 1057 | 1058 | ||
| 1058 | #undef printk | ||
| 1059 | |||
| 1060 | int of_n_addr_cells(struct device_node* np) | 1059 | int of_n_addr_cells(struct device_node* np) |
| 1061 | { | 1060 | { |
| 1062 | const int *ip; | 1061 | const int *ip; |
| @@ -1375,8 +1374,17 @@ static void of_node_release(struct kref *kref) | |||
| 1375 | struct device_node *node = kref_to_device_node(kref); | 1374 | struct device_node *node = kref_to_device_node(kref); |
| 1376 | struct property *prop = node->properties; | 1375 | struct property *prop = node->properties; |
| 1377 | 1376 | ||
| 1378 | if (!OF_IS_DYNAMIC(node)) | 1377 | /* We should never be releasing nodes that haven't been detached. */ |
| 1378 | if (!of_node_check_flag(node, OF_DETACHED)) { | ||
| 1379 | printk("WARNING: Bad of_node_put() on %s\n", node->full_name); | ||
| 1380 | dump_stack(); | ||
| 1381 | kref_init(&node->kref); | ||
| 1382 | return; | ||
| 1383 | } | ||
| 1384 | |||
| 1385 | if (!of_node_check_flag(node, OF_DYNAMIC)) | ||
| 1379 | return; | 1386 | return; |
| 1387 | |||
| 1380 | while (prop) { | 1388 | while (prop) { |
| 1381 | struct property *next = prop->next; | 1389 | struct property *next = prop->next; |
| 1382 | kfree(prop->name); | 1390 | kfree(prop->name); |
| @@ -1432,6 +1440,8 @@ void of_detach_node(const struct device_node *np) | |||
| 1432 | write_lock(&devtree_lock); | 1440 | write_lock(&devtree_lock); |
| 1433 | 1441 | ||
| 1434 | parent = np->parent; | 1442 | parent = np->parent; |
| 1443 | if (!parent) | ||
| 1444 | goto out_unlock; | ||
| 1435 | 1445 | ||
| 1436 | if (allnodes == np) | 1446 | if (allnodes == np) |
| 1437 | allnodes = np->allnext; | 1447 | allnodes = np->allnext; |
| @@ -1455,6 +1465,9 @@ void of_detach_node(const struct device_node *np) | |||
| 1455 | prevsib->sibling = np->sibling; | 1465 | prevsib->sibling = np->sibling; |
| 1456 | } | 1466 | } |
| 1457 | 1467 | ||
| 1468 | of_node_set_flag(np, OF_DETACHED); | ||
| 1469 | |||
| 1470 | out_unlock: | ||
| 1458 | write_unlock(&devtree_lock); | 1471 | write_unlock(&devtree_lock); |
| 1459 | } | 1472 | } |
| 1460 | 1473 | ||
| @@ -1716,22 +1729,18 @@ struct device_node *of_get_cpu_node(int cpu, unsigned int *thread) | |||
| 1716 | } | 1729 | } |
| 1717 | EXPORT_SYMBOL(of_get_cpu_node); | 1730 | EXPORT_SYMBOL(of_get_cpu_node); |
| 1718 | 1731 | ||
| 1719 | #ifdef DEBUG | 1732 | #if defined(CONFIG_DEBUG_FS) && defined(DEBUG) |
| 1720 | static struct debugfs_blob_wrapper flat_dt_blob; | 1733 | static struct debugfs_blob_wrapper flat_dt_blob; |
| 1721 | 1734 | ||
| 1722 | static int __init export_flat_device_tree(void) | 1735 | static int __init export_flat_device_tree(void) |
| 1723 | { | 1736 | { |
| 1724 | struct dentry *d; | 1737 | struct dentry *d; |
| 1725 | 1738 | ||
| 1726 | d = debugfs_create_dir("powerpc", NULL); | ||
| 1727 | if (!d) | ||
| 1728 | return 1; | ||
| 1729 | |||
| 1730 | flat_dt_blob.data = initial_boot_params; | 1739 | flat_dt_blob.data = initial_boot_params; |
| 1731 | flat_dt_blob.size = initial_boot_params->totalsize; | 1740 | flat_dt_blob.size = initial_boot_params->totalsize; |
| 1732 | 1741 | ||
| 1733 | d = debugfs_create_blob("flat-device-tree", S_IFREG | S_IRUSR, | 1742 | d = debugfs_create_blob("flat-device-tree", S_IFREG | S_IRUSR, |
| 1734 | d, &flat_dt_blob); | 1743 | powerpc_debugfs_root, &flat_dt_blob); |
| 1735 | if (!d) | 1744 | if (!d) |
| 1736 | return 1; | 1745 | return 1; |
| 1737 | 1746 | ||
diff --git a/arch/powerpc/kernel/prom_init.c b/arch/powerpc/kernel/prom_init.c index d6047c441034..a1d582e38627 100644 --- a/arch/powerpc/kernel/prom_init.c +++ b/arch/powerpc/kernel/prom_init.c | |||
| @@ -635,6 +635,7 @@ static void __init early_cmdline_parse(void) | |||
| 635 | /* ibm,dynamic-reconfiguration-memory property supported */ | 635 | /* ibm,dynamic-reconfiguration-memory property supported */ |
| 636 | #define OV5_DRCONF_MEMORY 0x20 | 636 | #define OV5_DRCONF_MEMORY 0x20 |
| 637 | #define OV5_LARGE_PAGES 0x10 /* large pages supported */ | 637 | #define OV5_LARGE_PAGES 0x10 /* large pages supported */ |
| 638 | #define OV5_DONATE_DEDICATE_CPU 0x02 /* donate dedicated CPU support */ | ||
| 638 | /* PCIe/MSI support. Without MSI full PCIe is not supported */ | 639 | /* PCIe/MSI support. Without MSI full PCIe is not supported */ |
| 639 | #ifdef CONFIG_PCI_MSI | 640 | #ifdef CONFIG_PCI_MSI |
| 640 | #define OV5_MSI 0x01 /* PCIe/MSI support */ | 641 | #define OV5_MSI 0x01 /* PCIe/MSI support */ |
| @@ -685,7 +686,8 @@ static unsigned char ibm_architecture_vec[] = { | |||
| 685 | /* option vector 5: PAPR/OF options */ | 686 | /* option vector 5: PAPR/OF options */ |
| 686 | 3 - 2, /* length */ | 687 | 3 - 2, /* length */ |
| 687 | 0, /* don't ignore, don't halt */ | 688 | 0, /* don't ignore, don't halt */ |
| 688 | OV5_LPAR | OV5_SPLPAR | OV5_LARGE_PAGES | OV5_DRCONF_MEMORY | OV5_MSI, | 689 | OV5_LPAR | OV5_SPLPAR | OV5_LARGE_PAGES | OV5_DRCONF_MEMORY | |
| 690 | OV5_DONATE_DEDICATE_CPU | OV5_MSI, | ||
| 689 | }; | 691 | }; |
| 690 | 692 | ||
| 691 | /* Old method - ELF header with PT_NOTE sections */ | 693 | /* Old method - ELF header with PT_NOTE sections */ |
diff --git a/arch/powerpc/kernel/ptrace-common.h b/arch/powerpc/kernel/ptrace-common.h deleted file mode 100644 index 8797ae737a7b..000000000000 --- a/arch/powerpc/kernel/ptrace-common.h +++ /dev/null | |||
| @@ -1,161 +0,0 @@ | |||
| 1 | /* | ||
| 2 | * Copyright (c) 2002 Stephen Rothwell, IBM Coproration | ||
| 3 | * Extracted from ptrace.c and ptrace32.c | ||
| 4 | * | ||
| 5 | * This file is subject to the terms and conditions of the GNU General | ||
| 6 | * Public License. See the file README.legal in the main directory of | ||
| 7 | * this archive for more details. | ||
| 8 | */ | ||
| 9 | |||
| 10 | #ifndef _PPC64_PTRACE_COMMON_H | ||
| 11 | #define _PPC64_PTRACE_COMMON_H | ||
| 12 | |||
| 13 | #include <asm/system.h> | ||
| 14 | |||
| 15 | /* | ||
| 16 | * Set of msr bits that gdb can change on behalf of a process. | ||
| 17 | */ | ||
| 18 | #define MSR_DEBUGCHANGE (MSR_FE0 | MSR_SE | MSR_BE | MSR_FE1) | ||
| 19 | |||
| 20 | /* | ||
| 21 | * Get contents of register REGNO in task TASK. | ||
| 22 | */ | ||
| 23 | static inline unsigned long get_reg(struct task_struct *task, int regno) | ||
| 24 | { | ||
| 25 | unsigned long tmp = 0; | ||
| 26 | |||
| 27 | /* | ||
| 28 | * Put the correct FP bits in, they might be wrong as a result | ||
| 29 | * of our lazy FP restore. | ||
| 30 | */ | ||
| 31 | if (regno == PT_MSR) { | ||
| 32 | tmp = ((unsigned long *)task->thread.regs)[PT_MSR]; | ||
| 33 | tmp |= task->thread.fpexc_mode; | ||
| 34 | } else if (regno < (sizeof(struct pt_regs) / sizeof(unsigned long))) { | ||
| 35 | tmp = ((unsigned long *)task->thread.regs)[regno]; | ||
| 36 | } | ||
| 37 | |||
| 38 | return tmp; | ||
| 39 | } | ||
| 40 | |||
| 41 | /* | ||
| 42 | * Write contents of register REGNO in task TASK. | ||
| 43 | */ | ||
| 44 | static inline int put_reg(struct task_struct *task, int regno, | ||
| 45 | unsigned long data) | ||
| 46 | { | ||
| 47 | if (regno < PT_SOFTE) { | ||
| 48 | if (regno == PT_MSR) | ||
| 49 | data = (data & MSR_DEBUGCHANGE) | ||
| 50 | | (task->thread.regs->msr & ~MSR_DEBUGCHANGE); | ||
| 51 | ((unsigned long *)task->thread.regs)[regno] = data; | ||
| 52 | return 0; | ||
| 53 | } | ||
| 54 | return -EIO; | ||
| 55 | } | ||
| 56 | |||
| 57 | static inline void set_single_step(struct task_struct *task) | ||
| 58 | { | ||
| 59 | struct pt_regs *regs = task->thread.regs; | ||
| 60 | if (regs != NULL) | ||
| 61 | regs->msr |= MSR_SE; | ||
| 62 | set_tsk_thread_flag(task, TIF_SINGLESTEP); | ||
| 63 | } | ||
| 64 | |||
| 65 | static inline void clear_single_step(struct task_struct *task) | ||
| 66 | { | ||
| 67 | struct pt_regs *regs = task->thread.regs; | ||
| 68 | if (regs != NULL) | ||
| 69 | regs->msr &= ~MSR_SE; | ||
| 70 | clear_tsk_thread_flag(task, TIF_SINGLESTEP); | ||
| 71 | } | ||
| 72 | |||
| 73 | #ifdef CONFIG_ALTIVEC | ||
| 74 | /* | ||
| 75 | * Get/set all the altivec registers vr0..vr31, vscr, vrsave, in one go. | ||
| 76 | * The transfer totals 34 quadword. Quadwords 0-31 contain the | ||
| 77 | * corresponding vector registers. Quadword 32 contains the vscr as the | ||
| 78 | * last word (offset 12) within that quadword. Quadword 33 contains the | ||
| 79 | * vrsave as the first word (offset 0) within the quadword. | ||
| 80 | * | ||
| 81 | * This definition of the VMX state is compatible with the current PPC32 | ||
| 82 | * ptrace interface. This allows signal handling and ptrace to use the | ||
| 83 | * same structures. This also simplifies the implementation of a bi-arch | ||
| 84 | * (combined (32- and 64-bit) gdb. | ||
| 85 | */ | ||
| 86 | |||
| 87 | /* | ||
| 88 | * Get contents of AltiVec register state in task TASK | ||
| 89 | */ | ||
| 90 | static inline int get_vrregs(unsigned long __user *data, | ||
| 91 | struct task_struct *task) | ||
| 92 | { | ||
| 93 | unsigned long regsize; | ||
| 94 | |||
| 95 | /* copy AltiVec registers VR[0] .. VR[31] */ | ||
| 96 | regsize = 32 * sizeof(vector128); | ||
| 97 | if (copy_to_user(data, task->thread.vr, regsize)) | ||
| 98 | return -EFAULT; | ||
| 99 | data += (regsize / sizeof(unsigned long)); | ||
| 100 | |||
| 101 | /* copy VSCR */ | ||
| 102 | regsize = 1 * sizeof(vector128); | ||
| 103 | if (copy_to_user(data, &task->thread.vscr, regsize)) | ||
| 104 | return -EFAULT; | ||
| 105 | data += (regsize / sizeof(unsigned long)); | ||
| 106 | |||
| 107 | /* copy VRSAVE */ | ||
| 108 | if (put_user(task->thread.vrsave, (u32 __user *)data)) | ||
| 109 | return -EFAULT; | ||
| 110 | |||
| 111 | return 0; | ||
| 112 | } | ||
| 113 | |||
| 114 | /* | ||
| 115 | * Write contents of AltiVec register state into task TASK. | ||
| 116 | */ | ||
| 117 | static inline int set_vrregs(struct task_struct *task, | ||
| 118 | unsigned long __user *data) | ||
| 119 | { | ||
| 120 | unsigned long regsize; | ||
| 121 | |||
| 122 | /* copy AltiVec registers VR[0] .. VR[31] */ | ||
| 123 | regsize = 32 * sizeof(vector128); | ||
| 124 | if (copy_from_user(task->thread.vr, data, regsize)) | ||
| 125 | return -EFAULT; | ||
| 126 | data += (regsize / sizeof(unsigned long)); | ||
| 127 | |||
| 128 | /* copy VSCR */ | ||
| 129 | regsize = 1 * sizeof(vector128); | ||
| 130 | if (copy_from_user(&task->thread.vscr, data, regsize)) | ||
| 131 | return -EFAULT; | ||
| 132 | data += (regsize / sizeof(unsigned long)); | ||
| 133 | |||
| 134 | /* copy VRSAVE */ | ||
| 135 | if (get_user(task->thread.vrsave, (u32 __user *)data)) | ||
| 136 | return -EFAULT; | ||
| 137 | |||
| 138 | return 0; | ||
| 139 | } | ||
| 140 | #endif | ||
| 141 | |||
| 142 | static inline int ptrace_set_debugreg(struct task_struct *task, | ||
| 143 | unsigned long addr, unsigned long data) | ||
| 144 | { | ||
| 145 | /* We only support one DABR and no IABRS at the moment */ | ||
| 146 | if (addr > 0) | ||
| 147 | return -EINVAL; | ||
| 148 | |||
| 149 | /* The bottom 3 bits are flags */ | ||
| 150 | if ((data & ~0x7UL) >= TASK_SIZE) | ||
| 151 | return -EIO; | ||
| 152 | |||
| 153 | /* Ensure translation is on */ | ||
| 154 | if (data && !(data & DABR_TRANSLATION)) | ||
| 155 | return -EIO; | ||
| 156 | |||
| 157 | task->thread.dabr = data; | ||
| 158 | return 0; | ||
| 159 | } | ||
| 160 | |||
| 161 | #endif /* _PPC64_PTRACE_COMMON_H */ | ||
diff --git a/arch/powerpc/kernel/ptrace.c b/arch/powerpc/kernel/ptrace.c index bf76562167c3..0fb53950da43 100644 --- a/arch/powerpc/kernel/ptrace.c +++ b/arch/powerpc/kernel/ptrace.c | |||
| @@ -35,11 +35,11 @@ | |||
| 35 | #include <asm/pgtable.h> | 35 | #include <asm/pgtable.h> |
| 36 | #include <asm/system.h> | 36 | #include <asm/system.h> |
| 37 | 37 | ||
| 38 | #ifdef CONFIG_PPC64 | 38 | /* |
| 39 | #include "ptrace-common.h" | 39 | * does not yet catch signals sent when the child dies. |
| 40 | #endif | 40 | * in exit.c or in signal.c. |
| 41 | */ | ||
| 41 | 42 | ||
| 42 | #ifdef CONFIG_PPC32 | ||
| 43 | /* | 43 | /* |
| 44 | * Set of msr bits that gdb can change on behalf of a process. | 44 | * Set of msr bits that gdb can change on behalf of a process. |
| 45 | */ | 45 | */ |
| @@ -48,65 +48,117 @@ | |||
| 48 | #else | 48 | #else |
| 49 | #define MSR_DEBUGCHANGE (MSR_SE | MSR_BE) | 49 | #define MSR_DEBUGCHANGE (MSR_SE | MSR_BE) |
| 50 | #endif | 50 | #endif |
| 51 | #endif /* CONFIG_PPC32 */ | ||
| 52 | 51 | ||
| 53 | /* | 52 | /* |
| 54 | * does not yet catch signals sent when the child dies. | 53 | * Max register writeable via put_reg |
| 55 | * in exit.c or in signal.c. | ||
| 56 | */ | 54 | */ |
| 57 | |||
| 58 | #ifdef CONFIG_PPC32 | 55 | #ifdef CONFIG_PPC32 |
| 56 | #define PT_MAX_PUT_REG PT_MQ | ||
| 57 | #else | ||
| 58 | #define PT_MAX_PUT_REG PT_CCR | ||
| 59 | #endif | ||
| 60 | |||
| 59 | /* | 61 | /* |
| 60 | * Get contents of register REGNO in task TASK. | 62 | * Get contents of register REGNO in task TASK. |
| 61 | */ | 63 | */ |
| 62 | static inline unsigned long get_reg(struct task_struct *task, int regno) | 64 | unsigned long ptrace_get_reg(struct task_struct *task, int regno) |
| 63 | { | 65 | { |
| 64 | if (regno < sizeof(struct pt_regs) / sizeof(unsigned long) | 66 | unsigned long tmp = 0; |
| 65 | && task->thread.regs != NULL) | 67 | |
| 68 | if (task->thread.regs == NULL) | ||
| 69 | return -EIO; | ||
| 70 | |||
| 71 | if (regno == PT_MSR) { | ||
| 72 | tmp = ((unsigned long *)task->thread.regs)[PT_MSR]; | ||
| 73 | return tmp | task->thread.fpexc_mode; | ||
| 74 | } | ||
| 75 | |||
| 76 | if (regno < (sizeof(struct pt_regs) / sizeof(unsigned long))) | ||
| 66 | return ((unsigned long *)task->thread.regs)[regno]; | 77 | return ((unsigned long *)task->thread.regs)[regno]; |
| 67 | return (0); | 78 | |
| 79 | return -EIO; | ||
| 68 | } | 80 | } |
| 69 | 81 | ||
| 70 | /* | 82 | /* |
| 71 | * Write contents of register REGNO in task TASK. | 83 | * Write contents of register REGNO in task TASK. |
| 72 | */ | 84 | */ |
| 73 | static inline int put_reg(struct task_struct *task, int regno, | 85 | int ptrace_put_reg(struct task_struct *task, int regno, unsigned long data) |
| 74 | unsigned long data) | ||
| 75 | { | 86 | { |
| 76 | if (regno <= PT_MQ && task->thread.regs != NULL) { | 87 | if (task->thread.regs == NULL) |
| 88 | return -EIO; | ||
| 89 | |||
| 90 | if (regno <= PT_MAX_PUT_REG || regno == PT_TRAP) { | ||
| 77 | if (regno == PT_MSR) | 91 | if (regno == PT_MSR) |
| 78 | data = (data & MSR_DEBUGCHANGE) | 92 | data = (data & MSR_DEBUGCHANGE) |
| 79 | | (task->thread.regs->msr & ~MSR_DEBUGCHANGE); | 93 | | (task->thread.regs->msr & ~MSR_DEBUGCHANGE); |
| 94 | /* We prevent mucking around with the reserved area of trap | ||
| 95 | * which are used internally by the kernel | ||
| 96 | */ | ||
| 97 | if (regno == PT_TRAP) | ||
| 98 | data &= 0xfff0; | ||
| 80 | ((unsigned long *)task->thread.regs)[regno] = data; | 99 | ((unsigned long *)task->thread.regs)[regno] = data; |
| 81 | return 0; | 100 | return 0; |
| 82 | } | 101 | } |
| 83 | return -EIO; | 102 | return -EIO; |
| 84 | } | 103 | } |
| 85 | 104 | ||
| 105 | |||
| 106 | static int get_fpregs(void __user *data, struct task_struct *task, | ||
| 107 | int has_fpscr) | ||
| 108 | { | ||
| 109 | unsigned int count = has_fpscr ? 33 : 32; | ||
| 110 | |||
| 111 | if (copy_to_user(data, task->thread.fpr, count * sizeof(double))) | ||
| 112 | return -EFAULT; | ||
| 113 | return 0; | ||
| 114 | } | ||
| 115 | |||
| 116 | static int set_fpregs(void __user *data, struct task_struct *task, | ||
| 117 | int has_fpscr) | ||
| 118 | { | ||
| 119 | unsigned int count = has_fpscr ? 33 : 32; | ||
| 120 | |||
| 121 | if (copy_from_user(task->thread.fpr, data, count * sizeof(double))) | ||
| 122 | return -EFAULT; | ||
| 123 | return 0; | ||
| 124 | } | ||
| 125 | |||
| 126 | |||
| 86 | #ifdef CONFIG_ALTIVEC | 127 | #ifdef CONFIG_ALTIVEC |
| 87 | /* | 128 | /* |
| 129 | * Get/set all the altivec registers vr0..vr31, vscr, vrsave, in one go. | ||
| 130 | * The transfer totals 34 quadword. Quadwords 0-31 contain the | ||
| 131 | * corresponding vector registers. Quadword 32 contains the vscr as the | ||
| 132 | * last word (offset 12) within that quadword. Quadword 33 contains the | ||
| 133 | * vrsave as the first word (offset 0) within the quadword. | ||
| 134 | * | ||
| 135 | * This definition of the VMX state is compatible with the current PPC32 | ||
| 136 | * ptrace interface. This allows signal handling and ptrace to use the | ||
| 137 | * same structures. This also simplifies the implementation of a bi-arch | ||
| 138 | * (combined (32- and 64-bit) gdb. | ||
| 139 | */ | ||
| 140 | |||
| 141 | /* | ||
| 88 | * Get contents of AltiVec register state in task TASK | 142 | * Get contents of AltiVec register state in task TASK |
| 89 | */ | 143 | */ |
| 90 | static inline int get_vrregs(unsigned long __user *data, struct task_struct *task) | 144 | static int get_vrregs(unsigned long __user *data, struct task_struct *task) |
| 91 | { | 145 | { |
| 92 | int i, j; | 146 | unsigned long regsize; |
| 93 | |||
| 94 | if (!access_ok(VERIFY_WRITE, data, 133 * sizeof(unsigned long))) | ||
| 95 | return -EFAULT; | ||
| 96 | 147 | ||
| 97 | /* copy AltiVec registers VR[0] .. VR[31] */ | 148 | /* copy AltiVec registers VR[0] .. VR[31] */ |
| 98 | for (i = 0; i < 32; i++) | 149 | regsize = 32 * sizeof(vector128); |
| 99 | for (j = 0; j < 4; j++, data++) | 150 | if (copy_to_user(data, task->thread.vr, regsize)) |
| 100 | if (__put_user(task->thread.vr[i].u[j], data)) | 151 | return -EFAULT; |
| 101 | return -EFAULT; | 152 | data += (regsize / sizeof(unsigned long)); |
| 102 | 153 | ||
| 103 | /* copy VSCR */ | 154 | /* copy VSCR */ |
| 104 | for (i = 0; i < 4; i++, data++) | 155 | regsize = 1 * sizeof(vector128); |
| 105 | if (__put_user(task->thread.vscr.u[i], data)) | 156 | if (copy_to_user(data, &task->thread.vscr, regsize)) |
| 106 | return -EFAULT; | 157 | return -EFAULT; |
| 158 | data += (regsize / sizeof(unsigned long)); | ||
| 107 | 159 | ||
| 108 | /* copy VRSAVE */ | 160 | /* copy VRSAVE */ |
| 109 | if (__put_user(task->thread.vrsave, data)) | 161 | if (put_user(task->thread.vrsave, (u32 __user *)data)) |
| 110 | return -EFAULT; | 162 | return -EFAULT; |
| 111 | 163 | ||
| 112 | return 0; | 164 | return 0; |
| @@ -115,31 +167,29 @@ static inline int get_vrregs(unsigned long __user *data, struct task_struct *tas | |||
| 115 | /* | 167 | /* |
| 116 | * Write contents of AltiVec register state into task TASK. | 168 | * Write contents of AltiVec register state into task TASK. |
| 117 | */ | 169 | */ |
| 118 | static inline int set_vrregs(struct task_struct *task, unsigned long __user *data) | 170 | static int set_vrregs(struct task_struct *task, unsigned long __user *data) |
| 119 | { | 171 | { |
| 120 | int i, j; | 172 | unsigned long regsize; |
| 121 | |||
| 122 | if (!access_ok(VERIFY_READ, data, 133 * sizeof(unsigned long))) | ||
| 123 | return -EFAULT; | ||
| 124 | 173 | ||
| 125 | /* copy AltiVec registers VR[0] .. VR[31] */ | 174 | /* copy AltiVec registers VR[0] .. VR[31] */ |
| 126 | for (i = 0; i < 32; i++) | 175 | regsize = 32 * sizeof(vector128); |
| 127 | for (j = 0; j < 4; j++, data++) | 176 | if (copy_from_user(task->thread.vr, data, regsize)) |
| 128 | if (__get_user(task->thread.vr[i].u[j], data)) | 177 | return -EFAULT; |
| 129 | return -EFAULT; | 178 | data += (regsize / sizeof(unsigned long)); |
| 130 | 179 | ||
| 131 | /* copy VSCR */ | 180 | /* copy VSCR */ |
| 132 | for (i = 0; i < 4; i++, data++) | 181 | regsize = 1 * sizeof(vector128); |
| 133 | if (__get_user(task->thread.vscr.u[i], data)) | 182 | if (copy_from_user(&task->thread.vscr, data, regsize)) |
| 134 | return -EFAULT; | 183 | return -EFAULT; |
| 184 | data += (regsize / sizeof(unsigned long)); | ||
| 135 | 185 | ||
| 136 | /* copy VRSAVE */ | 186 | /* copy VRSAVE */ |
| 137 | if (__get_user(task->thread.vrsave, data)) | 187 | if (get_user(task->thread.vrsave, (u32 __user *)data)) |
| 138 | return -EFAULT; | 188 | return -EFAULT; |
| 139 | 189 | ||
| 140 | return 0; | 190 | return 0; |
| 141 | } | 191 | } |
| 142 | #endif | 192 | #endif /* CONFIG_ALTIVEC */ |
| 143 | 193 | ||
| 144 | #ifdef CONFIG_SPE | 194 | #ifdef CONFIG_SPE |
| 145 | 195 | ||
| @@ -156,7 +206,7 @@ static inline int set_vrregs(struct task_struct *task, unsigned long __user *dat | |||
| 156 | /* | 206 | /* |
| 157 | * Get contents of SPE register state in task TASK. | 207 | * Get contents of SPE register state in task TASK. |
| 158 | */ | 208 | */ |
| 159 | static inline int get_evrregs(unsigned long *data, struct task_struct *task) | 209 | static int get_evrregs(unsigned long *data, struct task_struct *task) |
| 160 | { | 210 | { |
| 161 | int i; | 211 | int i; |
| 162 | 212 | ||
| @@ -182,7 +232,7 @@ static inline int get_evrregs(unsigned long *data, struct task_struct *task) | |||
| 182 | /* | 232 | /* |
| 183 | * Write contents of SPE register state into task TASK. | 233 | * Write contents of SPE register state into task TASK. |
| 184 | */ | 234 | */ |
| 185 | static inline int set_evrregs(struct task_struct *task, unsigned long *data) | 235 | static int set_evrregs(struct task_struct *task, unsigned long *data) |
| 186 | { | 236 | { |
| 187 | int i; | 237 | int i; |
| 188 | 238 | ||
| @@ -205,8 +255,8 @@ static inline int set_evrregs(struct task_struct *task, unsigned long *data) | |||
| 205 | } | 255 | } |
| 206 | #endif /* CONFIG_SPE */ | 256 | #endif /* CONFIG_SPE */ |
| 207 | 257 | ||
| 208 | static inline void | 258 | |
| 209 | set_single_step(struct task_struct *task) | 259 | static void set_single_step(struct task_struct *task) |
| 210 | { | 260 | { |
| 211 | struct pt_regs *regs = task->thread.regs; | 261 | struct pt_regs *regs = task->thread.regs; |
| 212 | 262 | ||
| @@ -221,8 +271,7 @@ set_single_step(struct task_struct *task) | |||
| 221 | set_tsk_thread_flag(task, TIF_SINGLESTEP); | 271 | set_tsk_thread_flag(task, TIF_SINGLESTEP); |
| 222 | } | 272 | } |
| 223 | 273 | ||
| 224 | static inline void | 274 | static void clear_single_step(struct task_struct *task) |
| 225 | clear_single_step(struct task_struct *task) | ||
| 226 | { | 275 | { |
| 227 | struct pt_regs *regs = task->thread.regs; | 276 | struct pt_regs *regs = task->thread.regs; |
| 228 | 277 | ||
| @@ -236,7 +285,25 @@ clear_single_step(struct task_struct *task) | |||
| 236 | } | 285 | } |
| 237 | clear_tsk_thread_flag(task, TIF_SINGLESTEP); | 286 | clear_tsk_thread_flag(task, TIF_SINGLESTEP); |
| 238 | } | 287 | } |
| 239 | #endif /* CONFIG_PPC32 */ | 288 | |
| 289 | static int ptrace_set_debugreg(struct task_struct *task, unsigned long addr, | ||
| 290 | unsigned long data) | ||
| 291 | { | ||
| 292 | /* We only support one DABR and no IABRS at the moment */ | ||
| 293 | if (addr > 0) | ||
| 294 | return -EINVAL; | ||
| 295 | |||
| 296 | /* The bottom 3 bits are flags */ | ||
| 297 | if ((data & ~0x7UL) >= TASK_SIZE) | ||
| 298 | return -EIO; | ||
| 299 | |||
| 300 | /* Ensure translation is on */ | ||
| 301 | if (data && !(data & DABR_TRANSLATION)) | ||
| 302 | return -EIO; | ||
| 303 | |||
| 304 | task->thread.dabr = data; | ||
| 305 | return 0; | ||
| 306 | } | ||
| 240 | 307 | ||
| 241 | /* | 308 | /* |
| 242 | * Called by kernel/ptrace.c when detaching.. | 309 | * Called by kernel/ptrace.c when detaching.. |
| @@ -249,6 +316,62 @@ void ptrace_disable(struct task_struct *child) | |||
| 249 | clear_single_step(child); | 316 | clear_single_step(child); |
| 250 | } | 317 | } |
| 251 | 318 | ||
| 319 | /* | ||
| 320 | * Here are the old "legacy" powerpc specific getregs/setregs ptrace calls, | ||
| 321 | * we mark them as obsolete now, they will be removed in a future version | ||
| 322 | */ | ||
| 323 | static long arch_ptrace_old(struct task_struct *child, long request, long addr, | ||
| 324 | long data) | ||
| 325 | { | ||
| 326 | int ret = -EPERM; | ||
| 327 | |||
| 328 | switch(request) { | ||
| 329 | case PPC_PTRACE_GETREGS: { /* Get GPRs 0 - 31. */ | ||
| 330 | int i; | ||
| 331 | unsigned long *reg = &((unsigned long *)child->thread.regs)[0]; | ||
| 332 | unsigned long __user *tmp = (unsigned long __user *)addr; | ||
| 333 | |||
| 334 | for (i = 0; i < 32; i++) { | ||
| 335 | ret = put_user(*reg, tmp); | ||
| 336 | if (ret) | ||
| 337 | break; | ||
| 338 | reg++; | ||
| 339 | tmp++; | ||
| 340 | } | ||
| 341 | break; | ||
| 342 | } | ||
| 343 | |||
| 344 | case PPC_PTRACE_SETREGS: { /* Set GPRs 0 - 31. */ | ||
| 345 | int i; | ||
| 346 | unsigned long *reg = &((unsigned long *)child->thread.regs)[0]; | ||
| 347 | unsigned long __user *tmp = (unsigned long __user *)addr; | ||
| 348 | |||
| 349 | for (i = 0; i < 32; i++) { | ||
| 350 | ret = get_user(*reg, tmp); | ||
| 351 | if (ret) | ||
| 352 | break; | ||
| 353 | reg++; | ||
| 354 | tmp++; | ||
| 355 | } | ||
| 356 | break; | ||
| 357 | } | ||
| 358 | |||
| 359 | case PPC_PTRACE_GETFPREGS: { /* Get FPRs 0 - 31. */ | ||
| 360 | flush_fp_to_thread(child); | ||
| 361 | ret = get_fpregs((void __user *)addr, child, 0); | ||
| 362 | break; | ||
| 363 | } | ||
| 364 | |||
| 365 | case PPC_PTRACE_SETFPREGS: { /* Get FPRs 0 - 31. */ | ||
| 366 | flush_fp_to_thread(child); | ||
| 367 | ret = set_fpregs((void __user *)addr, child, 0); | ||
| 368 | break; | ||
| 369 | } | ||
| 370 | |||
| 371 | } | ||
| 372 | return ret; | ||
| 373 | } | ||
| 374 | |||
| 252 | long arch_ptrace(struct task_struct *child, long request, long addr, long data) | 375 | long arch_ptrace(struct task_struct *child, long request, long addr, long data) |
| 253 | { | 376 | { |
| 254 | int ret = -EPERM; | 377 | int ret = -EPERM; |
| @@ -284,11 +407,9 @@ long arch_ptrace(struct task_struct *child, long request, long addr, long data) | |||
| 284 | #endif | 407 | #endif |
| 285 | break; | 408 | break; |
| 286 | 409 | ||
| 287 | #ifdef CONFIG_PPC32 | ||
| 288 | CHECK_FULL_REGS(child->thread.regs); | 410 | CHECK_FULL_REGS(child->thread.regs); |
| 289 | #endif | ||
| 290 | if (index < PT_FPR0) { | 411 | if (index < PT_FPR0) { |
| 291 | tmp = get_reg(child, (int) index); | 412 | tmp = ptrace_get_reg(child, (int) index); |
| 292 | } else { | 413 | } else { |
| 293 | flush_fp_to_thread(child); | 414 | flush_fp_to_thread(child); |
| 294 | tmp = ((unsigned long *)child->thread.fpr)[index - PT_FPR0]; | 415 | tmp = ((unsigned long *)child->thread.fpr)[index - PT_FPR0]; |
| @@ -323,13 +444,9 @@ long arch_ptrace(struct task_struct *child, long request, long addr, long data) | |||
| 323 | #endif | 444 | #endif |
| 324 | break; | 445 | break; |
| 325 | 446 | ||
| 326 | #ifdef CONFIG_PPC32 | ||
| 327 | CHECK_FULL_REGS(child->thread.regs); | 447 | CHECK_FULL_REGS(child->thread.regs); |
| 328 | #endif | ||
| 329 | if (index == PT_ORIG_R3) | ||
| 330 | break; | ||
| 331 | if (index < PT_FPR0) { | 448 | if (index < PT_FPR0) { |
| 332 | ret = put_reg(child, index, data); | 449 | ret = ptrace_put_reg(child, index, data); |
| 333 | } else { | 450 | } else { |
| 334 | flush_fp_to_thread(child); | 451 | flush_fp_to_thread(child); |
| 335 | ((unsigned long *)child->thread.fpr)[index - PT_FPR0] = data; | 452 | ((unsigned long *)child->thread.fpr)[index - PT_FPR0] = data; |
| @@ -384,7 +501,6 @@ long arch_ptrace(struct task_struct *child, long request, long addr, long data) | |||
| 384 | break; | 501 | break; |
| 385 | } | 502 | } |
| 386 | 503 | ||
| 387 | #ifdef CONFIG_PPC64 | ||
| 388 | case PTRACE_GET_DEBUGREG: { | 504 | case PTRACE_GET_DEBUGREG: { |
| 389 | ret = -EINVAL; | 505 | ret = -EINVAL; |
| 390 | /* We only support one DABR and no IABRS at the moment */ | 506 | /* We only support one DABR and no IABRS at the moment */ |
| @@ -398,73 +514,61 @@ long arch_ptrace(struct task_struct *child, long request, long addr, long data) | |||
| 398 | case PTRACE_SET_DEBUGREG: | 514 | case PTRACE_SET_DEBUGREG: |
| 399 | ret = ptrace_set_debugreg(child, addr, data); | 515 | ret = ptrace_set_debugreg(child, addr, data); |
| 400 | break; | 516 | break; |
| 401 | #endif | ||
| 402 | 517 | ||
| 403 | case PTRACE_DETACH: | 518 | case PTRACE_DETACH: |
| 404 | ret = ptrace_detach(child, data); | 519 | ret = ptrace_detach(child, data); |
| 405 | break; | 520 | break; |
| 406 | 521 | ||
| 407 | case PPC_PTRACE_GETREGS: { /* Get GPRs 0 - 31. */ | 522 | #ifdef CONFIG_PPC64 |
| 408 | int i; | 523 | case PTRACE_GETREGS64: |
| 409 | unsigned long *reg = &((unsigned long *)child->thread.regs)[0]; | 524 | #endif |
| 410 | unsigned long __user *tmp = (unsigned long __user *)addr; | 525 | case PTRACE_GETREGS: { /* Get all pt_regs from the child. */ |
| 411 | 526 | int ui; | |
| 412 | for (i = 0; i < 32; i++) { | 527 | if (!access_ok(VERIFY_WRITE, (void __user *)data, |
| 413 | ret = put_user(*reg, tmp); | 528 | sizeof(struct pt_regs))) { |
| 414 | if (ret) | 529 | ret = -EIO; |
| 415 | break; | 530 | break; |
| 416 | reg++; | 531 | } |
| 417 | tmp++; | 532 | ret = 0; |
| 533 | for (ui = 0; ui < PT_REGS_COUNT; ui ++) { | ||
| 534 | ret |= __put_user(ptrace_get_reg(child, ui), | ||
| 535 | (unsigned long __user *) data); | ||
| 536 | data += sizeof(long); | ||
| 418 | } | 537 | } |
| 419 | break; | 538 | break; |
| 420 | } | 539 | } |
| 421 | 540 | ||
| 422 | case PPC_PTRACE_SETREGS: { /* Set GPRs 0 - 31. */ | 541 | #ifdef CONFIG_PPC64 |
| 423 | int i; | 542 | case PTRACE_SETREGS64: |
| 424 | unsigned long *reg = &((unsigned long *)child->thread.regs)[0]; | 543 | #endif |
| 425 | unsigned long __user *tmp = (unsigned long __user *)addr; | 544 | case PTRACE_SETREGS: { /* Set all gp regs in the child. */ |
| 426 | 545 | unsigned long tmp; | |
| 427 | for (i = 0; i < 32; i++) { | 546 | int ui; |
| 428 | ret = get_user(*reg, tmp); | 547 | if (!access_ok(VERIFY_READ, (void __user *)data, |
| 548 | sizeof(struct pt_regs))) { | ||
| 549 | ret = -EIO; | ||
| 550 | break; | ||
| 551 | } | ||
| 552 | ret = 0; | ||
| 553 | for (ui = 0; ui < PT_REGS_COUNT; ui ++) { | ||
| 554 | ret = __get_user(tmp, (unsigned long __user *) data); | ||
| 429 | if (ret) | 555 | if (ret) |
| 430 | break; | 556 | break; |
| 431 | reg++; | 557 | ptrace_put_reg(child, ui, tmp); |
| 432 | tmp++; | 558 | data += sizeof(long); |
| 433 | } | 559 | } |
| 434 | break; | 560 | break; |
| 435 | } | 561 | } |
| 436 | 562 | ||
| 437 | case PPC_PTRACE_GETFPREGS: { /* Get FPRs 0 - 31. */ | 563 | case PTRACE_GETFPREGS: { /* Get the child FPU state (FPR0...31 + FPSCR) */ |
| 438 | int i; | ||
| 439 | unsigned long *reg = &((unsigned long *)child->thread.fpr)[0]; | ||
| 440 | unsigned long __user *tmp = (unsigned long __user *)addr; | ||
| 441 | |||
| 442 | flush_fp_to_thread(child); | 564 | flush_fp_to_thread(child); |
| 443 | 565 | ret = get_fpregs((void __user *)data, child, 1); | |
| 444 | for (i = 0; i < 32; i++) { | ||
| 445 | ret = put_user(*reg, tmp); | ||
| 446 | if (ret) | ||
| 447 | break; | ||
| 448 | reg++; | ||
| 449 | tmp++; | ||
| 450 | } | ||
| 451 | break; | 566 | break; |
| 452 | } | 567 | } |
| 453 | 568 | ||
| 454 | case PPC_PTRACE_SETFPREGS: { /* Get FPRs 0 - 31. */ | 569 | case PTRACE_SETFPREGS: { /* Set the child FPU state (FPR0...31 + FPSCR) */ |
| 455 | int i; | ||
| 456 | unsigned long *reg = &((unsigned long *)child->thread.fpr)[0]; | ||
| 457 | unsigned long __user *tmp = (unsigned long __user *)addr; | ||
| 458 | |||
| 459 | flush_fp_to_thread(child); | 570 | flush_fp_to_thread(child); |
| 460 | 571 | ret = set_fpregs((void __user *)data, child, 1); | |
| 461 | for (i = 0; i < 32; i++) { | ||
| 462 | ret = get_user(*reg, tmp); | ||
| 463 | if (ret) | ||
| 464 | break; | ||
| 465 | reg++; | ||
| 466 | tmp++; | ||
| 467 | } | ||
| 468 | break; | 572 | break; |
| 469 | } | 573 | } |
| 470 | 574 | ||
| @@ -499,11 +603,18 @@ long arch_ptrace(struct task_struct *child, long request, long addr, long data) | |||
| 499 | break; | 603 | break; |
| 500 | #endif | 604 | #endif |
| 501 | 605 | ||
| 606 | /* Old reverse args ptrace callss */ | ||
| 607 | case PPC_PTRACE_GETREGS: /* Get GPRs 0 - 31. */ | ||
| 608 | case PPC_PTRACE_SETREGS: /* Set GPRs 0 - 31. */ | ||
| 609 | case PPC_PTRACE_GETFPREGS: /* Get FPRs 0 - 31. */ | ||
| 610 | case PPC_PTRACE_SETFPREGS: /* Get FPRs 0 - 31. */ | ||
| 611 | ret = arch_ptrace_old(child, request, addr, data); | ||
| 612 | break; | ||
| 613 | |||
| 502 | default: | 614 | default: |
| 503 | ret = ptrace_request(child, request, addr, data); | 615 | ret = ptrace_request(child, request, addr, data); |
| 504 | break; | 616 | break; |
| 505 | } | 617 | } |
| 506 | |||
| 507 | return ret; | 618 | return ret; |
| 508 | } | 619 | } |
| 509 | 620 | ||
diff --git a/arch/powerpc/kernel/ptrace32.c b/arch/powerpc/kernel/ptrace32.c index 9b9a230349bc..9e6baeac0fb1 100644 --- a/arch/powerpc/kernel/ptrace32.c +++ b/arch/powerpc/kernel/ptrace32.c | |||
| @@ -33,13 +33,55 @@ | |||
| 33 | #include <asm/pgtable.h> | 33 | #include <asm/pgtable.h> |
| 34 | #include <asm/system.h> | 34 | #include <asm/system.h> |
| 35 | 35 | ||
| 36 | #include "ptrace-common.h" | ||
| 37 | |||
| 38 | /* | 36 | /* |
| 39 | * does not yet catch signals sent when the child dies. | 37 | * does not yet catch signals sent when the child dies. |
| 40 | * in exit.c or in signal.c. | 38 | * in exit.c or in signal.c. |
| 41 | */ | 39 | */ |
| 42 | 40 | ||
| 41 | /* | ||
| 42 | * Here are the old "legacy" powerpc specific getregs/setregs ptrace calls, | ||
| 43 | * we mark them as obsolete now, they will be removed in a future version | ||
| 44 | */ | ||
| 45 | static long compat_ptrace_old(struct task_struct *child, long request, | ||
| 46 | long addr, long data) | ||
| 47 | { | ||
| 48 | int ret = -EPERM; | ||
| 49 | |||
| 50 | switch(request) { | ||
| 51 | case PPC_PTRACE_GETREGS: { /* Get GPRs 0 - 31. */ | ||
| 52 | int i; | ||
| 53 | unsigned long *reg = &((unsigned long *)child->thread.regs)[0]; | ||
| 54 | unsigned int __user *tmp = (unsigned int __user *)addr; | ||
| 55 | |||
| 56 | for (i = 0; i < 32; i++) { | ||
| 57 | ret = put_user(*reg, tmp); | ||
| 58 | if (ret) | ||
| 59 | break; | ||
| 60 | reg++; | ||
| 61 | tmp++; | ||
| 62 | } | ||
| 63 | break; | ||
| 64 | } | ||
| 65 | |||
| 66 | case PPC_PTRACE_SETREGS: { /* Set GPRs 0 - 31. */ | ||
| 67 | int i; | ||
| 68 | unsigned long *reg = &((unsigned long *)child->thread.regs)[0]; | ||
| 69 | unsigned int __user *tmp = (unsigned int __user *)addr; | ||
| 70 | |||
| 71 | for (i = 0; i < 32; i++) { | ||
| 72 | ret = get_user(*reg, tmp); | ||
| 73 | if (ret) | ||
| 74 | break; | ||
| 75 | reg++; | ||
| 76 | tmp++; | ||
| 77 | } | ||
| 78 | break; | ||
| 79 | } | ||
| 80 | |||
| 81 | } | ||
| 82 | return ret; | ||
| 83 | } | ||
| 84 | |||
| 43 | long compat_sys_ptrace(int request, int pid, unsigned long addr, | 85 | long compat_sys_ptrace(int request, int pid, unsigned long addr, |
| 44 | unsigned long data) | 86 | unsigned long data) |
| 45 | { | 87 | { |
| @@ -123,7 +165,7 @@ long compat_sys_ptrace(int request, int pid, unsigned long addr, | |||
| 123 | break; | 165 | break; |
| 124 | 166 | ||
| 125 | if (index < PT_FPR0) { | 167 | if (index < PT_FPR0) { |
| 126 | tmp = get_reg(child, index); | 168 | tmp = ptrace_get_reg(child, index); |
| 127 | } else { | 169 | } else { |
| 128 | flush_fp_to_thread(child); | 170 | flush_fp_to_thread(child); |
| 129 | /* | 171 | /* |
| @@ -162,7 +204,9 @@ long compat_sys_ptrace(int request, int pid, unsigned long addr, | |||
| 162 | else | 204 | else |
| 163 | part = 0; /* want the 1st half of the register (left-most). */ | 205 | part = 0; /* want the 1st half of the register (left-most). */ |
| 164 | 206 | ||
| 165 | /* Validate the input - check to see if address is on the wrong boundary or beyond the end of the user area */ | 207 | /* Validate the input - check to see if address is on the wrong boundary |
| 208 | * or beyond the end of the user area | ||
| 209 | */ | ||
| 166 | if ((addr & 3) || numReg > PT_FPSCR) | 210 | if ((addr & 3) || numReg > PT_FPSCR) |
| 167 | break; | 211 | break; |
| 168 | 212 | ||
| @@ -170,7 +214,7 @@ long compat_sys_ptrace(int request, int pid, unsigned long addr, | |||
| 170 | flush_fp_to_thread(child); | 214 | flush_fp_to_thread(child); |
| 171 | tmp = ((unsigned long int *)child->thread.fpr)[numReg - PT_FPR0]; | 215 | tmp = ((unsigned long int *)child->thread.fpr)[numReg - PT_FPR0]; |
| 172 | } else { /* register within PT_REGS struct */ | 216 | } else { /* register within PT_REGS struct */ |
| 173 | tmp = get_reg(child, numReg); | 217 | tmp = ptrace_get_reg(child, numReg); |
| 174 | } | 218 | } |
| 175 | reg32bits = ((u32*)&tmp)[part]; | 219 | reg32bits = ((u32*)&tmp)[part]; |
| 176 | ret = put_user(reg32bits, (u32 __user *)data); | 220 | ret = put_user(reg32bits, (u32 __user *)data); |
| @@ -226,10 +270,8 @@ long compat_sys_ptrace(int request, int pid, unsigned long addr, | |||
| 226 | if ((addr & 3) || (index > PT_FPSCR32)) | 270 | if ((addr & 3) || (index > PT_FPSCR32)) |
| 227 | break; | 271 | break; |
| 228 | 272 | ||
| 229 | if (index == PT_ORIG_R3) | ||
| 230 | break; | ||
| 231 | if (index < PT_FPR0) { | 273 | if (index < PT_FPR0) { |
| 232 | ret = put_reg(child, index, data); | 274 | ret = ptrace_put_reg(child, index, data); |
| 233 | } else { | 275 | } else { |
| 234 | flush_fp_to_thread(child); | 276 | flush_fp_to_thread(child); |
| 235 | /* | 277 | /* |
| @@ -258,70 +300,25 @@ long compat_sys_ptrace(int request, int pid, unsigned long addr, | |||
| 258 | /* Determine which register the user wants */ | 300 | /* Determine which register the user wants */ |
| 259 | index = (u64)addr >> 2; | 301 | index = (u64)addr >> 2; |
| 260 | numReg = index / 2; | 302 | numReg = index / 2; |
| 303 | |||
| 261 | /* | 304 | /* |
| 262 | * Validate the input - check to see if address is on the | 305 | * Validate the input - check to see if address is on the |
| 263 | * wrong boundary or beyond the end of the user area | 306 | * wrong boundary or beyond the end of the user area |
| 264 | */ | 307 | */ |
| 265 | if ((addr & 3) || (numReg > PT_FPSCR)) | 308 | if ((addr & 3) || (numReg > PT_FPSCR)) |
| 266 | break; | 309 | break; |
| 267 | /* Insure it is a register we let them change */ | 310 | if (numReg < PT_FPR0) { |
| 268 | if ((numReg == PT_ORIG_R3) | 311 | unsigned long freg = ptrace_get_reg(child, numReg); |
| 269 | || ((numReg > PT_CCR) && (numReg < PT_FPR0))) | 312 | if (index % 2) |
| 270 | break; | 313 | freg = (freg & ~0xfffffffful) | (data & 0xfffffffful); |
| 271 | if (numReg >= PT_FPR0) { | 314 | else |
| 315 | freg = (freg & 0xfffffffful) | (data << 32); | ||
| 316 | ret = ptrace_put_reg(child, numReg, freg); | ||
| 317 | } else { | ||
| 272 | flush_fp_to_thread(child); | 318 | flush_fp_to_thread(child); |
| 319 | ((unsigned int *)child->thread.regs)[index] = data; | ||
| 320 | ret = 0; | ||
| 273 | } | 321 | } |
| 274 | if (numReg == PT_MSR) | ||
| 275 | data = (data & MSR_DEBUGCHANGE) | ||
| 276 | | (child->thread.regs->msr & ~MSR_DEBUGCHANGE); | ||
| 277 | ((u32*)child->thread.regs)[index] = data; | ||
| 278 | ret = 0; | ||
| 279 | break; | ||
| 280 | } | ||
| 281 | |||
| 282 | case PTRACE_SYSCALL: /* continue and stop at next (return from) syscall */ | ||
| 283 | case PTRACE_CONT: { /* restart after signal. */ | ||
| 284 | ret = -EIO; | ||
| 285 | if (!valid_signal(data)) | ||
| 286 | break; | ||
| 287 | if (request == PTRACE_SYSCALL) | ||
| 288 | set_tsk_thread_flag(child, TIF_SYSCALL_TRACE); | ||
| 289 | else | ||
| 290 | clear_tsk_thread_flag(child, TIF_SYSCALL_TRACE); | ||
| 291 | child->exit_code = data; | ||
| 292 | /* make sure the single step bit is not set. */ | ||
| 293 | clear_single_step(child); | ||
| 294 | wake_up_process(child); | ||
| 295 | ret = 0; | ||
| 296 | break; | ||
| 297 | } | ||
| 298 | |||
| 299 | /* | ||
| 300 | * make the child exit. Best I can do is send it a sigkill. | ||
| 301 | * perhaps it should be put in the status that it wants to | ||
| 302 | * exit. | ||
| 303 | */ | ||
| 304 | case PTRACE_KILL: { | ||
| 305 | ret = 0; | ||
| 306 | if (child->exit_state == EXIT_ZOMBIE) /* already dead */ | ||
| 307 | break; | ||
| 308 | child->exit_code = SIGKILL; | ||
| 309 | /* make sure the single step bit is not set. */ | ||
| 310 | clear_single_step(child); | ||
| 311 | wake_up_process(child); | ||
| 312 | break; | ||
| 313 | } | ||
| 314 | |||
| 315 | case PTRACE_SINGLESTEP: { /* set the trap flag. */ | ||
| 316 | ret = -EIO; | ||
| 317 | if (!valid_signal(data)) | ||
| 318 | break; | ||
| 319 | clear_tsk_thread_flag(child, TIF_SYSCALL_TRACE); | ||
| 320 | set_single_step(child); | ||
| 321 | child->exit_code = data; | ||
| 322 | /* give it a chance to run. */ | ||
| 323 | wake_up_process(child); | ||
| 324 | ret = 0; | ||
| 325 | break; | 322 | break; |
| 326 | } | 323 | } |
| 327 | 324 | ||
| @@ -334,95 +331,67 @@ long compat_sys_ptrace(int request, int pid, unsigned long addr, | |||
| 334 | break; | 331 | break; |
| 335 | } | 332 | } |
| 336 | 333 | ||
| 337 | case PTRACE_SET_DEBUGREG: | 334 | case PTRACE_GETEVENTMSG: |
| 338 | ret = ptrace_set_debugreg(child, addr, data); | 335 | ret = put_user(child->ptrace_message, (unsigned int __user *) data); |
| 339 | break; | ||
| 340 | |||
| 341 | case PTRACE_DETACH: | ||
| 342 | ret = ptrace_detach(child, data); | ||
| 343 | break; | 336 | break; |
| 344 | 337 | ||
| 345 | case PPC_PTRACE_GETREGS: { /* Get GPRs 0 - 31. */ | 338 | case PTRACE_GETREGS: { /* Get all pt_regs from the child. */ |
| 346 | int i; | 339 | int ui; |
| 347 | unsigned long *reg = &((unsigned long *)child->thread.regs)[0]; | 340 | if (!access_ok(VERIFY_WRITE, (void __user *)data, |
| 348 | unsigned int __user *tmp = (unsigned int __user *)addr; | 341 | PT_REGS_COUNT * sizeof(int))) { |
| 349 | 342 | ret = -EIO; | |
| 350 | for (i = 0; i < 32; i++) { | 343 | break; |
| 351 | ret = put_user(*reg, tmp); | ||
| 352 | if (ret) | ||
| 353 | break; | ||
| 354 | reg++; | ||
| 355 | tmp++; | ||
| 356 | } | 344 | } |
| 357 | break; | 345 | ret = 0; |
| 358 | } | 346 | for (ui = 0; ui < PT_REGS_COUNT; ui ++) { |
| 359 | 347 | ret |= __put_user(ptrace_get_reg(child, ui), | |
| 360 | case PPC_PTRACE_SETREGS: { /* Set GPRs 0 - 31. */ | 348 | (unsigned int __user *) data); |
| 361 | int i; | 349 | data += sizeof(int); |
| 362 | unsigned long *reg = &((unsigned long *)child->thread.regs)[0]; | ||
| 363 | unsigned int __user *tmp = (unsigned int __user *)addr; | ||
| 364 | |||
| 365 | for (i = 0; i < 32; i++) { | ||
| 366 | ret = get_user(*reg, tmp); | ||
| 367 | if (ret) | ||
| 368 | break; | ||
| 369 | reg++; | ||
| 370 | tmp++; | ||
| 371 | } | 350 | } |
| 372 | break; | 351 | break; |
| 373 | } | 352 | } |
| 374 | 353 | ||
| 375 | case PPC_PTRACE_GETFPREGS: { /* Get FPRs 0 - 31. */ | 354 | case PTRACE_SETREGS: { /* Set all gp regs in the child. */ |
| 376 | int i; | 355 | unsigned long tmp; |
| 377 | unsigned long *reg = &((unsigned long *)child->thread.fpr)[0]; | 356 | int ui; |
| 378 | unsigned int __user *tmp = (unsigned int __user *)addr; | 357 | if (!access_ok(VERIFY_READ, (void __user *)data, |
| 379 | 358 | PT_REGS_COUNT * sizeof(int))) { | |
| 380 | flush_fp_to_thread(child); | 359 | ret = -EIO; |
| 381 | 360 | break; | |
| 382 | for (i = 0; i < 32; i++) { | ||
| 383 | ret = put_user(*reg, tmp); | ||
| 384 | if (ret) | ||
| 385 | break; | ||
| 386 | reg++; | ||
| 387 | tmp++; | ||
| 388 | } | 361 | } |
| 389 | break; | 362 | ret = 0; |
| 390 | } | 363 | for (ui = 0; ui < PT_REGS_COUNT; ui ++) { |
| 391 | 364 | ret = __get_user(tmp, (unsigned int __user *) data); | |
| 392 | case PPC_PTRACE_SETFPREGS: { /* Get FPRs 0 - 31. */ | ||
| 393 | int i; | ||
| 394 | unsigned long *reg = &((unsigned long *)child->thread.fpr)[0]; | ||
| 395 | unsigned int __user *tmp = (unsigned int __user *)addr; | ||
| 396 | |||
| 397 | flush_fp_to_thread(child); | ||
| 398 | |||
| 399 | for (i = 0; i < 32; i++) { | ||
| 400 | ret = get_user(*reg, tmp); | ||
| 401 | if (ret) | 365 | if (ret) |
| 402 | break; | 366 | break; |
| 403 | reg++; | 367 | ptrace_put_reg(child, ui, tmp); |
| 404 | tmp++; | 368 | data += sizeof(int); |
| 405 | } | 369 | } |
| 406 | break; | 370 | break; |
| 407 | } | 371 | } |
| 408 | 372 | ||
| 409 | case PTRACE_GETEVENTMSG: | 373 | case PTRACE_GETFPREGS: |
| 410 | ret = put_user(child->ptrace_message, (unsigned int __user *) data); | 374 | case PTRACE_SETFPREGS: |
| 411 | break; | ||
| 412 | |||
| 413 | #ifdef CONFIG_ALTIVEC | ||
| 414 | case PTRACE_GETVRREGS: | 375 | case PTRACE_GETVRREGS: |
| 415 | /* Get the child altivec register state. */ | 376 | case PTRACE_SETVRREGS: |
| 416 | flush_altivec_to_thread(child); | 377 | case PTRACE_GETREGS64: |
| 417 | ret = get_vrregs((unsigned long __user *)data, child); | 378 | case PTRACE_SETREGS64: |
| 379 | case PPC_PTRACE_GETFPREGS: | ||
| 380 | case PPC_PTRACE_SETFPREGS: | ||
| 381 | case PTRACE_KILL: | ||
| 382 | case PTRACE_SINGLESTEP: | ||
| 383 | case PTRACE_DETACH: | ||
| 384 | case PTRACE_SET_DEBUGREG: | ||
| 385 | case PTRACE_SYSCALL: | ||
| 386 | case PTRACE_CONT: | ||
| 387 | ret = arch_ptrace(child, request, addr, data); | ||
| 418 | break; | 388 | break; |
| 419 | 389 | ||
| 420 | case PTRACE_SETVRREGS: | 390 | /* Old reverse args ptrace callss */ |
| 421 | /* Set the child altivec register state. */ | 391 | case PPC_PTRACE_GETREGS: /* Get GPRs 0 - 31. */ |
| 422 | flush_altivec_to_thread(child); | 392 | case PPC_PTRACE_SETREGS: /* Set GPRs 0 - 31. */ |
| 423 | ret = set_vrregs(child, (unsigned long __user *)data); | 393 | ret = compat_ptrace_old(child, request, addr, data); |
| 424 | break; | 394 | break; |
| 425 | #endif | ||
| 426 | 395 | ||
| 427 | default: | 396 | default: |
| 428 | ret = ptrace_request(child, request, addr, data); | 397 | ret = ptrace_request(child, request, addr, data); |
diff --git a/arch/powerpc/kernel/rtas_pci.c b/arch/powerpc/kernel/rtas_pci.c index f2286822be09..a5de6211b97a 100644 --- a/arch/powerpc/kernel/rtas_pci.c +++ b/arch/powerpc/kernel/rtas_pci.c | |||
| @@ -278,10 +278,8 @@ void __init find_and_init_phbs(void) | |||
| 278 | { | 278 | { |
| 279 | struct device_node *node; | 279 | struct device_node *node; |
| 280 | struct pci_controller *phb; | 280 | struct pci_controller *phb; |
| 281 | unsigned int index; | ||
| 282 | struct device_node *root = of_find_node_by_path("/"); | 281 | struct device_node *root = of_find_node_by_path("/"); |
| 283 | 282 | ||
| 284 | index = 0; | ||
| 285 | for (node = of_get_next_child(root, NULL); | 283 | for (node = of_get_next_child(root, NULL); |
| 286 | node != NULL; | 284 | node != NULL; |
| 287 | node = of_get_next_child(root, node)) { | 285 | node = of_get_next_child(root, node)) { |
| @@ -295,8 +293,7 @@ void __init find_and_init_phbs(void) | |||
| 295 | continue; | 293 | continue; |
| 296 | rtas_setup_phb(phb); | 294 | rtas_setup_phb(phb); |
| 297 | pci_process_bridge_OF_ranges(phb, node, 0); | 295 | pci_process_bridge_OF_ranges(phb, node, 0); |
| 298 | pci_setup_phb_io(phb, index == 0); | 296 | isa_bridge_find_early(phb); |
| 299 | index++; | ||
| 300 | } | 297 | } |
| 301 | 298 | ||
| 302 | of_node_put(root); | 299 | of_node_put(root); |
| @@ -335,7 +332,7 @@ int pcibios_remove_root_bus(struct pci_controller *phb) | |||
| 335 | return 1; | 332 | return 1; |
| 336 | } | 333 | } |
| 337 | 334 | ||
| 338 | rc = unmap_bus_range(b); | 335 | rc = pcibios_unmap_io_space(b); |
| 339 | if (rc) { | 336 | if (rc) { |
| 340 | printk(KERN_ERR "%s: failed to unmap IO on bus %s\n", | 337 | printk(KERN_ERR "%s: failed to unmap IO on bus %s\n", |
| 341 | __FUNCTION__, b->name); | 338 | __FUNCTION__, b->name); |
diff --git a/arch/powerpc/kernel/setup-common.c b/arch/powerpc/kernel/setup-common.c index ed07a198f8d6..4924c48cb1ff 100644 --- a/arch/powerpc/kernel/setup-common.c +++ b/arch/powerpc/kernel/setup-common.c | |||
| @@ -32,6 +32,7 @@ | |||
| 32 | #include <linux/unistd.h> | 32 | #include <linux/unistd.h> |
| 33 | #include <linux/serial.h> | 33 | #include <linux/serial.h> |
| 34 | #include <linux/serial_8250.h> | 34 | #include <linux/serial_8250.h> |
| 35 | #include <linux/debugfs.h> | ||
| 35 | #include <asm/io.h> | 36 | #include <asm/io.h> |
| 36 | #include <asm/prom.h> | 37 | #include <asm/prom.h> |
| 37 | #include <asm/processor.h> | 38 | #include <asm/processor.h> |
| @@ -486,6 +487,14 @@ int check_legacy_ioport(unsigned long base_port) | |||
| 486 | 487 | ||
| 487 | switch(base_port) { | 488 | switch(base_port) { |
| 488 | case I8042_DATA_REG: | 489 | case I8042_DATA_REG: |
| 490 | if (!(np = of_find_compatible_node(NULL, NULL, "pnpPNP,303"))) | ||
| 491 | np = of_find_compatible_node(NULL, NULL, "pnpPNP,f03"); | ||
| 492 | if (np) { | ||
| 493 | parent = of_get_parent(np); | ||
| 494 | of_node_put(np); | ||
| 495 | np = parent; | ||
| 496 | break; | ||
| 497 | } | ||
| 489 | np = of_find_node_by_type(NULL, "8042"); | 498 | np = of_find_node_by_type(NULL, "8042"); |
| 490 | break; | 499 | break; |
| 491 | case FDC_BASE: /* FDC1 */ | 500 | case FDC_BASE: /* FDC1 */ |
| @@ -571,3 +580,15 @@ static int __init check_cache_coherency(void) | |||
| 571 | 580 | ||
| 572 | late_initcall(check_cache_coherency); | 581 | late_initcall(check_cache_coherency); |
| 573 | #endif /* CONFIG_CHECK_CACHE_COHERENCY */ | 582 | #endif /* CONFIG_CHECK_CACHE_COHERENCY */ |
| 583 | |||
| 584 | #ifdef CONFIG_DEBUG_FS | ||
| 585 | struct dentry *powerpc_debugfs_root; | ||
| 586 | |||
| 587 | static int powerpc_debugfs_init(void) | ||
| 588 | { | ||
| 589 | powerpc_debugfs_root = debugfs_create_dir("powerpc", NULL); | ||
| 590 | |||
| 591 | return powerpc_debugfs_root == NULL; | ||
| 592 | } | ||
| 593 | arch_initcall(powerpc_debugfs_init); | ||
| 594 | #endif | ||
diff --git a/arch/powerpc/kernel/setup_32.c b/arch/powerpc/kernel/setup_32.c index 35f8f443c14f..7ec6ba56d83d 100644 --- a/arch/powerpc/kernel/setup_32.c +++ b/arch/powerpc/kernel/setup_32.c | |||
| @@ -262,13 +262,11 @@ void __init setup_arch(char **cmdline_p) | |||
| 262 | * Systems with OF can look in the properties on the cpu node(s) | 262 | * Systems with OF can look in the properties on the cpu node(s) |
| 263 | * for a possibly more accurate value. | 263 | * for a possibly more accurate value. |
| 264 | */ | 264 | */ |
| 265 | if (cpu_has_feature(CPU_FTR_SPLIT_ID_CACHE)) { | 265 | dcache_bsize = cur_cpu_spec->dcache_bsize; |
| 266 | dcache_bsize = cur_cpu_spec->dcache_bsize; | 266 | icache_bsize = cur_cpu_spec->icache_bsize; |
| 267 | icache_bsize = cur_cpu_spec->icache_bsize; | 267 | ucache_bsize = 0; |
| 268 | ucache_bsize = 0; | 268 | if (cpu_has_feature(CPU_FTR_UNIFIED_ID_CACHE)) |
| 269 | } else | 269 | ucache_bsize = icache_bsize = dcache_bsize; |
| 270 | ucache_bsize = dcache_bsize = icache_bsize | ||
| 271 | = cur_cpu_spec->dcache_bsize; | ||
| 272 | 270 | ||
| 273 | /* reboot on panic */ | 271 | /* reboot on panic */ |
| 274 | panic_timeout = 180; | 272 | panic_timeout = 180; |
diff --git a/arch/powerpc/kernel/setup_64.c b/arch/powerpc/kernel/setup_64.c index 6018178708a5..bc43bba05cf8 100644 --- a/arch/powerpc/kernel/setup_64.c +++ b/arch/powerpc/kernel/setup_64.c | |||
| @@ -350,13 +350,11 @@ void __init setup_system(void) | |||
| 350 | { | 350 | { |
| 351 | DBG(" -> setup_system()\n"); | 351 | DBG(" -> setup_system()\n"); |
| 352 | 352 | ||
| 353 | /* Apply the CPUs-specific and firmware specific fixups to kernel | 353 | /* Apply CPUs-specific fixups to kernel text (nop out sections |
| 354 | * text (nop out sections not relevant to this CPU or this firmware) | 354 | * not relevant to this CPU) |
| 355 | */ | 355 | */ |
| 356 | do_feature_fixups(cur_cpu_spec->cpu_features, | 356 | do_feature_fixups(cur_cpu_spec->cpu_features, |
| 357 | &__start___ftr_fixup, &__stop___ftr_fixup); | 357 | &__start___ftr_fixup, &__stop___ftr_fixup); |
| 358 | do_feature_fixups(powerpc_firmware_features, | ||
| 359 | &__start___fw_ftr_fixup, &__stop___fw_ftr_fixup); | ||
| 360 | 358 | ||
| 361 | /* | 359 | /* |
| 362 | * Unflatten the device-tree passed by prom_init or kexec | 360 | * Unflatten the device-tree passed by prom_init or kexec |
| @@ -394,6 +392,12 @@ void __init setup_system(void) | |||
| 394 | if (ppc_md.init_early) | 392 | if (ppc_md.init_early) |
| 395 | ppc_md.init_early(); | 393 | ppc_md.init_early(); |
| 396 | 394 | ||
| 395 | /* Apply firmware specific fixups to kernel text (nop out | ||
| 396 | * sections not relevant to this firmware) | ||
| 397 | */ | ||
| 398 | do_feature_fixups(powerpc_firmware_features, | ||
| 399 | &__start___fw_ftr_fixup, &__stop___fw_ftr_fixup); | ||
| 400 | |||
| 397 | /* | 401 | /* |
| 398 | * We can discover serial ports now since the above did setup the | 402 | * We can discover serial ports now since the above did setup the |
| 399 | * hash table management for us, thus ioremap works. We do that early | 403 | * hash table management for us, thus ioremap works. We do that early |
diff --git a/arch/powerpc/kernel/signal.c b/arch/powerpc/kernel/signal.c new file mode 100644 index 000000000000..c434d6c4e4e6 --- /dev/null +++ b/arch/powerpc/kernel/signal.c | |||
| @@ -0,0 +1,180 @@ | |||
| 1 | /* | ||
| 2 | * Common signal handling code for both 32 and 64 bits | ||
| 3 | * | ||
| 4 | * Copyright (c) 2007 Benjamin Herrenschmidt, IBM Coproration | ||
| 5 | * Extracted from signal_32.c and signal_64.c | ||
| 6 | * | ||
| 7 | * This file is subject to the terms and conditions of the GNU General | ||
| 8 | * Public License. See the file README.legal in the main directory of | ||
| 9 | * this archive for more details. | ||
| 10 | */ | ||
| 11 | |||
| 12 | #include <linux/ptrace.h> | ||
| 13 | #include <linux/signal.h> | ||
| 14 | #include <asm/uaccess.h> | ||
| 15 | #include <asm/unistd.h> | ||
| 16 | |||
| 17 | #include "signal.h" | ||
| 18 | |||
| 19 | /* | ||
| 20 | * Allocate space for the signal frame | ||
| 21 | */ | ||
| 22 | void __user * get_sigframe(struct k_sigaction *ka, struct pt_regs *regs, | ||
| 23 | size_t frame_size) | ||
| 24 | { | ||
| 25 | unsigned long oldsp, newsp; | ||
| 26 | |||
| 27 | /* Default to using normal stack */ | ||
| 28 | oldsp = regs->gpr[1]; | ||
| 29 | |||
| 30 | /* Check for alt stack */ | ||
| 31 | if ((ka->sa.sa_flags & SA_ONSTACK) && | ||
| 32 | current->sas_ss_size && !on_sig_stack(oldsp)) | ||
| 33 | oldsp = (current->sas_ss_sp + current->sas_ss_size); | ||
| 34 | |||
| 35 | /* Get aligned frame */ | ||
| 36 | newsp = (oldsp - frame_size) & ~0xFUL; | ||
| 37 | |||
| 38 | /* Check access */ | ||
| 39 | if (!access_ok(VERIFY_WRITE, (void __user *)newsp, oldsp - newsp)) | ||
| 40 | return NULL; | ||
| 41 | |||
| 42 | return (void __user *)newsp; | ||
| 43 | } | ||
| 44 | |||
| 45 | |||
| 46 | /* | ||
| 47 | * Restore the user process's signal mask | ||
| 48 | */ | ||
| 49 | void restore_sigmask(sigset_t *set) | ||
| 50 | { | ||
| 51 | sigdelsetmask(set, ~_BLOCKABLE); | ||
| 52 | spin_lock_irq(¤t->sighand->siglock); | ||
| 53 | current->blocked = *set; | ||
| 54 | recalc_sigpending(); | ||
| 55 | spin_unlock_irq(¤t->sighand->siglock); | ||
| 56 | } | ||
| 57 | |||
| 58 | static void check_syscall_restart(struct pt_regs *regs, struct k_sigaction *ka, | ||
| 59 | int has_handler) | ||
| 60 | { | ||
| 61 | unsigned long ret = regs->gpr[3]; | ||
| 62 | int restart = 1; | ||
| 63 | |||
| 64 | /* syscall ? */ | ||
| 65 | if (TRAP(regs) != 0x0C00) | ||
| 66 | return; | ||
| 67 | |||
| 68 | /* error signalled ? */ | ||
| 69 | if (!(regs->ccr & 0x10000000)) | ||
| 70 | return; | ||
| 71 | |||
| 72 | switch (ret) { | ||
| 73 | case ERESTART_RESTARTBLOCK: | ||
| 74 | case ERESTARTNOHAND: | ||
| 75 | /* ERESTARTNOHAND means that the syscall should only be | ||
| 76 | * restarted if there was no handler for the signal, and since | ||
| 77 | * we only get here if there is a handler, we dont restart. | ||
| 78 | */ | ||
| 79 | restart = !has_handler; | ||
| 80 | break; | ||
| 81 | case ERESTARTSYS: | ||
| 82 | /* ERESTARTSYS means to restart the syscall if there is no | ||
| 83 | * handler or the handler was registered with SA_RESTART | ||
| 84 | */ | ||
| 85 | restart = !has_handler || (ka->sa.sa_flags & SA_RESTART) != 0; | ||
| 86 | break; | ||
| 87 | case ERESTARTNOINTR: | ||
| 88 | /* ERESTARTNOINTR means that the syscall should be | ||
| 89 | * called again after the signal handler returns. | ||
| 90 | */ | ||
| 91 | break; | ||
| 92 | default: | ||
| 93 | return; | ||
| 94 | } | ||
| 95 | if (restart) { | ||
| 96 | if (ret == ERESTART_RESTARTBLOCK) | ||
| 97 | regs->gpr[0] = __NR_restart_syscall; | ||
| 98 | else | ||
| 99 | regs->gpr[3] = regs->orig_gpr3; | ||
| 100 | regs->nip -= 4; | ||
| 101 | regs->result = 0; | ||
| 102 | } else { | ||
| 103 | regs->result = -EINTR; | ||
| 104 | regs->gpr[3] = EINTR; | ||
| 105 | regs->ccr |= 0x10000000; | ||
| 106 | } | ||
| 107 | } | ||
| 108 | |||
| 109 | int do_signal(sigset_t *oldset, struct pt_regs *regs) | ||
| 110 | { | ||
| 111 | siginfo_t info; | ||
| 112 | int signr; | ||
| 113 | struct k_sigaction ka; | ||
| 114 | int ret; | ||
| 115 | int is32 = is_32bit_task(); | ||
| 116 | |||
| 117 | if (test_thread_flag(TIF_RESTORE_SIGMASK)) | ||
| 118 | oldset = ¤t->saved_sigmask; | ||
| 119 | else if (!oldset) | ||
| 120 | oldset = ¤t->blocked; | ||
| 121 | |||
| 122 | signr = get_signal_to_deliver(&info, &ka, regs, NULL); | ||
| 123 | |||
| 124 | /* Is there any syscall restart business here ? */ | ||
| 125 | check_syscall_restart(regs, &ka, signr > 0); | ||
| 126 | |||
| 127 | if (signr <= 0) { | ||
| 128 | /* No signal to deliver -- put the saved sigmask back */ | ||
| 129 | if (test_thread_flag(TIF_RESTORE_SIGMASK)) { | ||
| 130 | clear_thread_flag(TIF_RESTORE_SIGMASK); | ||
| 131 | sigprocmask(SIG_SETMASK, ¤t->saved_sigmask, NULL); | ||
| 132 | } | ||
| 133 | return 0; /* no signals delivered */ | ||
| 134 | } | ||
| 135 | |||
| 136 | /* | ||
| 137 | * Reenable the DABR before delivering the signal to | ||
| 138 | * user space. The DABR will have been cleared if it | ||
| 139 | * triggered inside the kernel. | ||
| 140 | */ | ||
| 141 | if (current->thread.dabr) | ||
| 142 | set_dabr(current->thread.dabr); | ||
| 143 | |||
| 144 | if (is32) { | ||
| 145 | if (ka.sa.sa_flags & SA_SIGINFO) | ||
| 146 | ret = handle_rt_signal32(signr, &ka, &info, oldset, | ||
| 147 | regs); | ||
| 148 | else | ||
| 149 | ret = handle_signal32(signr, &ka, &info, oldset, | ||
| 150 | regs); | ||
| 151 | } else { | ||
| 152 | ret = handle_rt_signal64(signr, &ka, &info, oldset, regs); | ||
| 153 | } | ||
| 154 | |||
| 155 | if (ret) { | ||
| 156 | spin_lock_irq(¤t->sighand->siglock); | ||
| 157 | sigorsets(¤t->blocked, ¤t->blocked, | ||
| 158 | &ka.sa.sa_mask); | ||
| 159 | if (!(ka.sa.sa_flags & SA_NODEFER)) | ||
| 160 | sigaddset(¤t->blocked, signr); | ||
| 161 | recalc_sigpending(); | ||
| 162 | spin_unlock_irq(¤t->sighand->siglock); | ||
| 163 | |||
| 164 | /* | ||
| 165 | * A signal was successfully delivered; the saved sigmask is in | ||
| 166 | * its frame, and we can clear the TIF_RESTORE_SIGMASK flag. | ||
| 167 | */ | ||
| 168 | if (test_thread_flag(TIF_RESTORE_SIGMASK)) | ||
| 169 | clear_thread_flag(TIF_RESTORE_SIGMASK); | ||
| 170 | } | ||
| 171 | |||
| 172 | return ret; | ||
| 173 | } | ||
| 174 | |||
| 175 | long sys_sigaltstack(const stack_t __user *uss, stack_t __user *uoss, | ||
| 176 | unsigned long r5, unsigned long r6, unsigned long r7, | ||
| 177 | unsigned long r8, struct pt_regs *regs) | ||
| 178 | { | ||
| 179 | return do_sigaltstack(uss, uoss, regs->gpr[1]); | ||
| 180 | } | ||
diff --git a/arch/powerpc/kernel/signal.h b/arch/powerpc/kernel/signal.h new file mode 100644 index 000000000000..77efb3d5465a --- /dev/null +++ b/arch/powerpc/kernel/signal.h | |||
| @@ -0,0 +1,55 @@ | |||
| 1 | /* | ||
| 2 | * Copyright (c) 2007 Benjamin Herrenschmidt, IBM Coproration | ||
| 3 | * Extracted from signal_32.c and signal_64.c | ||
| 4 | * | ||
| 5 | * This file is subject to the terms and conditions of the GNU General | ||
| 6 | * Public License. See the file README.legal in the main directory of | ||
| 7 | * this archive for more details. | ||
| 8 | */ | ||
| 9 | |||
| 10 | #ifndef _POWERPC_ARCH_SIGNAL_H | ||
| 11 | #define _POWERPC_ARCH_SIGNAL_H | ||
| 12 | |||
| 13 | #define _BLOCKABLE (~(sigmask(SIGKILL) | sigmask(SIGSTOP))) | ||
| 14 | |||
| 15 | extern void __user * get_sigframe(struct k_sigaction *ka, struct pt_regs *regs, | ||
| 16 | size_t frame_size); | ||
| 17 | extern void restore_sigmask(sigset_t *set); | ||
| 18 | |||
| 19 | extern int handle_signal32(unsigned long sig, struct k_sigaction *ka, | ||
| 20 | siginfo_t *info, sigset_t *oldset, | ||
| 21 | struct pt_regs *regs); | ||
| 22 | |||
| 23 | extern int handle_rt_signal32(unsigned long sig, struct k_sigaction *ka, | ||
| 24 | siginfo_t *info, sigset_t *oldset, | ||
| 25 | struct pt_regs *regs); | ||
| 26 | |||
| 27 | |||
| 28 | #ifdef CONFIG_PPC64 | ||
| 29 | |||
| 30 | static inline int is_32bit_task(void) | ||
| 31 | { | ||
| 32 | return test_thread_flag(TIF_32BIT); | ||
| 33 | } | ||
| 34 | |||
| 35 | extern int handle_rt_signal64(int signr, struct k_sigaction *ka, | ||
| 36 | siginfo_t *info, sigset_t *set, | ||
| 37 | struct pt_regs *regs); | ||
| 38 | |||
| 39 | #else /* CONFIG_PPC64 */ | ||
| 40 | |||
| 41 | static inline int is_32bit_task(void) | ||
| 42 | { | ||
| 43 | return 1; | ||
| 44 | } | ||
| 45 | |||
| 46 | static inline int handle_rt_signal64(int signr, struct k_sigaction *ka, | ||
| 47 | siginfo_t *info, sigset_t *set, | ||
| 48 | struct pt_regs *regs) | ||
| 49 | { | ||
| 50 | return -EFAULT; | ||
| 51 | } | ||
| 52 | |||
| 53 | #endif /* !defined(CONFIG_PPC64) */ | ||
| 54 | |||
| 55 | #endif /* _POWERPC_ARCH_SIGNAL_H */ | ||
diff --git a/arch/powerpc/kernel/signal_32.c b/arch/powerpc/kernel/signal_32.c index dd1dca5bfa81..590057e9e987 100644 --- a/arch/powerpc/kernel/signal_32.c +++ b/arch/powerpc/kernel/signal_32.c | |||
| @@ -51,12 +51,11 @@ | |||
| 51 | #include <asm/pgtable.h> | 51 | #include <asm/pgtable.h> |
| 52 | #endif | 52 | #endif |
| 53 | 53 | ||
| 54 | #undef DEBUG_SIG | 54 | #include "signal.h" |
| 55 | 55 | ||
| 56 | #define _BLOCKABLE (~(sigmask(SIGKILL) | sigmask(SIGSTOP))) | 56 | #undef DEBUG_SIG |
| 57 | 57 | ||
| 58 | #ifdef CONFIG_PPC64 | 58 | #ifdef CONFIG_PPC64 |
| 59 | #define do_signal do_signal32 | ||
| 60 | #define sys_sigsuspend compat_sys_sigsuspend | 59 | #define sys_sigsuspend compat_sys_sigsuspend |
| 61 | #define sys_rt_sigsuspend compat_sys_rt_sigsuspend | 60 | #define sys_rt_sigsuspend compat_sys_rt_sigsuspend |
| 62 | #define sys_rt_sigreturn compat_sys_rt_sigreturn | 61 | #define sys_rt_sigreturn compat_sys_rt_sigreturn |
| @@ -231,8 +230,6 @@ static inline int restore_general_regs(struct pt_regs *regs, | |||
| 231 | 230 | ||
| 232 | #endif /* CONFIG_PPC64 */ | 231 | #endif /* CONFIG_PPC64 */ |
| 233 | 232 | ||
| 234 | int do_signal(sigset_t *oldset, struct pt_regs *regs); | ||
| 235 | |||
| 236 | /* | 233 | /* |
| 237 | * Atomically swap in the new signal mask, and wait for a signal. | 234 | * Atomically swap in the new signal mask, and wait for a signal. |
| 238 | */ | 235 | */ |
| @@ -251,14 +248,6 @@ long sys_sigsuspend(old_sigset_t mask) | |||
| 251 | return -ERESTARTNOHAND; | 248 | return -ERESTARTNOHAND; |
| 252 | } | 249 | } |
| 253 | 250 | ||
| 254 | #ifdef CONFIG_PPC32 | ||
| 255 | long sys_sigaltstack(const stack_t __user *uss, stack_t __user *uoss, int r5, | ||
| 256 | int r6, int r7, int r8, struct pt_regs *regs) | ||
| 257 | { | ||
| 258 | return do_sigaltstack(uss, uoss, regs->gpr[1]); | ||
| 259 | } | ||
| 260 | #endif | ||
| 261 | |||
| 262 | long sys_sigaction(int sig, struct old_sigaction __user *act, | 251 | long sys_sigaction(int sig, struct old_sigaction __user *act, |
| 263 | struct old_sigaction __user *oact) | 252 | struct old_sigaction __user *oact) |
| 264 | { | 253 | { |
| @@ -293,14 +282,17 @@ long sys_sigaction(int sig, struct old_sigaction __user *act, | |||
| 293 | /* | 282 | /* |
| 294 | * When we have signals to deliver, we set up on the | 283 | * When we have signals to deliver, we set up on the |
| 295 | * user stack, going down from the original stack pointer: | 284 | * user stack, going down from the original stack pointer: |
| 296 | * a sigregs struct | 285 | * an ABI gap of 56 words |
| 286 | * an mcontext struct | ||
| 297 | * a sigcontext struct | 287 | * a sigcontext struct |
| 298 | * a gap of __SIGNAL_FRAMESIZE bytes | 288 | * a gap of __SIGNAL_FRAMESIZE bytes |
| 299 | * | 289 | * |
| 300 | * Each of these things must be a multiple of 16 bytes in size. | 290 | * Each of these things must be a multiple of 16 bytes in size. The following |
| 291 | * structure represent all of this except the __SIGNAL_FRAMESIZE gap | ||
| 301 | * | 292 | * |
| 302 | */ | 293 | */ |
| 303 | struct sigregs { | 294 | struct sigframe { |
| 295 | struct sigcontext sctx; /* the sigcontext */ | ||
| 304 | struct mcontext mctx; /* all the register values */ | 296 | struct mcontext mctx; /* all the register values */ |
| 305 | /* | 297 | /* |
| 306 | * Programs using the rs6000/xcoff abi can save up to 19 gp | 298 | * Programs using the rs6000/xcoff abi can save up to 19 gp |
| @@ -703,44 +695,22 @@ int compat_sys_sigaltstack(u32 __new, u32 __old, int r5, | |||
| 703 | } | 695 | } |
| 704 | #endif /* CONFIG_PPC64 */ | 696 | #endif /* CONFIG_PPC64 */ |
| 705 | 697 | ||
| 706 | |||
| 707 | /* | ||
| 708 | * Restore the user process's signal mask | ||
| 709 | */ | ||
| 710 | #ifdef CONFIG_PPC64 | ||
| 711 | extern void restore_sigmask(sigset_t *set); | ||
| 712 | #else /* CONFIG_PPC64 */ | ||
| 713 | static void restore_sigmask(sigset_t *set) | ||
| 714 | { | ||
| 715 | sigdelsetmask(set, ~_BLOCKABLE); | ||
| 716 | spin_lock_irq(¤t->sighand->siglock); | ||
| 717 | current->blocked = *set; | ||
| 718 | recalc_sigpending(); | ||
| 719 | spin_unlock_irq(¤t->sighand->siglock); | ||
| 720 | } | ||
| 721 | #endif | ||
| 722 | |||
| 723 | /* | 698 | /* |
| 724 | * Set up a signal frame for a "real-time" signal handler | 699 | * Set up a signal frame for a "real-time" signal handler |
| 725 | * (one which gets siginfo). | 700 | * (one which gets siginfo). |
| 726 | */ | 701 | */ |
| 727 | static int handle_rt_signal(unsigned long sig, struct k_sigaction *ka, | 702 | int handle_rt_signal32(unsigned long sig, struct k_sigaction *ka, |
| 728 | siginfo_t *info, sigset_t *oldset, | 703 | siginfo_t *info, sigset_t *oldset, |
| 729 | struct pt_regs *regs, unsigned long newsp) | 704 | struct pt_regs *regs) |
| 730 | { | 705 | { |
| 731 | struct rt_sigframe __user *rt_sf; | 706 | struct rt_sigframe __user *rt_sf; |
| 732 | struct mcontext __user *frame; | 707 | struct mcontext __user *frame; |
| 733 | unsigned long origsp = newsp; | 708 | unsigned long newsp = 0; |
| 734 | 709 | ||
| 735 | /* Set up Signal Frame */ | 710 | /* Set up Signal Frame */ |
| 736 | /* Put a Real Time Context onto stack */ | 711 | /* Put a Real Time Context onto stack */ |
| 737 | newsp -= sizeof(*rt_sf); | 712 | rt_sf = get_sigframe(ka, regs, sizeof(*rt_sf)); |
| 738 | rt_sf = (struct rt_sigframe __user *)newsp; | 713 | if (unlikely(rt_sf == NULL)) |
| 739 | |||
| 740 | /* create a stack frame for the caller of the handler */ | ||
| 741 | newsp -= __SIGNAL_FRAMESIZE + 16; | ||
| 742 | |||
| 743 | if (!access_ok(VERIFY_WRITE, (void __user *)newsp, origsp - newsp)) | ||
| 744 | goto badframe; | 714 | goto badframe; |
| 745 | 715 | ||
| 746 | /* Put the siginfo & fill in most of the ucontext */ | 716 | /* Put the siginfo & fill in most of the ucontext */ |
| @@ -770,8 +740,12 @@ static int handle_rt_signal(unsigned long sig, struct k_sigaction *ka, | |||
| 770 | 740 | ||
| 771 | current->thread.fpscr.val = 0; /* turn off all fp exceptions */ | 741 | current->thread.fpscr.val = 0; /* turn off all fp exceptions */ |
| 772 | 742 | ||
| 743 | /* create a stack frame for the caller of the handler */ | ||
| 744 | newsp = ((unsigned long)rt_sf) - (__SIGNAL_FRAMESIZE + 16); | ||
| 773 | if (put_user(regs->gpr[1], (u32 __user *)newsp)) | 745 | if (put_user(regs->gpr[1], (u32 __user *)newsp)) |
| 774 | goto badframe; | 746 | goto badframe; |
| 747 | |||
| 748 | /* Fill registers for signal handler */ | ||
| 775 | regs->gpr[1] = newsp; | 749 | regs->gpr[1] = newsp; |
| 776 | regs->gpr[3] = sig; | 750 | regs->gpr[3] = sig; |
| 777 | regs->gpr[4] = (unsigned long) &rt_sf->info; | 751 | regs->gpr[4] = (unsigned long) &rt_sf->info; |
| @@ -1015,27 +989,18 @@ int sys_debug_setcontext(struct ucontext __user *ctx, | |||
| 1015 | /* | 989 | /* |
| 1016 | * OK, we're invoking a handler | 990 | * OK, we're invoking a handler |
| 1017 | */ | 991 | */ |
| 1018 | static int handle_signal(unsigned long sig, struct k_sigaction *ka, | 992 | int handle_signal32(unsigned long sig, struct k_sigaction *ka, |
| 1019 | siginfo_t *info, sigset_t *oldset, struct pt_regs *regs, | 993 | siginfo_t *info, sigset_t *oldset, struct pt_regs *regs) |
| 1020 | unsigned long newsp) | ||
| 1021 | { | 994 | { |
| 1022 | struct sigcontext __user *sc; | 995 | struct sigcontext __user *sc; |
| 1023 | struct sigregs __user *frame; | 996 | struct sigframe __user *frame; |
| 1024 | unsigned long origsp = newsp; | 997 | unsigned long newsp = 0; |
| 1025 | 998 | ||
| 1026 | /* Set up Signal Frame */ | 999 | /* Set up Signal Frame */ |
| 1027 | newsp -= sizeof(struct sigregs); | 1000 | frame = get_sigframe(ka, regs, sizeof(*frame)); |
| 1028 | frame = (struct sigregs __user *) newsp; | 1001 | if (unlikely(frame == NULL)) |
| 1029 | |||
| 1030 | /* Put a sigcontext on the stack */ | ||
| 1031 | newsp -= sizeof(*sc); | ||
| 1032 | sc = (struct sigcontext __user *) newsp; | ||
| 1033 | |||
| 1034 | /* create a stack frame for the caller of the handler */ | ||
| 1035 | newsp -= __SIGNAL_FRAMESIZE; | ||
| 1036 | |||
| 1037 | if (!access_ok(VERIFY_WRITE, (void __user *) newsp, origsp - newsp)) | ||
| 1038 | goto badframe; | 1002 | goto badframe; |
| 1003 | sc = (struct sigcontext __user *) &frame->sctx; | ||
| 1039 | 1004 | ||
| 1040 | #if _NSIG != 64 | 1005 | #if _NSIG != 64 |
| 1041 | #error "Please adjust handle_signal()" | 1006 | #error "Please adjust handle_signal()" |
| @@ -1047,7 +1012,7 @@ static int handle_signal(unsigned long sig, struct k_sigaction *ka, | |||
| 1047 | #else | 1012 | #else |
| 1048 | || __put_user(oldset->sig[1], &sc->_unused[3]) | 1013 | || __put_user(oldset->sig[1], &sc->_unused[3]) |
| 1049 | #endif | 1014 | #endif |
| 1050 | || __put_user(to_user_ptr(frame), &sc->regs) | 1015 | || __put_user(to_user_ptr(&frame->mctx), &sc->regs) |
| 1051 | || __put_user(sig, &sc->signal)) | 1016 | || __put_user(sig, &sc->signal)) |
| 1052 | goto badframe; | 1017 | goto badframe; |
| 1053 | 1018 | ||
| @@ -1063,8 +1028,11 @@ static int handle_signal(unsigned long sig, struct k_sigaction *ka, | |||
| 1063 | 1028 | ||
| 1064 | current->thread.fpscr.val = 0; /* turn off all fp exceptions */ | 1029 | current->thread.fpscr.val = 0; /* turn off all fp exceptions */ |
| 1065 | 1030 | ||
| 1031 | /* create a stack frame for the caller of the handler */ | ||
| 1032 | newsp = ((unsigned long)frame) - __SIGNAL_FRAMESIZE; | ||
| 1066 | if (put_user(regs->gpr[1], (u32 __user *)newsp)) | 1033 | if (put_user(regs->gpr[1], (u32 __user *)newsp)) |
| 1067 | goto badframe; | 1034 | goto badframe; |
| 1035 | |||
| 1068 | regs->gpr[1] = newsp; | 1036 | regs->gpr[1] = newsp; |
| 1069 | regs->gpr[3] = sig; | 1037 | regs->gpr[3] = sig; |
| 1070 | regs->gpr[4] = (unsigned long) sc; | 1038 | regs->gpr[4] = (unsigned long) sc; |
| @@ -1126,106 +1094,3 @@ badframe: | |||
| 1126 | force_sig(SIGSEGV, current); | 1094 | force_sig(SIGSEGV, current); |
| 1127 | return 0; | 1095 | return 0; |
| 1128 | } | 1096 | } |
| 1129 | |||
| 1130 | /* | ||
| 1131 | * Note that 'init' is a special process: it doesn't get signals it doesn't | ||
| 1132 | * want to handle. Thus you cannot kill init even with a SIGKILL even by | ||
| 1133 | * mistake. | ||
| 1134 | */ | ||
| 1135 | int do_signal(sigset_t *oldset, struct pt_regs *regs) | ||
| 1136 | { | ||
| 1137 | siginfo_t info; | ||
| 1138 | struct k_sigaction ka; | ||
| 1139 | unsigned int newsp; | ||
| 1140 | int signr, ret; | ||
| 1141 | |||
| 1142 | #ifdef CONFIG_PPC32 | ||
| 1143 | if (try_to_freeze()) { | ||
| 1144 | signr = 0; | ||
| 1145 | if (!signal_pending(current)) | ||
| 1146 | goto no_signal; | ||
| 1147 | } | ||
| 1148 | #endif | ||
| 1149 | |||
| 1150 | if (test_thread_flag(TIF_RESTORE_SIGMASK)) | ||
| 1151 | oldset = ¤t->saved_sigmask; | ||
| 1152 | else if (!oldset) | ||
| 1153 | oldset = ¤t->blocked; | ||
| 1154 | |||
| 1155 | signr = get_signal_to_deliver(&info, &ka, regs, NULL); | ||
| 1156 | #ifdef CONFIG_PPC32 | ||
| 1157 | no_signal: | ||
| 1158 | #endif | ||
| 1159 | if (TRAP(regs) == 0x0C00 /* System Call! */ | ||
| 1160 | && regs->ccr & 0x10000000 /* error signalled */ | ||
| 1161 | && ((ret = regs->gpr[3]) == ERESTARTSYS | ||
| 1162 | || ret == ERESTARTNOHAND || ret == ERESTARTNOINTR | ||
| 1163 | || ret == ERESTART_RESTARTBLOCK)) { | ||
| 1164 | |||
| 1165 | if (signr > 0 | ||
| 1166 | && (ret == ERESTARTNOHAND || ret == ERESTART_RESTARTBLOCK | ||
| 1167 | || (ret == ERESTARTSYS | ||
| 1168 | && !(ka.sa.sa_flags & SA_RESTART)))) { | ||
| 1169 | /* make the system call return an EINTR error */ | ||
| 1170 | regs->result = -EINTR; | ||
| 1171 | regs->gpr[3] = EINTR; | ||
| 1172 | /* note that the cr0.SO bit is already set */ | ||
| 1173 | } else { | ||
| 1174 | regs->nip -= 4; /* Back up & retry system call */ | ||
| 1175 | regs->result = 0; | ||
| 1176 | regs->trap = 0; | ||
| 1177 | if (ret == ERESTART_RESTARTBLOCK) | ||
| 1178 | regs->gpr[0] = __NR_restart_syscall; | ||
| 1179 | else | ||
| 1180 | regs->gpr[3] = regs->orig_gpr3; | ||
| 1181 | } | ||
| 1182 | } | ||
| 1183 | |||
| 1184 | if (signr == 0) { | ||
| 1185 | /* No signal to deliver -- put the saved sigmask back */ | ||
| 1186 | if (test_thread_flag(TIF_RESTORE_SIGMASK)) { | ||
| 1187 | clear_thread_flag(TIF_RESTORE_SIGMASK); | ||
| 1188 | sigprocmask(SIG_SETMASK, ¤t->saved_sigmask, NULL); | ||
| 1189 | } | ||
| 1190 | return 0; /* no signals delivered */ | ||
| 1191 | } | ||
| 1192 | |||
| 1193 | if ((ka.sa.sa_flags & SA_ONSTACK) && current->sas_ss_size | ||
| 1194 | && !on_sig_stack(regs->gpr[1])) | ||
| 1195 | newsp = current->sas_ss_sp + current->sas_ss_size; | ||
| 1196 | else | ||
| 1197 | newsp = regs->gpr[1]; | ||
| 1198 | newsp &= ~0xfUL; | ||
| 1199 | |||
| 1200 | #ifdef CONFIG_PPC64 | ||
| 1201 | /* | ||
| 1202 | * Reenable the DABR before delivering the signal to | ||
| 1203 | * user space. The DABR will have been cleared if it | ||
| 1204 | * triggered inside the kernel. | ||
| 1205 | */ | ||
| 1206 | if (current->thread.dabr) | ||
| 1207 | set_dabr(current->thread.dabr); | ||
| 1208 | #endif | ||
| 1209 | |||
| 1210 | /* Whee! Actually deliver the signal. */ | ||
| 1211 | if (ka.sa.sa_flags & SA_SIGINFO) | ||
| 1212 | ret = handle_rt_signal(signr, &ka, &info, oldset, regs, newsp); | ||
| 1213 | else | ||
| 1214 | ret = handle_signal(signr, &ka, &info, oldset, regs, newsp); | ||
| 1215 | |||
| 1216 | if (ret) { | ||
| 1217 | spin_lock_irq(¤t->sighand->siglock); | ||
| 1218 | sigorsets(¤t->blocked, ¤t->blocked, | ||
| 1219 | &ka.sa.sa_mask); | ||
| 1220 | if (!(ka.sa.sa_flags & SA_NODEFER)) | ||
| 1221 | sigaddset(¤t->blocked, signr); | ||
| 1222 | recalc_sigpending(); | ||
| 1223 | spin_unlock_irq(¤t->sighand->siglock); | ||
| 1224 | /* A signal was successfully delivered; the saved sigmask is in | ||
| 1225 | its frame, and we can clear the TIF_RESTORE_SIGMASK flag */ | ||
| 1226 | if (test_thread_flag(TIF_RESTORE_SIGMASK)) | ||
| 1227 | clear_thread_flag(TIF_RESTORE_SIGMASK); | ||
| 1228 | } | ||
| 1229 | |||
| 1230 | return ret; | ||
| 1231 | } | ||
diff --git a/arch/powerpc/kernel/signal_64.c b/arch/powerpc/kernel/signal_64.c index b27e26852fdb..de895e6d8c62 100644 --- a/arch/powerpc/kernel/signal_64.c +++ b/arch/powerpc/kernel/signal_64.c | |||
| @@ -34,9 +34,9 @@ | |||
| 34 | #include <asm/syscalls.h> | 34 | #include <asm/syscalls.h> |
| 35 | #include <asm/vdso.h> | 35 | #include <asm/vdso.h> |
| 36 | 36 | ||
| 37 | #define DEBUG_SIG 0 | 37 | #include "signal.h" |
| 38 | 38 | ||
| 39 | #define _BLOCKABLE (~(sigmask(SIGKILL) | sigmask(SIGSTOP))) | 39 | #define DEBUG_SIG 0 |
| 40 | 40 | ||
| 41 | #define GP_REGS_SIZE min(sizeof(elf_gregset_t), sizeof(struct pt_regs)) | 41 | #define GP_REGS_SIZE min(sizeof(elf_gregset_t), sizeof(struct pt_regs)) |
| 42 | #define FP_REGS_SIZE sizeof(elf_fpregset_t) | 42 | #define FP_REGS_SIZE sizeof(elf_fpregset_t) |
| @@ -64,14 +64,6 @@ struct rt_sigframe { | |||
| 64 | char abigap[288]; | 64 | char abigap[288]; |
| 65 | } __attribute__ ((aligned (16))); | 65 | } __attribute__ ((aligned (16))); |
| 66 | 66 | ||
| 67 | long sys_sigaltstack(const stack_t __user *uss, stack_t __user *uoss, unsigned long r5, | ||
| 68 | unsigned long r6, unsigned long r7, unsigned long r8, | ||
| 69 | struct pt_regs *regs) | ||
| 70 | { | ||
| 71 | return do_sigaltstack(uss, uoss, regs->gpr[1]); | ||
| 72 | } | ||
| 73 | |||
| 74 | |||
| 75 | /* | 67 | /* |
| 76 | * Set up the sigcontext for the signal frame. | 68 | * Set up the sigcontext for the signal frame. |
| 77 | */ | 69 | */ |
| @@ -208,25 +200,6 @@ static long restore_sigcontext(struct pt_regs *regs, sigset_t *set, int sig, | |||
| 208 | } | 200 | } |
| 209 | 201 | ||
| 210 | /* | 202 | /* |
| 211 | * Allocate space for the signal frame | ||
| 212 | */ | ||
| 213 | static inline void __user * get_sigframe(struct k_sigaction *ka, struct pt_regs *regs, | ||
| 214 | size_t frame_size) | ||
| 215 | { | ||
| 216 | unsigned long newsp; | ||
| 217 | |||
| 218 | /* Default to using normal stack */ | ||
| 219 | newsp = regs->gpr[1]; | ||
| 220 | |||
| 221 | if ((ka->sa.sa_flags & SA_ONSTACK) && current->sas_ss_size) { | ||
| 222 | if (! on_sig_stack(regs->gpr[1])) | ||
| 223 | newsp = (current->sas_ss_sp + current->sas_ss_size); | ||
| 224 | } | ||
| 225 | |||
| 226 | return (void __user *)((newsp - frame_size) & -16ul); | ||
| 227 | } | ||
| 228 | |||
| 229 | /* | ||
| 230 | * Setup the trampoline code on the stack | 203 | * Setup the trampoline code on the stack |
| 231 | */ | 204 | */ |
| 232 | static long setup_trampoline(unsigned int syscall, unsigned int __user *tramp) | 205 | static long setup_trampoline(unsigned int syscall, unsigned int __user *tramp) |
| @@ -253,19 +226,6 @@ static long setup_trampoline(unsigned int syscall, unsigned int __user *tramp) | |||
| 253 | } | 226 | } |
| 254 | 227 | ||
| 255 | /* | 228 | /* |
| 256 | * Restore the user process's signal mask (also used by signal32.c) | ||
| 257 | */ | ||
| 258 | void restore_sigmask(sigset_t *set) | ||
| 259 | { | ||
| 260 | sigdelsetmask(set, ~_BLOCKABLE); | ||
| 261 | spin_lock_irq(¤t->sighand->siglock); | ||
| 262 | current->blocked = *set; | ||
| 263 | recalc_sigpending(); | ||
| 264 | spin_unlock_irq(¤t->sighand->siglock); | ||
| 265 | } | ||
| 266 | |||
| 267 | |||
| 268 | /* | ||
| 269 | * Handle {get,set,swap}_context operations | 229 | * Handle {get,set,swap}_context operations |
| 270 | */ | 230 | */ |
| 271 | int sys_swapcontext(struct ucontext __user *old_ctx, | 231 | int sys_swapcontext(struct ucontext __user *old_ctx, |
| @@ -359,7 +319,7 @@ badframe: | |||
| 359 | return 0; | 319 | return 0; |
| 360 | } | 320 | } |
| 361 | 321 | ||
| 362 | static int setup_rt_frame(int signr, struct k_sigaction *ka, siginfo_t *info, | 322 | int handle_rt_signal64(int signr, struct k_sigaction *ka, siginfo_t *info, |
| 363 | sigset_t *set, struct pt_regs *regs) | 323 | sigset_t *set, struct pt_regs *regs) |
| 364 | { | 324 | { |
| 365 | /* Handler is *really* a pointer to the function descriptor for | 325 | /* Handler is *really* a pointer to the function descriptor for |
| @@ -373,8 +333,7 @@ static int setup_rt_frame(int signr, struct k_sigaction *ka, siginfo_t *info, | |||
| 373 | long err = 0; | 333 | long err = 0; |
| 374 | 334 | ||
| 375 | frame = get_sigframe(ka, regs, sizeof(*frame)); | 335 | frame = get_sigframe(ka, regs, sizeof(*frame)); |
| 376 | 336 | if (unlikely(frame == NULL)) | |
| 377 | if (!access_ok(VERIFY_WRITE, frame, sizeof(*frame))) | ||
| 378 | goto badframe; | 337 | goto badframe; |
| 379 | 338 | ||
| 380 | err |= __put_user(&frame->info, &frame->pinfo); | 339 | err |= __put_user(&frame->info, &frame->pinfo); |
| @@ -411,7 +370,7 @@ static int setup_rt_frame(int signr, struct k_sigaction *ka, siginfo_t *info, | |||
| 411 | funct_desc_ptr = (func_descr_t __user *) ka->sa.sa_handler; | 370 | funct_desc_ptr = (func_descr_t __user *) ka->sa.sa_handler; |
| 412 | 371 | ||
| 413 | /* Allocate a dummy caller frame for the signal handler. */ | 372 | /* Allocate a dummy caller frame for the signal handler. */ |
| 414 | newsp = (unsigned long)frame - __SIGNAL_FRAMESIZE; | 373 | newsp = ((unsigned long)frame) - __SIGNAL_FRAMESIZE; |
| 415 | err |= put_user(regs->gpr[1], (unsigned long __user *)newsp); | 374 | err |= put_user(regs->gpr[1], (unsigned long __user *)newsp); |
| 416 | 375 | ||
| 417 | /* Set up "regs" so we "return" to the signal handler. */ | 376 | /* Set up "regs" so we "return" to the signal handler. */ |
| @@ -442,134 +401,3 @@ badframe: | |||
| 442 | force_sigsegv(signr, current); | 401 | force_sigsegv(signr, current); |
| 443 | return 0; | 402 | return 0; |
| 444 | } | 403 | } |
| 445 | |||
| 446 | |||
| 447 | /* | ||
| 448 | * OK, we're invoking a handler | ||
| 449 | */ | ||
| 450 | static int handle_signal(unsigned long sig, struct k_sigaction *ka, | ||
| 451 | siginfo_t *info, sigset_t *oldset, struct pt_regs *regs) | ||
| 452 | { | ||
| 453 | int ret; | ||
| 454 | |||
| 455 | /* Set up Signal Frame */ | ||
| 456 | ret = setup_rt_frame(sig, ka, info, oldset, regs); | ||
| 457 | |||
| 458 | if (ret) { | ||
| 459 | spin_lock_irq(¤t->sighand->siglock); | ||
| 460 | sigorsets(¤t->blocked, ¤t->blocked, &ka->sa.sa_mask); | ||
| 461 | if (!(ka->sa.sa_flags & SA_NODEFER)) | ||
| 462 | sigaddset(¤t->blocked,sig); | ||
| 463 | recalc_sigpending(); | ||
| 464 | spin_unlock_irq(¤t->sighand->siglock); | ||
| 465 | } | ||
| 466 | |||
| 467 | return ret; | ||
| 468 | } | ||
| 469 | |||
| 470 | static inline void syscall_restart(struct pt_regs *regs, struct k_sigaction *ka) | ||
| 471 | { | ||
| 472 | switch ((int)regs->result) { | ||
| 473 | case -ERESTART_RESTARTBLOCK: | ||
| 474 | case -ERESTARTNOHAND: | ||
| 475 | /* ERESTARTNOHAND means that the syscall should only be | ||
| 476 | * restarted if there was no handler for the signal, and since | ||
| 477 | * we only get here if there is a handler, we dont restart. | ||
| 478 | */ | ||
| 479 | regs->result = -EINTR; | ||
| 480 | regs->gpr[3] = EINTR; | ||
| 481 | regs->ccr |= 0x10000000; | ||
| 482 | break; | ||
| 483 | case -ERESTARTSYS: | ||
| 484 | /* ERESTARTSYS means to restart the syscall if there is no | ||
| 485 | * handler or the handler was registered with SA_RESTART | ||
| 486 | */ | ||
| 487 | if (!(ka->sa.sa_flags & SA_RESTART)) { | ||
| 488 | regs->result = -EINTR; | ||
| 489 | regs->gpr[3] = EINTR; | ||
| 490 | regs->ccr |= 0x10000000; | ||
| 491 | break; | ||
| 492 | } | ||
| 493 | /* fallthrough */ | ||
| 494 | case -ERESTARTNOINTR: | ||
| 495 | /* ERESTARTNOINTR means that the syscall should be | ||
| 496 | * called again after the signal handler returns. | ||
| 497 | */ | ||
| 498 | regs->gpr[3] = regs->orig_gpr3; | ||
| 499 | regs->nip -= 4; | ||
| 500 | regs->result = 0; | ||
| 501 | break; | ||
| 502 | } | ||
| 503 | } | ||
| 504 | |||
| 505 | /* | ||
| 506 | * Note that 'init' is a special process: it doesn't get signals it doesn't | ||
| 507 | * want to handle. Thus you cannot kill init even with a SIGKILL even by | ||
| 508 | * mistake. | ||
| 509 | */ | ||
| 510 | int do_signal(sigset_t *oldset, struct pt_regs *regs) | ||
| 511 | { | ||
| 512 | siginfo_t info; | ||
| 513 | int signr; | ||
| 514 | struct k_sigaction ka; | ||
| 515 | |||
| 516 | /* | ||
| 517 | * If the current thread is 32 bit - invoke the | ||
| 518 | * 32 bit signal handling code | ||
| 519 | */ | ||
| 520 | if (test_thread_flag(TIF_32BIT)) | ||
| 521 | return do_signal32(oldset, regs); | ||
| 522 | |||
| 523 | if (test_thread_flag(TIF_RESTORE_SIGMASK)) | ||
| 524 | oldset = ¤t->saved_sigmask; | ||
| 525 | else if (!oldset) | ||
| 526 | oldset = ¤t->blocked; | ||
| 527 | |||
| 528 | signr = get_signal_to_deliver(&info, &ka, regs, NULL); | ||
| 529 | if (signr > 0) { | ||
| 530 | int ret; | ||
| 531 | |||
| 532 | /* Whee! Actually deliver the signal. */ | ||
| 533 | if (TRAP(regs) == 0x0C00) | ||
| 534 | syscall_restart(regs, &ka); | ||
| 535 | |||
| 536 | /* | ||
| 537 | * Reenable the DABR before delivering the signal to | ||
| 538 | * user space. The DABR will have been cleared if it | ||
| 539 | * triggered inside the kernel. | ||
| 540 | */ | ||
| 541 | if (current->thread.dabr) | ||
| 542 | set_dabr(current->thread.dabr); | ||
| 543 | |||
| 544 | ret = handle_signal(signr, &ka, &info, oldset, regs); | ||
| 545 | |||
| 546 | /* If a signal was successfully delivered, the saved sigmask is in | ||
| 547 | its frame, and we can clear the TIF_RESTORE_SIGMASK flag */ | ||
| 548 | if (ret && test_thread_flag(TIF_RESTORE_SIGMASK)) | ||
| 549 | clear_thread_flag(TIF_RESTORE_SIGMASK); | ||
| 550 | |||
| 551 | return ret; | ||
| 552 | } | ||
| 553 | |||
| 554 | if (TRAP(regs) == 0x0C00) { /* System Call! */ | ||
| 555 | if ((int)regs->result == -ERESTARTNOHAND || | ||
| 556 | (int)regs->result == -ERESTARTSYS || | ||
| 557 | (int)regs->result == -ERESTARTNOINTR) { | ||
| 558 | regs->gpr[3] = regs->orig_gpr3; | ||
| 559 | regs->nip -= 4; /* Back up & retry system call */ | ||
| 560 | regs->result = 0; | ||
| 561 | } else if ((int)regs->result == -ERESTART_RESTARTBLOCK) { | ||
| 562 | regs->gpr[0] = __NR_restart_syscall; | ||
| 563 | regs->nip -= 4; | ||
| 564 | regs->result = 0; | ||
| 565 | } | ||
| 566 | } | ||
| 567 | /* No signal to deliver -- put the saved sigmask back */ | ||
| 568 | if (test_thread_flag(TIF_RESTORE_SIGMASK)) { | ||
| 569 | clear_thread_flag(TIF_RESTORE_SIGMASK); | ||
| 570 | sigprocmask(SIG_SETMASK, ¤t->saved_sigmask, NULL); | ||
| 571 | } | ||
| 572 | |||
| 573 | return 0; | ||
| 574 | } | ||
| 575 | EXPORT_SYMBOL(do_signal); | ||
diff --git a/arch/powerpc/kernel/sysfs.c b/arch/powerpc/kernel/sysfs.c index 68991c2d4a1b..55d29ed4b7a0 100644 --- a/arch/powerpc/kernel/sysfs.c +++ b/arch/powerpc/kernel/sysfs.c | |||
| @@ -442,12 +442,14 @@ int sysfs_add_device_to_node(struct sys_device *dev, int nid) | |||
| 442 | return sysfs_create_link(&node->sysdev.kobj, &dev->kobj, | 442 | return sysfs_create_link(&node->sysdev.kobj, &dev->kobj, |
| 443 | kobject_name(&dev->kobj)); | 443 | kobject_name(&dev->kobj)); |
| 444 | } | 444 | } |
| 445 | EXPORT_SYMBOL_GPL(sysfs_add_device_to_node); | ||
| 445 | 446 | ||
| 446 | void sysfs_remove_device_from_node(struct sys_device *dev, int nid) | 447 | void sysfs_remove_device_from_node(struct sys_device *dev, int nid) |
| 447 | { | 448 | { |
| 448 | struct node *node = &node_devices[nid]; | 449 | struct node *node = &node_devices[nid]; |
| 449 | sysfs_remove_link(&node->sysdev.kobj, kobject_name(&dev->kobj)); | 450 | sysfs_remove_link(&node->sysdev.kobj, kobject_name(&dev->kobj)); |
| 450 | } | 451 | } |
| 452 | EXPORT_SYMBOL_GPL(sysfs_remove_device_from_node); | ||
| 451 | 453 | ||
| 452 | #else | 454 | #else |
| 453 | static void register_nodes(void) | 455 | static void register_nodes(void) |
| @@ -457,9 +459,6 @@ static void register_nodes(void) | |||
| 457 | 459 | ||
| 458 | #endif | 460 | #endif |
| 459 | 461 | ||
| 460 | EXPORT_SYMBOL_GPL(sysfs_add_device_to_node); | ||
| 461 | EXPORT_SYMBOL_GPL(sysfs_remove_device_from_node); | ||
| 462 | |||
| 463 | /* Only valid if CPU is present. */ | 462 | /* Only valid if CPU is present. */ |
| 464 | static ssize_t show_physical_id(struct sys_device *dev, char *buf) | 463 | static ssize_t show_physical_id(struct sys_device *dev, char *buf) |
| 465 | { | 464 | { |
diff --git a/arch/powerpc/kernel/time.c b/arch/powerpc/kernel/time.c index 2c8564d54e4d..e5df167f7824 100644 --- a/arch/powerpc/kernel/time.c +++ b/arch/powerpc/kernel/time.c | |||
| @@ -77,9 +77,8 @@ | |||
| 77 | /* keep track of when we need to update the rtc */ | 77 | /* keep track of when we need to update the rtc */ |
| 78 | time_t last_rtc_update; | 78 | time_t last_rtc_update; |
| 79 | #ifdef CONFIG_PPC_ISERIES | 79 | #ifdef CONFIG_PPC_ISERIES |
| 80 | unsigned long iSeries_recal_titan = 0; | 80 | static unsigned long __initdata iSeries_recal_titan; |
| 81 | unsigned long iSeries_recal_tb = 0; | 81 | static signed long __initdata iSeries_recal_tb; |
| 82 | static unsigned long first_settimeofday = 1; | ||
| 83 | #endif | 82 | #endif |
| 84 | 83 | ||
| 85 | /* The decrementer counts down by 128 every 128ns on a 601. */ | 84 | /* The decrementer counts down by 128 every 128ns on a 601. */ |
| @@ -113,8 +112,9 @@ u64 ticklen_to_xs; /* 0.64 fraction */ | |||
| 113 | DEFINE_SPINLOCK(rtc_lock); | 112 | DEFINE_SPINLOCK(rtc_lock); |
| 114 | EXPORT_SYMBOL_GPL(rtc_lock); | 113 | EXPORT_SYMBOL_GPL(rtc_lock); |
| 115 | 114 | ||
| 116 | u64 tb_to_ns_scale; | 115 | static u64 tb_to_ns_scale __read_mostly; |
| 117 | unsigned tb_to_ns_shift; | 116 | static unsigned tb_to_ns_shift __read_mostly; |
| 117 | static unsigned long boot_tb __read_mostly; | ||
| 118 | 118 | ||
| 119 | struct gettimeofday_struct do_gtod; | 119 | struct gettimeofday_struct do_gtod; |
| 120 | 120 | ||
| @@ -214,7 +214,6 @@ static void account_process_time(struct pt_regs *regs) | |||
| 214 | run_posix_cpu_timers(current); | 214 | run_posix_cpu_timers(current); |
| 215 | } | 215 | } |
| 216 | 216 | ||
| 217 | #ifdef CONFIG_PPC_SPLPAR | ||
| 218 | /* | 217 | /* |
| 219 | * Stuff for accounting stolen time. | 218 | * Stuff for accounting stolen time. |
| 220 | */ | 219 | */ |
| @@ -222,19 +221,28 @@ struct cpu_purr_data { | |||
| 222 | int initialized; /* thread is running */ | 221 | int initialized; /* thread is running */ |
| 223 | u64 tb; /* last TB value read */ | 222 | u64 tb; /* last TB value read */ |
| 224 | u64 purr; /* last PURR value read */ | 223 | u64 purr; /* last PURR value read */ |
| 225 | spinlock_t lock; | ||
| 226 | }; | 224 | }; |
| 227 | 225 | ||
| 226 | /* | ||
| 227 | * Each entry in the cpu_purr_data array is manipulated only by its | ||
| 228 | * "owner" cpu -- usually in the timer interrupt but also occasionally | ||
| 229 | * in process context for cpu online. As long as cpus do not touch | ||
| 230 | * each others' cpu_purr_data, disabling local interrupts is | ||
| 231 | * sufficient to serialize accesses. | ||
| 232 | */ | ||
| 228 | static DEFINE_PER_CPU(struct cpu_purr_data, cpu_purr_data); | 233 | static DEFINE_PER_CPU(struct cpu_purr_data, cpu_purr_data); |
| 229 | 234 | ||
| 230 | static void snapshot_tb_and_purr(void *data) | 235 | static void snapshot_tb_and_purr(void *data) |
| 231 | { | 236 | { |
| 237 | unsigned long flags; | ||
| 232 | struct cpu_purr_data *p = &__get_cpu_var(cpu_purr_data); | 238 | struct cpu_purr_data *p = &__get_cpu_var(cpu_purr_data); |
| 233 | 239 | ||
| 240 | local_irq_save(flags); | ||
| 234 | p->tb = mftb(); | 241 | p->tb = mftb(); |
| 235 | p->purr = mfspr(SPRN_PURR); | 242 | p->purr = mfspr(SPRN_PURR); |
| 236 | wmb(); | 243 | wmb(); |
| 237 | p->initialized = 1; | 244 | p->initialized = 1; |
| 245 | local_irq_restore(flags); | ||
| 238 | } | 246 | } |
| 239 | 247 | ||
| 240 | /* | 248 | /* |
| @@ -242,15 +250,14 @@ static void snapshot_tb_and_purr(void *data) | |||
| 242 | */ | 250 | */ |
| 243 | void snapshot_timebases(void) | 251 | void snapshot_timebases(void) |
| 244 | { | 252 | { |
| 245 | int cpu; | ||
| 246 | |||
| 247 | if (!cpu_has_feature(CPU_FTR_PURR)) | 253 | if (!cpu_has_feature(CPU_FTR_PURR)) |
| 248 | return; | 254 | return; |
| 249 | for_each_possible_cpu(cpu) | ||
| 250 | spin_lock_init(&per_cpu(cpu_purr_data, cpu).lock); | ||
| 251 | on_each_cpu(snapshot_tb_and_purr, NULL, 0, 1); | 255 | on_each_cpu(snapshot_tb_and_purr, NULL, 0, 1); |
| 252 | } | 256 | } |
| 253 | 257 | ||
| 258 | /* | ||
| 259 | * Must be called with interrupts disabled. | ||
| 260 | */ | ||
| 254 | void calculate_steal_time(void) | 261 | void calculate_steal_time(void) |
| 255 | { | 262 | { |
| 256 | u64 tb, purr; | 263 | u64 tb, purr; |
| @@ -262,7 +269,6 @@ void calculate_steal_time(void) | |||
| 262 | pme = &per_cpu(cpu_purr_data, smp_processor_id()); | 269 | pme = &per_cpu(cpu_purr_data, smp_processor_id()); |
| 263 | if (!pme->initialized) | 270 | if (!pme->initialized) |
| 264 | return; /* this can happen in early boot */ | 271 | return; /* this can happen in early boot */ |
| 265 | spin_lock(&pme->lock); | ||
| 266 | tb = mftb(); | 272 | tb = mftb(); |
| 267 | purr = mfspr(SPRN_PURR); | 273 | purr = mfspr(SPRN_PURR); |
| 268 | stolen = (tb - pme->tb) - (purr - pme->purr); | 274 | stolen = (tb - pme->tb) - (purr - pme->purr); |
| @@ -270,9 +276,9 @@ void calculate_steal_time(void) | |||
| 270 | account_steal_time(current, stolen); | 276 | account_steal_time(current, stolen); |
| 271 | pme->tb = tb; | 277 | pme->tb = tb; |
| 272 | pme->purr = purr; | 278 | pme->purr = purr; |
| 273 | spin_unlock(&pme->lock); | ||
| 274 | } | 279 | } |
| 275 | 280 | ||
| 281 | #ifdef CONFIG_PPC_SPLPAR | ||
| 276 | /* | 282 | /* |
| 277 | * Must be called before the cpu is added to the online map when | 283 | * Must be called before the cpu is added to the online map when |
| 278 | * a cpu is being brought up at runtime. | 284 | * a cpu is being brought up at runtime. |
| @@ -284,12 +290,12 @@ static void snapshot_purr(void) | |||
| 284 | 290 | ||
| 285 | if (!cpu_has_feature(CPU_FTR_PURR)) | 291 | if (!cpu_has_feature(CPU_FTR_PURR)) |
| 286 | return; | 292 | return; |
| 293 | local_irq_save(flags); | ||
| 287 | pme = &per_cpu(cpu_purr_data, smp_processor_id()); | 294 | pme = &per_cpu(cpu_purr_data, smp_processor_id()); |
| 288 | spin_lock_irqsave(&pme->lock, flags); | ||
| 289 | pme->tb = mftb(); | 295 | pme->tb = mftb(); |
| 290 | pme->purr = mfspr(SPRN_PURR); | 296 | pme->purr = mfspr(SPRN_PURR); |
| 291 | pme->initialized = 1; | 297 | pme->initialized = 1; |
| 292 | spin_unlock_irqrestore(&pme->lock, flags); | 298 | local_irq_restore(flags); |
| 293 | } | 299 | } |
| 294 | 300 | ||
| 295 | #endif /* CONFIG_PPC_SPLPAR */ | 301 | #endif /* CONFIG_PPC_SPLPAR */ |
| @@ -550,10 +556,15 @@ EXPORT_SYMBOL(profile_pc); | |||
| 550 | * returned by the service processor for the timebase frequency. | 556 | * returned by the service processor for the timebase frequency. |
| 551 | */ | 557 | */ |
| 552 | 558 | ||
| 553 | static void iSeries_tb_recal(void) | 559 | static int __init iSeries_tb_recal(void) |
| 554 | { | 560 | { |
| 555 | struct div_result divres; | 561 | struct div_result divres; |
| 556 | unsigned long titan, tb; | 562 | unsigned long titan, tb; |
| 563 | |||
| 564 | /* Make sure we only run on iSeries */ | ||
| 565 | if (!firmware_has_feature(FW_FEATURE_ISERIES)) | ||
| 566 | return -ENODEV; | ||
| 567 | |||
| 557 | tb = get_tb(); | 568 | tb = get_tb(); |
| 558 | titan = HvCallXm_loadTod(); | 569 | titan = HvCallXm_loadTod(); |
| 559 | if ( iSeries_recal_titan ) { | 570 | if ( iSeries_recal_titan ) { |
| @@ -594,8 +605,18 @@ static void iSeries_tb_recal(void) | |||
| 594 | } | 605 | } |
| 595 | iSeries_recal_titan = titan; | 606 | iSeries_recal_titan = titan; |
| 596 | iSeries_recal_tb = tb; | 607 | iSeries_recal_tb = tb; |
| 608 | |||
| 609 | return 0; | ||
| 597 | } | 610 | } |
| 598 | #endif | 611 | late_initcall(iSeries_tb_recal); |
| 612 | |||
| 613 | /* Called from platform early init */ | ||
| 614 | void __init iSeries_time_init_early(void) | ||
| 615 | { | ||
| 616 | iSeries_recal_tb = get_tb(); | ||
| 617 | iSeries_recal_titan = HvCallXm_loadTod(); | ||
| 618 | } | ||
| 619 | #endif /* CONFIG_PPC_ISERIES */ | ||
| 599 | 620 | ||
| 600 | /* | 621 | /* |
| 601 | * For iSeries shared processors, we have to let the hypervisor | 622 | * For iSeries shared processors, we have to let the hypervisor |
| @@ -735,7 +756,7 @@ unsigned long long sched_clock(void) | |||
| 735 | { | 756 | { |
| 736 | if (__USE_RTC()) | 757 | if (__USE_RTC()) |
| 737 | return get_rtc(); | 758 | return get_rtc(); |
| 738 | return mulhdu(get_tb(), tb_to_ns_scale) << tb_to_ns_shift; | 759 | return mulhdu(get_tb() - boot_tb, tb_to_ns_scale) << tb_to_ns_shift; |
| 739 | } | 760 | } |
| 740 | 761 | ||
| 741 | int do_settimeofday(struct timespec *tv) | 762 | int do_settimeofday(struct timespec *tv) |
| @@ -759,12 +780,6 @@ int do_settimeofday(struct timespec *tv) | |||
| 759 | * to the RTC again, or write to the RTC but then they don't call | 780 | * to the RTC again, or write to the RTC but then they don't call |
| 760 | * settimeofday to perform this operation. | 781 | * settimeofday to perform this operation. |
| 761 | */ | 782 | */ |
| 762 | #ifdef CONFIG_PPC_ISERIES | ||
| 763 | if (firmware_has_feature(FW_FEATURE_ISERIES) && first_settimeofday) { | ||
| 764 | iSeries_tb_recal(); | ||
| 765 | first_settimeofday = 0; | ||
| 766 | } | ||
| 767 | #endif | ||
| 768 | 783 | ||
| 769 | /* Make userspace gettimeofday spin until we're done. */ | 784 | /* Make userspace gettimeofday spin until we're done. */ |
| 770 | ++vdso_data->tb_update_count; | 785 | ++vdso_data->tb_update_count; |
| @@ -960,6 +975,8 @@ void __init time_init(void) | |||
| 960 | } | 975 | } |
| 961 | tb_to_ns_scale = scale; | 976 | tb_to_ns_scale = scale; |
| 962 | tb_to_ns_shift = shift; | 977 | tb_to_ns_shift = shift; |
| 978 | /* Save the current timebase to pretty up CONFIG_PRINTK_TIME */ | ||
| 979 | boot_tb = get_tb(); | ||
| 963 | 980 | ||
| 964 | tm = get_boot_time(); | 981 | tm = get_boot_time(); |
| 965 | 982 | ||
diff --git a/arch/powerpc/kernel/vdso.c b/arch/powerpc/kernel/vdso.c index 4245579edb4e..cef01e4e8989 100644 --- a/arch/powerpc/kernel/vdso.c +++ b/arch/powerpc/kernel/vdso.c | |||
| @@ -670,7 +670,7 @@ static int __init vdso_init(void) | |||
| 670 | /* | 670 | /* |
| 671 | * Fill up the "systemcfg" stuff for backward compatiblity | 671 | * Fill up the "systemcfg" stuff for backward compatiblity |
| 672 | */ | 672 | */ |
| 673 | strcpy(vdso_data->eye_catcher, "SYSTEMCFG:PPC64"); | 673 | strcpy((char *)vdso_data->eye_catcher, "SYSTEMCFG:PPC64"); |
| 674 | vdso_data->version.major = SYSTEMCFG_MAJOR; | 674 | vdso_data->version.major = SYSTEMCFG_MAJOR; |
| 675 | vdso_data->version.minor = SYSTEMCFG_MINOR; | 675 | vdso_data->version.minor = SYSTEMCFG_MINOR; |
| 676 | vdso_data->processor = mfspr(SPRN_PVR); | 676 | vdso_data->processor = mfspr(SPRN_PVR); |
diff --git a/arch/powerpc/kernel/vmlinux.lds.S b/arch/powerpc/kernel/vmlinux.lds.S index 21c39ff2dc39..ae4acd84143d 100644 --- a/arch/powerpc/kernel/vmlinux.lds.S +++ b/arch/powerpc/kernel/vmlinux.lds.S | |||
| @@ -7,6 +7,7 @@ | |||
| 7 | #define PROVIDE32(x) PROVIDE(x) | 7 | #define PROVIDE32(x) PROVIDE(x) |
| 8 | #endif | 8 | #endif |
| 9 | #include <asm-generic/vmlinux.lds.h> | 9 | #include <asm-generic/vmlinux.lds.h> |
| 10 | #include <asm/cache.h> | ||
| 10 | 11 | ||
| 11 | ENTRY(_stext) | 12 | ENTRY(_stext) |
| 12 | 13 | ||
| @@ -211,6 +212,11 @@ SECTIONS | |||
| 211 | *(.data.cacheline_aligned) | 212 | *(.data.cacheline_aligned) |
| 212 | } | 213 | } |
| 213 | 214 | ||
| 215 | . = ALIGN(L1_CACHE_BYTES); | ||
| 216 | .data.read_mostly : { | ||
| 217 | *(.data.read_mostly) | ||
| 218 | } | ||
| 219 | |||
| 214 | . = ALIGN(PAGE_SIZE); | 220 | . = ALIGN(PAGE_SIZE); |
| 215 | __data_nosave : { | 221 | __data_nosave : { |
| 216 | __nosave_begin = .; | 222 | __nosave_begin = .; |
