Commit f2ab4461249df85b20930a7a57b54f39c5ae291a
Committed by
Linus Torvalds
1 parent
4f0cb8d978
Exists in
master
and in
4 other branches
[PATCH] x86: more asm cleanups
Some more assembler cleanups I noticed along the way. Signed-off-by: Zachary Amsden <zach@vmware.com> Cc: "H. Peter Anvin" <hpa@zytor.com> Signed-off-by: Andrew Morton <akpm@osdl.org> Signed-off-by: Linus Torvalds <torvalds@osdl.org>
Showing 8 changed files with 35 additions and 50 deletions Inline Diff
arch/i386/kernel/cpu/intel.c
| 1 | #include <linux/config.h> | 1 | #include <linux/config.h> |
| 2 | #include <linux/init.h> | 2 | #include <linux/init.h> |
| 3 | #include <linux/kernel.h> | 3 | #include <linux/kernel.h> |
| 4 | 4 | ||
| 5 | #include <linux/string.h> | 5 | #include <linux/string.h> |
| 6 | #include <linux/bitops.h> | 6 | #include <linux/bitops.h> |
| 7 | #include <linux/smp.h> | 7 | #include <linux/smp.h> |
| 8 | #include <linux/thread_info.h> | 8 | #include <linux/thread_info.h> |
| 9 | 9 | ||
| 10 | #include <asm/processor.h> | 10 | #include <asm/processor.h> |
| 11 | #include <asm/msr.h> | 11 | #include <asm/msr.h> |
| 12 | #include <asm/uaccess.h> | 12 | #include <asm/uaccess.h> |
| 13 | 13 | ||
| 14 | #include "cpu.h" | 14 | #include "cpu.h" |
| 15 | 15 | ||
| 16 | #ifdef CONFIG_X86_LOCAL_APIC | 16 | #ifdef CONFIG_X86_LOCAL_APIC |
| 17 | #include <asm/mpspec.h> | 17 | #include <asm/mpspec.h> |
| 18 | #include <asm/apic.h> | 18 | #include <asm/apic.h> |
| 19 | #include <mach_apic.h> | 19 | #include <mach_apic.h> |
| 20 | #endif | 20 | #endif |
| 21 | 21 | ||
| 22 | extern int trap_init_f00f_bug(void); | 22 | extern int trap_init_f00f_bug(void); |
| 23 | 23 | ||
| 24 | #ifdef CONFIG_X86_INTEL_USERCOPY | 24 | #ifdef CONFIG_X86_INTEL_USERCOPY |
| 25 | /* | 25 | /* |
| 26 | * Alignment at which movsl is preferred for bulk memory copies. | 26 | * Alignment at which movsl is preferred for bulk memory copies. |
| 27 | */ | 27 | */ |
| 28 | struct movsl_mask movsl_mask __read_mostly; | 28 | struct movsl_mask movsl_mask __read_mostly; |
| 29 | #endif | 29 | #endif |
| 30 | 30 | ||
| 31 | void __devinit early_intel_workaround(struct cpuinfo_x86 *c) | 31 | void __devinit early_intel_workaround(struct cpuinfo_x86 *c) |
| 32 | { | 32 | { |
| 33 | if (c->x86_vendor != X86_VENDOR_INTEL) | 33 | if (c->x86_vendor != X86_VENDOR_INTEL) |
| 34 | return; | 34 | return; |
| 35 | /* Netburst reports 64 bytes clflush size, but does IO in 128 bytes */ | 35 | /* Netburst reports 64 bytes clflush size, but does IO in 128 bytes */ |
| 36 | if (c->x86 == 15 && c->x86_cache_alignment == 64) | 36 | if (c->x86 == 15 && c->x86_cache_alignment == 64) |
| 37 | c->x86_cache_alignment = 128; | 37 | c->x86_cache_alignment = 128; |
| 38 | } | 38 | } |
| 39 | 39 | ||
| 40 | /* | 40 | /* |
| 41 | * Early probe support logic for ppro memory erratum #50 | 41 | * Early probe support logic for ppro memory erratum #50 |
| 42 | * | 42 | * |
| 43 | * This is called before we do cpu ident work | 43 | * This is called before we do cpu ident work |
| 44 | */ | 44 | */ |
| 45 | 45 | ||
| 46 | int __devinit ppro_with_ram_bug(void) | 46 | int __devinit ppro_with_ram_bug(void) |
| 47 | { | 47 | { |
| 48 | /* Uses data from early_cpu_detect now */ | 48 | /* Uses data from early_cpu_detect now */ |
| 49 | if (boot_cpu_data.x86_vendor == X86_VENDOR_INTEL && | 49 | if (boot_cpu_data.x86_vendor == X86_VENDOR_INTEL && |
| 50 | boot_cpu_data.x86 == 6 && | 50 | boot_cpu_data.x86 == 6 && |
| 51 | boot_cpu_data.x86_model == 1 && | 51 | boot_cpu_data.x86_model == 1 && |
| 52 | boot_cpu_data.x86_mask < 8) { | 52 | boot_cpu_data.x86_mask < 8) { |
| 53 | printk(KERN_INFO "Pentium Pro with Errata#50 detected. Taking evasive action.\n"); | 53 | printk(KERN_INFO "Pentium Pro with Errata#50 detected. Taking evasive action.\n"); |
| 54 | return 1; | 54 | return 1; |
| 55 | } | 55 | } |
| 56 | return 0; | 56 | return 0; |
| 57 | } | 57 | } |
| 58 | 58 | ||
| 59 | 59 | ||
| 60 | /* | 60 | /* |
| 61 | * P4 Xeon errata 037 workaround. | 61 | * P4 Xeon errata 037 workaround. |
| 62 | * Hardware prefetcher may cause stale data to be loaded into the cache. | 62 | * Hardware prefetcher may cause stale data to be loaded into the cache. |
| 63 | */ | 63 | */ |
| 64 | static void __devinit Intel_errata_workarounds(struct cpuinfo_x86 *c) | 64 | static void __devinit Intel_errata_workarounds(struct cpuinfo_x86 *c) |
| 65 | { | 65 | { |
| 66 | unsigned long lo, hi; | 66 | unsigned long lo, hi; |
| 67 | 67 | ||
| 68 | if ((c->x86 == 15) && (c->x86_model == 1) && (c->x86_mask == 1)) { | 68 | if ((c->x86 == 15) && (c->x86_model == 1) && (c->x86_mask == 1)) { |
| 69 | rdmsr (MSR_IA32_MISC_ENABLE, lo, hi); | 69 | rdmsr (MSR_IA32_MISC_ENABLE, lo, hi); |
| 70 | if ((lo & (1<<9)) == 0) { | 70 | if ((lo & (1<<9)) == 0) { |
| 71 | printk (KERN_INFO "CPU: C0 stepping P4 Xeon detected.\n"); | 71 | printk (KERN_INFO "CPU: C0 stepping P4 Xeon detected.\n"); |
| 72 | printk (KERN_INFO "CPU: Disabling hardware prefetching (Errata 037)\n"); | 72 | printk (KERN_INFO "CPU: Disabling hardware prefetching (Errata 037)\n"); |
| 73 | lo |= (1<<9); /* Disable hw prefetching */ | 73 | lo |= (1<<9); /* Disable hw prefetching */ |
| 74 | wrmsr (MSR_IA32_MISC_ENABLE, lo, hi); | 74 | wrmsr (MSR_IA32_MISC_ENABLE, lo, hi); |
| 75 | } | 75 | } |
| 76 | } | 76 | } |
| 77 | } | 77 | } |
| 78 | 78 | ||
| 79 | 79 | ||
| 80 | /* | 80 | /* |
| 81 | * find out the number of processor cores on the die | 81 | * find out the number of processor cores on the die |
| 82 | */ | 82 | */ |
| 83 | static int __devinit num_cpu_cores(struct cpuinfo_x86 *c) | 83 | static int __devinit num_cpu_cores(struct cpuinfo_x86 *c) |
| 84 | { | 84 | { |
| 85 | unsigned int eax; | 85 | unsigned int eax, ebx, ecx, edx; |
| 86 | 86 | ||
| 87 | if (c->cpuid_level < 4) | 87 | if (c->cpuid_level < 4) |
| 88 | return 1; | 88 | return 1; |
| 89 | 89 | ||
| 90 | __asm__("cpuid" | 90 | /* Intel has a non-standard dependency on %ecx for this CPUID level. */ |
| 91 | : "=a" (eax) | 91 | cpuid_count(4, 0, &eax, &ebx, &ecx, &edx); |
| 92 | : "0" (4), "c" (0) | ||
| 93 | : "bx", "dx"); | ||
| 94 | |||
| 95 | if (eax & 0x1f) | 92 | if (eax & 0x1f) |
| 96 | return ((eax >> 26) + 1); | 93 | return ((eax >> 26) + 1); |
| 97 | else | 94 | else |
| 98 | return 1; | 95 | return 1; |
| 99 | } | 96 | } |
| 100 | 97 | ||
| 101 | static void __devinit init_intel(struct cpuinfo_x86 *c) | 98 | static void __devinit init_intel(struct cpuinfo_x86 *c) |
| 102 | { | 99 | { |
| 103 | unsigned int l2 = 0; | 100 | unsigned int l2 = 0; |
| 104 | char *p = NULL; | 101 | char *p = NULL; |
| 105 | 102 | ||
| 106 | #ifdef CONFIG_X86_F00F_BUG | 103 | #ifdef CONFIG_X86_F00F_BUG |
| 107 | /* | 104 | /* |
| 108 | * All current models of Pentium and Pentium with MMX technology CPUs | 105 | * All current models of Pentium and Pentium with MMX technology CPUs |
| 109 | * have the F0 0F bug, which lets nonprivileged users lock up the system. | 106 | * have the F0 0F bug, which lets nonprivileged users lock up the system. |
| 110 | * Note that the workaround only should be initialized once... | 107 | * Note that the workaround only should be initialized once... |
| 111 | */ | 108 | */ |
| 112 | c->f00f_bug = 0; | 109 | c->f00f_bug = 0; |
| 113 | if ( c->x86 == 5 ) { | 110 | if ( c->x86 == 5 ) { |
| 114 | static int f00f_workaround_enabled = 0; | 111 | static int f00f_workaround_enabled = 0; |
| 115 | 112 | ||
| 116 | c->f00f_bug = 1; | 113 | c->f00f_bug = 1; |
| 117 | if ( !f00f_workaround_enabled ) { | 114 | if ( !f00f_workaround_enabled ) { |
| 118 | trap_init_f00f_bug(); | 115 | trap_init_f00f_bug(); |
| 119 | printk(KERN_NOTICE "Intel Pentium with F0 0F bug - workaround enabled.\n"); | 116 | printk(KERN_NOTICE "Intel Pentium with F0 0F bug - workaround enabled.\n"); |
| 120 | f00f_workaround_enabled = 1; | 117 | f00f_workaround_enabled = 1; |
| 121 | } | 118 | } |
| 122 | } | 119 | } |
| 123 | #endif | 120 | #endif |
| 124 | 121 | ||
| 125 | select_idle_routine(c); | 122 | select_idle_routine(c); |
| 126 | l2 = init_intel_cacheinfo(c); | 123 | l2 = init_intel_cacheinfo(c); |
| 127 | 124 | ||
| 128 | /* SEP CPUID bug: Pentium Pro reports SEP but doesn't have it until model 3 mask 3 */ | 125 | /* SEP CPUID bug: Pentium Pro reports SEP but doesn't have it until model 3 mask 3 */ |
| 129 | if ((c->x86<<8 | c->x86_model<<4 | c->x86_mask) < 0x633) | 126 | if ((c->x86<<8 | c->x86_model<<4 | c->x86_mask) < 0x633) |
| 130 | clear_bit(X86_FEATURE_SEP, c->x86_capability); | 127 | clear_bit(X86_FEATURE_SEP, c->x86_capability); |
| 131 | 128 | ||
| 132 | /* Names for the Pentium II/Celeron processors | 129 | /* Names for the Pentium II/Celeron processors |
| 133 | detectable only by also checking the cache size. | 130 | detectable only by also checking the cache size. |
| 134 | Dixon is NOT a Celeron. */ | 131 | Dixon is NOT a Celeron. */ |
| 135 | if (c->x86 == 6) { | 132 | if (c->x86 == 6) { |
| 136 | switch (c->x86_model) { | 133 | switch (c->x86_model) { |
| 137 | case 5: | 134 | case 5: |
| 138 | if (c->x86_mask == 0) { | 135 | if (c->x86_mask == 0) { |
| 139 | if (l2 == 0) | 136 | if (l2 == 0) |
| 140 | p = "Celeron (Covington)"; | 137 | p = "Celeron (Covington)"; |
| 141 | else if (l2 == 256) | 138 | else if (l2 == 256) |
| 142 | p = "Mobile Pentium II (Dixon)"; | 139 | p = "Mobile Pentium II (Dixon)"; |
| 143 | } | 140 | } |
| 144 | break; | 141 | break; |
| 145 | 142 | ||
| 146 | case 6: | 143 | case 6: |
| 147 | if (l2 == 128) | 144 | if (l2 == 128) |
| 148 | p = "Celeron (Mendocino)"; | 145 | p = "Celeron (Mendocino)"; |
| 149 | else if (c->x86_mask == 0 || c->x86_mask == 5) | 146 | else if (c->x86_mask == 0 || c->x86_mask == 5) |
| 150 | p = "Celeron-A"; | 147 | p = "Celeron-A"; |
| 151 | break; | 148 | break; |
| 152 | 149 | ||
| 153 | case 8: | 150 | case 8: |
| 154 | if (l2 == 128) | 151 | if (l2 == 128) |
| 155 | p = "Celeron (Coppermine)"; | 152 | p = "Celeron (Coppermine)"; |
| 156 | break; | 153 | break; |
| 157 | } | 154 | } |
| 158 | } | 155 | } |
| 159 | 156 | ||
| 160 | if ( p ) | 157 | if ( p ) |
| 161 | strcpy(c->x86_model_id, p); | 158 | strcpy(c->x86_model_id, p); |
| 162 | 159 | ||
| 163 | c->x86_num_cores = num_cpu_cores(c); | 160 | c->x86_num_cores = num_cpu_cores(c); |
| 164 | 161 | ||
| 165 | detect_ht(c); | 162 | detect_ht(c); |
| 166 | 163 | ||
| 167 | /* Work around errata */ | 164 | /* Work around errata */ |
| 168 | Intel_errata_workarounds(c); | 165 | Intel_errata_workarounds(c); |
| 169 | 166 | ||
| 170 | #ifdef CONFIG_X86_INTEL_USERCOPY | 167 | #ifdef CONFIG_X86_INTEL_USERCOPY |
| 171 | /* | 168 | /* |
| 172 | * Set up the preferred alignment for movsl bulk memory moves | 169 | * Set up the preferred alignment for movsl bulk memory moves |
| 173 | */ | 170 | */ |
| 174 | switch (c->x86) { | 171 | switch (c->x86) { |
| 175 | case 4: /* 486: untested */ | 172 | case 4: /* 486: untested */ |
| 176 | break; | 173 | break; |
| 177 | case 5: /* Old Pentia: untested */ | 174 | case 5: /* Old Pentia: untested */ |
| 178 | break; | 175 | break; |
| 179 | case 6: /* PII/PIII only like movsl with 8-byte alignment */ | 176 | case 6: /* PII/PIII only like movsl with 8-byte alignment */ |
| 180 | movsl_mask.mask = 7; | 177 | movsl_mask.mask = 7; |
| 181 | break; | 178 | break; |
| 182 | case 15: /* P4 is OK down to 8-byte alignment */ | 179 | case 15: /* P4 is OK down to 8-byte alignment */ |
| 183 | movsl_mask.mask = 7; | 180 | movsl_mask.mask = 7; |
| 184 | break; | 181 | break; |
| 185 | } | 182 | } |
| 186 | #endif | 183 | #endif |
| 187 | 184 | ||
| 188 | if (c->x86 == 15) | 185 | if (c->x86 == 15) |
| 189 | set_bit(X86_FEATURE_P4, c->x86_capability); | 186 | set_bit(X86_FEATURE_P4, c->x86_capability); |
| 190 | if (c->x86 == 6) | 187 | if (c->x86 == 6) |
| 191 | set_bit(X86_FEATURE_P3, c->x86_capability); | 188 | set_bit(X86_FEATURE_P3, c->x86_capability); |
| 192 | } | 189 | } |
| 193 | 190 | ||
| 194 | 191 | ||
| 195 | static unsigned int intel_size_cache(struct cpuinfo_x86 * c, unsigned int size) | 192 | static unsigned int intel_size_cache(struct cpuinfo_x86 * c, unsigned int size) |
| 196 | { | 193 | { |
| 197 | /* Intel PIII Tualatin. This comes in two flavours. | 194 | /* Intel PIII Tualatin. This comes in two flavours. |
| 198 | * One has 256kb of cache, the other 512. We have no way | 195 | * One has 256kb of cache, the other 512. We have no way |
| 199 | * to determine which, so we use a boottime override | 196 | * to determine which, so we use a boottime override |
| 200 | * for the 512kb model, and assume 256 otherwise. | 197 | * for the 512kb model, and assume 256 otherwise. |
| 201 | */ | 198 | */ |
| 202 | if ((c->x86 == 6) && (c->x86_model == 11) && (size == 0)) | 199 | if ((c->x86 == 6) && (c->x86_model == 11) && (size == 0)) |
| 203 | size = 256; | 200 | size = 256; |
| 204 | return size; | 201 | return size; |
| 205 | } | 202 | } |
| 206 | 203 | ||
| 207 | static struct cpu_dev intel_cpu_dev __devinitdata = { | 204 | static struct cpu_dev intel_cpu_dev __devinitdata = { |
| 208 | .c_vendor = "Intel", | 205 | .c_vendor = "Intel", |
| 209 | .c_ident = { "GenuineIntel" }, | 206 | .c_ident = { "GenuineIntel" }, |
| 210 | .c_models = { | 207 | .c_models = { |
| 211 | { .vendor = X86_VENDOR_INTEL, .family = 4, .model_names = | 208 | { .vendor = X86_VENDOR_INTEL, .family = 4, .model_names = |
| 212 | { | 209 | { |
| 213 | [0] = "486 DX-25/33", | 210 | [0] = "486 DX-25/33", |
| 214 | [1] = "486 DX-50", | 211 | [1] = "486 DX-50", |
| 215 | [2] = "486 SX", | 212 | [2] = "486 SX", |
| 216 | [3] = "486 DX/2", | 213 | [3] = "486 DX/2", |
| 217 | [4] = "486 SL", | 214 | [4] = "486 SL", |
| 218 | [5] = "486 SX/2", | 215 | [5] = "486 SX/2", |
| 219 | [7] = "486 DX/2-WB", | 216 | [7] = "486 DX/2-WB", |
| 220 | [8] = "486 DX/4", | 217 | [8] = "486 DX/4", |
| 221 | [9] = "486 DX/4-WB" | 218 | [9] = "486 DX/4-WB" |
| 222 | } | 219 | } |
| 223 | }, | 220 | }, |
| 224 | { .vendor = X86_VENDOR_INTEL, .family = 5, .model_names = | 221 | { .vendor = X86_VENDOR_INTEL, .family = 5, .model_names = |
| 225 | { | 222 | { |
| 226 | [0] = "Pentium 60/66 A-step", | 223 | [0] = "Pentium 60/66 A-step", |
| 227 | [1] = "Pentium 60/66", | 224 | [1] = "Pentium 60/66", |
| 228 | [2] = "Pentium 75 - 200", | 225 | [2] = "Pentium 75 - 200", |
| 229 | [3] = "OverDrive PODP5V83", | 226 | [3] = "OverDrive PODP5V83", |
| 230 | [4] = "Pentium MMX", | 227 | [4] = "Pentium MMX", |
| 231 | [7] = "Mobile Pentium 75 - 200", | 228 | [7] = "Mobile Pentium 75 - 200", |
| 232 | [8] = "Mobile Pentium MMX" | 229 | [8] = "Mobile Pentium MMX" |
| 233 | } | 230 | } |
| 234 | }, | 231 | }, |
| 235 | { .vendor = X86_VENDOR_INTEL, .family = 6, .model_names = | 232 | { .vendor = X86_VENDOR_INTEL, .family = 6, .model_names = |
| 236 | { | 233 | { |
| 237 | [0] = "Pentium Pro A-step", | 234 | [0] = "Pentium Pro A-step", |
| 238 | [1] = "Pentium Pro", | 235 | [1] = "Pentium Pro", |
| 239 | [3] = "Pentium II (Klamath)", | 236 | [3] = "Pentium II (Klamath)", |
| 240 | [4] = "Pentium II (Deschutes)", | 237 | [4] = "Pentium II (Deschutes)", |
| 241 | [5] = "Pentium II (Deschutes)", | 238 | [5] = "Pentium II (Deschutes)", |
| 242 | [6] = "Mobile Pentium II", | 239 | [6] = "Mobile Pentium II", |
| 243 | [7] = "Pentium III (Katmai)", | 240 | [7] = "Pentium III (Katmai)", |
| 244 | [8] = "Pentium III (Coppermine)", | 241 | [8] = "Pentium III (Coppermine)", |
| 245 | [10] = "Pentium III (Cascades)", | 242 | [10] = "Pentium III (Cascades)", |
| 246 | [11] = "Pentium III (Tualatin)", | 243 | [11] = "Pentium III (Tualatin)", |
| 247 | } | 244 | } |
| 248 | }, | 245 | }, |
| 249 | { .vendor = X86_VENDOR_INTEL, .family = 15, .model_names = | 246 | { .vendor = X86_VENDOR_INTEL, .family = 15, .model_names = |
| 250 | { | 247 | { |
| 251 | [0] = "Pentium 4 (Unknown)", | 248 | [0] = "Pentium 4 (Unknown)", |
| 252 | [1] = "Pentium 4 (Willamette)", | 249 | [1] = "Pentium 4 (Willamette)", |
| 253 | [2] = "Pentium 4 (Northwood)", | 250 | [2] = "Pentium 4 (Northwood)", |
| 254 | [4] = "Pentium 4 (Foster)", | 251 | [4] = "Pentium 4 (Foster)", |
| 255 | [5] = "Pentium 4 (Foster)", | 252 | [5] = "Pentium 4 (Foster)", |
| 256 | } | 253 | } |
| 257 | }, | 254 | }, |
| 258 | }, | 255 | }, |
| 259 | .c_init = init_intel, | 256 | .c_init = init_intel, |
| 260 | .c_identify = generic_identify, | 257 | .c_identify = generic_identify, |
| 261 | .c_size_cache = intel_size_cache, | 258 | .c_size_cache = intel_size_cache, |
| 262 | }; | 259 | }; |
| 263 | 260 | ||
| 264 | __init int intel_cpu_init(void) | 261 | __init int intel_cpu_init(void) |
| 265 | { | 262 | { |
| 266 | cpu_devs[X86_VENDOR_INTEL] = &intel_cpu_dev; | 263 | cpu_devs[X86_VENDOR_INTEL] = &intel_cpu_dev; |
| 267 | return 0; | 264 | return 0; |
| 268 | } | 265 | } |
| 269 | 266 | ||
| 270 | // arch_initcall(intel_cpu_init); | 267 | // arch_initcall(intel_cpu_init); |
| 271 | 268 | ||
| 272 | 269 |
arch/i386/kernel/crash.c
| 1 | /* | 1 | /* |
| 2 | * Architecture specific (i386) functions for kexec based crash dumps. | 2 | * Architecture specific (i386) functions for kexec based crash dumps. |
| 3 | * | 3 | * |
| 4 | * Created by: Hariprasad Nellitheertha (hari@in.ibm.com) | 4 | * Created by: Hariprasad Nellitheertha (hari@in.ibm.com) |
| 5 | * | 5 | * |
| 6 | * Copyright (C) IBM Corporation, 2004. All rights reserved. | 6 | * Copyright (C) IBM Corporation, 2004. All rights reserved. |
| 7 | * | 7 | * |
| 8 | */ | 8 | */ |
| 9 | 9 | ||
| 10 | #include <linux/init.h> | 10 | #include <linux/init.h> |
| 11 | #include <linux/types.h> | 11 | #include <linux/types.h> |
| 12 | #include <linux/kernel.h> | 12 | #include <linux/kernel.h> |
| 13 | #include <linux/smp.h> | 13 | #include <linux/smp.h> |
| 14 | #include <linux/irq.h> | 14 | #include <linux/irq.h> |
| 15 | #include <linux/reboot.h> | 15 | #include <linux/reboot.h> |
| 16 | #include <linux/kexec.h> | 16 | #include <linux/kexec.h> |
| 17 | #include <linux/irq.h> | 17 | #include <linux/irq.h> |
| 18 | #include <linux/delay.h> | 18 | #include <linux/delay.h> |
| 19 | #include <linux/elf.h> | 19 | #include <linux/elf.h> |
| 20 | #include <linux/elfcore.h> | 20 | #include <linux/elfcore.h> |
| 21 | 21 | ||
| 22 | #include <asm/processor.h> | 22 | #include <asm/processor.h> |
| 23 | #include <asm/hardirq.h> | 23 | #include <asm/hardirq.h> |
| 24 | #include <asm/nmi.h> | 24 | #include <asm/nmi.h> |
| 25 | #include <asm/hw_irq.h> | 25 | #include <asm/hw_irq.h> |
| 26 | #include <asm/apic.h> | 26 | #include <asm/apic.h> |
| 27 | #include <mach_ipi.h> | 27 | #include <mach_ipi.h> |
| 28 | 28 | ||
| 29 | 29 | ||
| 30 | note_buf_t crash_notes[NR_CPUS]; | 30 | note_buf_t crash_notes[NR_CPUS]; |
| 31 | /* This keeps a track of which one is crashing cpu. */ | 31 | /* This keeps a track of which one is crashing cpu. */ |
| 32 | static int crashing_cpu; | 32 | static int crashing_cpu; |
| 33 | 33 | ||
| 34 | static u32 *append_elf_note(u32 *buf, char *name, unsigned type, void *data, | 34 | static u32 *append_elf_note(u32 *buf, char *name, unsigned type, void *data, |
| 35 | size_t data_len) | 35 | size_t data_len) |
| 36 | { | 36 | { |
| 37 | struct elf_note note; | 37 | struct elf_note note; |
| 38 | 38 | ||
| 39 | note.n_namesz = strlen(name) + 1; | 39 | note.n_namesz = strlen(name) + 1; |
| 40 | note.n_descsz = data_len; | 40 | note.n_descsz = data_len; |
| 41 | note.n_type = type; | 41 | note.n_type = type; |
| 42 | memcpy(buf, ¬e, sizeof(note)); | 42 | memcpy(buf, ¬e, sizeof(note)); |
| 43 | buf += (sizeof(note) +3)/4; | 43 | buf += (sizeof(note) +3)/4; |
| 44 | memcpy(buf, name, note.n_namesz); | 44 | memcpy(buf, name, note.n_namesz); |
| 45 | buf += (note.n_namesz + 3)/4; | 45 | buf += (note.n_namesz + 3)/4; |
| 46 | memcpy(buf, data, note.n_descsz); | 46 | memcpy(buf, data, note.n_descsz); |
| 47 | buf += (note.n_descsz + 3)/4; | 47 | buf += (note.n_descsz + 3)/4; |
| 48 | 48 | ||
| 49 | return buf; | 49 | return buf; |
| 50 | } | 50 | } |
| 51 | 51 | ||
| 52 | static void final_note(u32 *buf) | 52 | static void final_note(u32 *buf) |
| 53 | { | 53 | { |
| 54 | struct elf_note note; | 54 | struct elf_note note; |
| 55 | 55 | ||
| 56 | note.n_namesz = 0; | 56 | note.n_namesz = 0; |
| 57 | note.n_descsz = 0; | 57 | note.n_descsz = 0; |
| 58 | note.n_type = 0; | 58 | note.n_type = 0; |
| 59 | memcpy(buf, ¬e, sizeof(note)); | 59 | memcpy(buf, ¬e, sizeof(note)); |
| 60 | } | 60 | } |
| 61 | 61 | ||
| 62 | static void crash_save_this_cpu(struct pt_regs *regs, int cpu) | 62 | static void crash_save_this_cpu(struct pt_regs *regs, int cpu) |
| 63 | { | 63 | { |
| 64 | struct elf_prstatus prstatus; | 64 | struct elf_prstatus prstatus; |
| 65 | u32 *buf; | 65 | u32 *buf; |
| 66 | 66 | ||
| 67 | if ((cpu < 0) || (cpu >= NR_CPUS)) | 67 | if ((cpu < 0) || (cpu >= NR_CPUS)) |
| 68 | return; | 68 | return; |
| 69 | 69 | ||
| 70 | /* Using ELF notes here is opportunistic. | 70 | /* Using ELF notes here is opportunistic. |
| 71 | * I need a well defined structure format | 71 | * I need a well defined structure format |
| 72 | * for the data I pass, and I need tags | 72 | * for the data I pass, and I need tags |
| 73 | * on the data to indicate what information I have | 73 | * on the data to indicate what information I have |
| 74 | * squirrelled away. ELF notes happen to provide | 74 | * squirrelled away. ELF notes happen to provide |
| 75 | * all of that that no need to invent something new. | 75 | * all of that that no need to invent something new. |
| 76 | */ | 76 | */ |
| 77 | buf = &crash_notes[cpu][0]; | 77 | buf = &crash_notes[cpu][0]; |
| 78 | memset(&prstatus, 0, sizeof(prstatus)); | 78 | memset(&prstatus, 0, sizeof(prstatus)); |
| 79 | prstatus.pr_pid = current->pid; | 79 | prstatus.pr_pid = current->pid; |
| 80 | elf_core_copy_regs(&prstatus.pr_reg, regs); | 80 | elf_core_copy_regs(&prstatus.pr_reg, regs); |
| 81 | buf = append_elf_note(buf, "CORE", NT_PRSTATUS, &prstatus, | 81 | buf = append_elf_note(buf, "CORE", NT_PRSTATUS, &prstatus, |
| 82 | sizeof(prstatus)); | 82 | sizeof(prstatus)); |
| 83 | final_note(buf); | 83 | final_note(buf); |
| 84 | } | 84 | } |
| 85 | 85 | ||
| 86 | static void crash_get_current_regs(struct pt_regs *regs) | 86 | static void crash_get_current_regs(struct pt_regs *regs) |
| 87 | { | 87 | { |
| 88 | __asm__ __volatile__("movl %%ebx,%0" : "=m"(regs->ebx)); | 88 | __asm__ __volatile__("movl %%ebx,%0" : "=m"(regs->ebx)); |
| 89 | __asm__ __volatile__("movl %%ecx,%0" : "=m"(regs->ecx)); | 89 | __asm__ __volatile__("movl %%ecx,%0" : "=m"(regs->ecx)); |
| 90 | __asm__ __volatile__("movl %%edx,%0" : "=m"(regs->edx)); | 90 | __asm__ __volatile__("movl %%edx,%0" : "=m"(regs->edx)); |
| 91 | __asm__ __volatile__("movl %%esi,%0" : "=m"(regs->esi)); | 91 | __asm__ __volatile__("movl %%esi,%0" : "=m"(regs->esi)); |
| 92 | __asm__ __volatile__("movl %%edi,%0" : "=m"(regs->edi)); | 92 | __asm__ __volatile__("movl %%edi,%0" : "=m"(regs->edi)); |
| 93 | __asm__ __volatile__("movl %%ebp,%0" : "=m"(regs->ebp)); | 93 | __asm__ __volatile__("movl %%ebp,%0" : "=m"(regs->ebp)); |
| 94 | __asm__ __volatile__("movl %%eax,%0" : "=m"(regs->eax)); | 94 | __asm__ __volatile__("movl %%eax,%0" : "=m"(regs->eax)); |
| 95 | __asm__ __volatile__("movl %%esp,%0" : "=m"(regs->esp)); | 95 | __asm__ __volatile__("movl %%esp,%0" : "=m"(regs->esp)); |
| 96 | __asm__ __volatile__("movw %%ss, %%ax;" :"=a"(regs->xss)); | 96 | __asm__ __volatile__("movw %%ss, %%ax;" :"=a"(regs->xss)); |
| 97 | __asm__ __volatile__("movw %%cs, %%ax;" :"=a"(regs->xcs)); | 97 | __asm__ __volatile__("movw %%cs, %%ax;" :"=a"(regs->xcs)); |
| 98 | __asm__ __volatile__("movw %%ds, %%ax;" :"=a"(regs->xds)); | 98 | __asm__ __volatile__("movw %%ds, %%ax;" :"=a"(regs->xds)); |
| 99 | __asm__ __volatile__("movw %%es, %%ax;" :"=a"(regs->xes)); | 99 | __asm__ __volatile__("movw %%es, %%ax;" :"=a"(regs->xes)); |
| 100 | __asm__ __volatile__("pushfl; popl %0" :"=m"(regs->eflags)); | 100 | __asm__ __volatile__("pushfl; popl %0" :"=m"(regs->eflags)); |
| 101 | 101 | ||
| 102 | regs->eip = (unsigned long)current_text_addr(); | 102 | regs->eip = (unsigned long)current_text_addr(); |
| 103 | } | 103 | } |
| 104 | 104 | ||
| 105 | /* CPU does not save ss and esp on stack if execution is already | 105 | /* CPU does not save ss and esp on stack if execution is already |
| 106 | * running in kernel mode at the time of NMI occurrence. This code | 106 | * running in kernel mode at the time of NMI occurrence. This code |
| 107 | * fixes it. | 107 | * fixes it. |
| 108 | */ | 108 | */ |
| 109 | static void crash_setup_regs(struct pt_regs *newregs, struct pt_regs *oldregs) | 109 | static void crash_setup_regs(struct pt_regs *newregs, struct pt_regs *oldregs) |
| 110 | { | 110 | { |
| 111 | memcpy(newregs, oldregs, sizeof(*newregs)); | 111 | memcpy(newregs, oldregs, sizeof(*newregs)); |
| 112 | newregs->esp = (unsigned long)&(oldregs->esp); | 112 | newregs->esp = (unsigned long)&(oldregs->esp); |
| 113 | __asm__ __volatile__("xorl %eax, %eax;"); | 113 | __asm__ __volatile__("xorl %eax, %eax;"); |
| 114 | __asm__ __volatile__ ("movw %%ss, %%ax;" :"=a"(newregs->xss)); | 114 | __asm__ __volatile__ ("movw %%ss, %%ax;" :"=a"(newregs->xss)); |
| 115 | } | 115 | } |
| 116 | 116 | ||
| 117 | /* We may have saved_regs from where the error came from | 117 | /* We may have saved_regs from where the error came from |
| 118 | * or it is NULL if via a direct panic(). | 118 | * or it is NULL if via a direct panic(). |
| 119 | */ | 119 | */ |
| 120 | static void crash_save_self(struct pt_regs *saved_regs) | 120 | static void crash_save_self(struct pt_regs *saved_regs) |
| 121 | { | 121 | { |
| 122 | struct pt_regs regs; | 122 | struct pt_regs regs; |
| 123 | int cpu; | 123 | int cpu; |
| 124 | 124 | ||
| 125 | cpu = smp_processor_id(); | 125 | cpu = smp_processor_id(); |
| 126 | if (saved_regs) | 126 | if (saved_regs) |
| 127 | crash_setup_regs(®s, saved_regs); | 127 | crash_setup_regs(®s, saved_regs); |
| 128 | else | 128 | else |
| 129 | crash_get_current_regs(®s); | 129 | crash_get_current_regs(®s); |
| 130 | crash_save_this_cpu(®s, cpu); | 130 | crash_save_this_cpu(®s, cpu); |
| 131 | } | 131 | } |
| 132 | 132 | ||
| 133 | #ifdef CONFIG_SMP | 133 | #ifdef CONFIG_SMP |
| 134 | static atomic_t waiting_for_crash_ipi; | 134 | static atomic_t waiting_for_crash_ipi; |
| 135 | 135 | ||
| 136 | static int crash_nmi_callback(struct pt_regs *regs, int cpu) | 136 | static int crash_nmi_callback(struct pt_regs *regs, int cpu) |
| 137 | { | 137 | { |
| 138 | struct pt_regs fixed_regs; | 138 | struct pt_regs fixed_regs; |
| 139 | 139 | ||
| 140 | /* Don't do anything if this handler is invoked on crashing cpu. | 140 | /* Don't do anything if this handler is invoked on crashing cpu. |
| 141 | * Otherwise, system will completely hang. Crashing cpu can get | 141 | * Otherwise, system will completely hang. Crashing cpu can get |
| 142 | * an NMI if system was initially booted with nmi_watchdog parameter. | 142 | * an NMI if system was initially booted with nmi_watchdog parameter. |
| 143 | */ | 143 | */ |
| 144 | if (cpu == crashing_cpu) | 144 | if (cpu == crashing_cpu) |
| 145 | return 1; | 145 | return 1; |
| 146 | local_irq_disable(); | 146 | local_irq_disable(); |
| 147 | 147 | ||
| 148 | if (!user_mode(regs)) { | 148 | if (!user_mode(regs)) { |
| 149 | crash_setup_regs(&fixed_regs, regs); | 149 | crash_setup_regs(&fixed_regs, regs); |
| 150 | regs = &fixed_regs; | 150 | regs = &fixed_regs; |
| 151 | } | 151 | } |
| 152 | crash_save_this_cpu(regs, cpu); | 152 | crash_save_this_cpu(regs, cpu); |
| 153 | disable_local_APIC(); | 153 | disable_local_APIC(); |
| 154 | atomic_dec(&waiting_for_crash_ipi); | 154 | atomic_dec(&waiting_for_crash_ipi); |
| 155 | /* Assume hlt works */ | 155 | /* Assume hlt works */ |
| 156 | __asm__("hlt"); | 156 | halt(); |
| 157 | for(;;); | 157 | for(;;); |
| 158 | 158 | ||
| 159 | return 1; | 159 | return 1; |
| 160 | } | 160 | } |
| 161 | 161 | ||
| 162 | /* | 162 | /* |
| 163 | * By using the NMI code instead of a vector we just sneak thru the | 163 | * By using the NMI code instead of a vector we just sneak thru the |
| 164 | * word generator coming out with just what we want. AND it does | 164 | * word generator coming out with just what we want. AND it does |
| 165 | * not matter if clustered_apic_mode is set or not. | 165 | * not matter if clustered_apic_mode is set or not. |
| 166 | */ | 166 | */ |
| 167 | static void smp_send_nmi_allbutself(void) | 167 | static void smp_send_nmi_allbutself(void) |
| 168 | { | 168 | { |
| 169 | send_IPI_allbutself(APIC_DM_NMI); | 169 | send_IPI_allbutself(APIC_DM_NMI); |
| 170 | } | 170 | } |
| 171 | 171 | ||
| 172 | static void nmi_shootdown_cpus(void) | 172 | static void nmi_shootdown_cpus(void) |
| 173 | { | 173 | { |
| 174 | unsigned long msecs; | 174 | unsigned long msecs; |
| 175 | 175 | ||
| 176 | atomic_set(&waiting_for_crash_ipi, num_online_cpus() - 1); | 176 | atomic_set(&waiting_for_crash_ipi, num_online_cpus() - 1); |
| 177 | /* Would it be better to replace the trap vector here? */ | 177 | /* Would it be better to replace the trap vector here? */ |
| 178 | set_nmi_callback(crash_nmi_callback); | 178 | set_nmi_callback(crash_nmi_callback); |
| 179 | /* Ensure the new callback function is set before sending | 179 | /* Ensure the new callback function is set before sending |
| 180 | * out the NMI | 180 | * out the NMI |
| 181 | */ | 181 | */ |
| 182 | wmb(); | 182 | wmb(); |
| 183 | 183 | ||
| 184 | smp_send_nmi_allbutself(); | 184 | smp_send_nmi_allbutself(); |
| 185 | 185 | ||
| 186 | msecs = 1000; /* Wait at most a second for the other cpus to stop */ | 186 | msecs = 1000; /* Wait at most a second for the other cpus to stop */ |
| 187 | while ((atomic_read(&waiting_for_crash_ipi) > 0) && msecs) { | 187 | while ((atomic_read(&waiting_for_crash_ipi) > 0) && msecs) { |
| 188 | mdelay(1); | 188 | mdelay(1); |
| 189 | msecs--; | 189 | msecs--; |
| 190 | } | 190 | } |
| 191 | 191 | ||
| 192 | /* Leave the nmi callback set */ | 192 | /* Leave the nmi callback set */ |
| 193 | disable_local_APIC(); | 193 | disable_local_APIC(); |
| 194 | } | 194 | } |
| 195 | #else | 195 | #else |
| 196 | static void nmi_shootdown_cpus(void) | 196 | static void nmi_shootdown_cpus(void) |
| 197 | { | 197 | { |
| 198 | /* There are no cpus to shootdown */ | 198 | /* There are no cpus to shootdown */ |
| 199 | } | 199 | } |
| 200 | #endif | 200 | #endif |
| 201 | 201 | ||
| 202 | void machine_crash_shutdown(struct pt_regs *regs) | 202 | void machine_crash_shutdown(struct pt_regs *regs) |
| 203 | { | 203 | { |
| 204 | /* This function is only called after the system | 204 | /* This function is only called after the system |
| 205 | * has paniced or is otherwise in a critical state. | 205 | * has paniced or is otherwise in a critical state. |
| 206 | * The minimum amount of code to allow a kexec'd kernel | 206 | * The minimum amount of code to allow a kexec'd kernel |
| 207 | * to run successfully needs to happen here. | 207 | * to run successfully needs to happen here. |
| 208 | * | 208 | * |
| 209 | * In practice this means shooting down the other cpus in | 209 | * In practice this means shooting down the other cpus in |
| 210 | * an SMP system. | 210 | * an SMP system. |
| 211 | */ | 211 | */ |
| 212 | /* The kernel is broken so disable interrupts */ | 212 | /* The kernel is broken so disable interrupts */ |
| 213 | local_irq_disable(); | 213 | local_irq_disable(); |
| 214 | 214 | ||
| 215 | /* Make a note of crashing cpu. Will be used in NMI callback.*/ | 215 | /* Make a note of crashing cpu. Will be used in NMI callback.*/ |
| 216 | crashing_cpu = smp_processor_id(); | 216 | crashing_cpu = smp_processor_id(); |
| 217 | nmi_shootdown_cpus(); | 217 | nmi_shootdown_cpus(); |
| 218 | lapic_shutdown(); | 218 | lapic_shutdown(); |
| 219 | #if defined(CONFIG_X86_IO_APIC) | 219 | #if defined(CONFIG_X86_IO_APIC) |
| 220 | disable_IO_APIC(); | 220 | disable_IO_APIC(); |
| 221 | #endif | 221 | #endif |
| 222 | crash_save_self(regs); | 222 | crash_save_self(regs); |
| 223 | } | 223 | } |
| 224 | 224 |
arch/i386/kernel/machine_kexec.c
| 1 | /* | 1 | /* |
| 2 | * machine_kexec.c - handle transition of Linux booting another kernel | 2 | * machine_kexec.c - handle transition of Linux booting another kernel |
| 3 | * Copyright (C) 2002-2005 Eric Biederman <ebiederm@xmission.com> | 3 | * Copyright (C) 2002-2005 Eric Biederman <ebiederm@xmission.com> |
| 4 | * | 4 | * |
| 5 | * This source code is licensed under the GNU General Public License, | 5 | * This source code is licensed under the GNU General Public License, |
| 6 | * Version 2. See the file COPYING for more details. | 6 | * Version 2. See the file COPYING for more details. |
| 7 | */ | 7 | */ |
| 8 | 8 | ||
| 9 | #include <linux/mm.h> | 9 | #include <linux/mm.h> |
| 10 | #include <linux/kexec.h> | 10 | #include <linux/kexec.h> |
| 11 | #include <linux/delay.h> | 11 | #include <linux/delay.h> |
| 12 | #include <asm/pgtable.h> | 12 | #include <asm/pgtable.h> |
| 13 | #include <asm/pgalloc.h> | 13 | #include <asm/pgalloc.h> |
| 14 | #include <asm/tlbflush.h> | 14 | #include <asm/tlbflush.h> |
| 15 | #include <asm/mmu_context.h> | 15 | #include <asm/mmu_context.h> |
| 16 | #include <asm/io.h> | 16 | #include <asm/io.h> |
| 17 | #include <asm/apic.h> | 17 | #include <asm/apic.h> |
| 18 | #include <asm/cpufeature.h> | 18 | #include <asm/cpufeature.h> |
| 19 | #include <asm/desc.h> | 19 | #include <asm/desc.h> |
| 20 | #include <asm/system.h> | 20 | #include <asm/system.h> |
| 21 | 21 | ||
| 22 | #define PAGE_ALIGNED __attribute__ ((__aligned__(PAGE_SIZE))) | 22 | #define PAGE_ALIGNED __attribute__ ((__aligned__(PAGE_SIZE))) |
| 23 | 23 | ||
| 24 | #define L0_ATTR (_PAGE_PRESENT | _PAGE_RW | _PAGE_ACCESSED | _PAGE_DIRTY) | 24 | #define L0_ATTR (_PAGE_PRESENT | _PAGE_RW | _PAGE_ACCESSED | _PAGE_DIRTY) |
| 25 | #define L1_ATTR (_PAGE_PRESENT | _PAGE_RW | _PAGE_ACCESSED | _PAGE_DIRTY) | 25 | #define L1_ATTR (_PAGE_PRESENT | _PAGE_RW | _PAGE_ACCESSED | _PAGE_DIRTY) |
| 26 | #define L2_ATTR (_PAGE_PRESENT) | 26 | #define L2_ATTR (_PAGE_PRESENT) |
| 27 | 27 | ||
| 28 | #define LEVEL0_SIZE (1UL << 12UL) | 28 | #define LEVEL0_SIZE (1UL << 12UL) |
| 29 | 29 | ||
| 30 | #ifndef CONFIG_X86_PAE | 30 | #ifndef CONFIG_X86_PAE |
| 31 | #define LEVEL1_SIZE (1UL << 22UL) | 31 | #define LEVEL1_SIZE (1UL << 22UL) |
| 32 | static u32 pgtable_level1[1024] PAGE_ALIGNED; | 32 | static u32 pgtable_level1[1024] PAGE_ALIGNED; |
| 33 | 33 | ||
| 34 | static void identity_map_page(unsigned long address) | 34 | static void identity_map_page(unsigned long address) |
| 35 | { | 35 | { |
| 36 | unsigned long level1_index, level2_index; | 36 | unsigned long level1_index, level2_index; |
| 37 | u32 *pgtable_level2; | 37 | u32 *pgtable_level2; |
| 38 | 38 | ||
| 39 | /* Find the current page table */ | 39 | /* Find the current page table */ |
| 40 | pgtable_level2 = __va(read_cr3()); | 40 | pgtable_level2 = __va(read_cr3()); |
| 41 | 41 | ||
| 42 | /* Find the indexes of the physical address to identity map */ | 42 | /* Find the indexes of the physical address to identity map */ |
| 43 | level1_index = (address % LEVEL1_SIZE)/LEVEL0_SIZE; | 43 | level1_index = (address % LEVEL1_SIZE)/LEVEL0_SIZE; |
| 44 | level2_index = address / LEVEL1_SIZE; | 44 | level2_index = address / LEVEL1_SIZE; |
| 45 | 45 | ||
| 46 | /* Identity map the page table entry */ | 46 | /* Identity map the page table entry */ |
| 47 | pgtable_level1[level1_index] = address | L0_ATTR; | 47 | pgtable_level1[level1_index] = address | L0_ATTR; |
| 48 | pgtable_level2[level2_index] = __pa(pgtable_level1) | L1_ATTR; | 48 | pgtable_level2[level2_index] = __pa(pgtable_level1) | L1_ATTR; |
| 49 | 49 | ||
| 50 | /* Flush the tlb so the new mapping takes effect. | 50 | /* Flush the tlb so the new mapping takes effect. |
| 51 | * Global tlb entries are not flushed but that is not an issue. | 51 | * Global tlb entries are not flushed but that is not an issue. |
| 52 | */ | 52 | */ |
| 53 | load_cr3(pgtable_level2); | 53 | load_cr3(pgtable_level2); |
| 54 | } | 54 | } |
| 55 | 55 | ||
| 56 | #else | 56 | #else |
| 57 | #define LEVEL1_SIZE (1UL << 21UL) | 57 | #define LEVEL1_SIZE (1UL << 21UL) |
| 58 | #define LEVEL2_SIZE (1UL << 30UL) | 58 | #define LEVEL2_SIZE (1UL << 30UL) |
| 59 | static u64 pgtable_level1[512] PAGE_ALIGNED; | 59 | static u64 pgtable_level1[512] PAGE_ALIGNED; |
| 60 | static u64 pgtable_level2[512] PAGE_ALIGNED; | 60 | static u64 pgtable_level2[512] PAGE_ALIGNED; |
| 61 | 61 | ||
| 62 | static void identity_map_page(unsigned long address) | 62 | static void identity_map_page(unsigned long address) |
| 63 | { | 63 | { |
| 64 | unsigned long level1_index, level2_index, level3_index; | 64 | unsigned long level1_index, level2_index, level3_index; |
| 65 | u64 *pgtable_level3; | 65 | u64 *pgtable_level3; |
| 66 | 66 | ||
| 67 | /* Find the current page table */ | 67 | /* Find the current page table */ |
| 68 | pgtable_level3 = __va(read_cr3()); | 68 | pgtable_level3 = __va(read_cr3()); |
| 69 | 69 | ||
| 70 | /* Find the indexes of the physical address to identity map */ | 70 | /* Find the indexes of the physical address to identity map */ |
| 71 | level1_index = (address % LEVEL1_SIZE)/LEVEL0_SIZE; | 71 | level1_index = (address % LEVEL1_SIZE)/LEVEL0_SIZE; |
| 72 | level2_index = (address % LEVEL2_SIZE)/LEVEL1_SIZE; | 72 | level2_index = (address % LEVEL2_SIZE)/LEVEL1_SIZE; |
| 73 | level3_index = address / LEVEL2_SIZE; | 73 | level3_index = address / LEVEL2_SIZE; |
| 74 | 74 | ||
| 75 | /* Identity map the page table entry */ | 75 | /* Identity map the page table entry */ |
| 76 | pgtable_level1[level1_index] = address | L0_ATTR; | 76 | pgtable_level1[level1_index] = address | L0_ATTR; |
| 77 | pgtable_level2[level2_index] = __pa(pgtable_level1) | L1_ATTR; | 77 | pgtable_level2[level2_index] = __pa(pgtable_level1) | L1_ATTR; |
| 78 | set_64bit(&pgtable_level3[level3_index], | 78 | set_64bit(&pgtable_level3[level3_index], |
| 79 | __pa(pgtable_level2) | L2_ATTR); | 79 | __pa(pgtable_level2) | L2_ATTR); |
| 80 | 80 | ||
| 81 | /* Flush the tlb so the new mapping takes effect. | 81 | /* Flush the tlb so the new mapping takes effect. |
| 82 | * Global tlb entries are not flushed but that is not an issue. | 82 | * Global tlb entries are not flushed but that is not an issue. |
| 83 | */ | 83 | */ |
| 84 | load_cr3(pgtable_level3); | 84 | load_cr3(pgtable_level3); |
| 85 | } | 85 | } |
| 86 | #endif | 86 | #endif |
| 87 | 87 | ||
| 88 | static void set_idt(void *newidt, __u16 limit) | 88 | static void set_idt(void *newidt, __u16 limit) |
| 89 | { | 89 | { |
| 90 | struct Xgt_desc_struct curidt; | 90 | struct Xgt_desc_struct curidt; |
| 91 | 91 | ||
| 92 | /* ia32 supports unaliged loads & stores */ | 92 | /* ia32 supports unaliged loads & stores */ |
| 93 | curidt.size = limit; | 93 | curidt.size = limit; |
| 94 | curidt.address = (unsigned long)newidt; | 94 | curidt.address = (unsigned long)newidt; |
| 95 | 95 | ||
| 96 | __asm__ __volatile__ ( | 96 | load_idt(&curidt); |
| 97 | "lidtl %0\n" | ||
| 98 | : : "m" (curidt) | ||
| 99 | ); | ||
| 100 | }; | 97 | }; |
| 101 | 98 | ||
| 102 | 99 | ||
| 103 | static void set_gdt(void *newgdt, __u16 limit) | 100 | static void set_gdt(void *newgdt, __u16 limit) |
| 104 | { | 101 | { |
| 105 | struct Xgt_desc_struct curgdt; | 102 | struct Xgt_desc_struct curgdt; |
| 106 | 103 | ||
| 107 | /* ia32 supports unaligned loads & stores */ | 104 | /* ia32 supports unaligned loads & stores */ |
| 108 | curgdt.size = limit; | 105 | curgdt.size = limit; |
| 109 | curgdt.address = (unsigned long)newgdt; | 106 | curgdt.address = (unsigned long)newgdt; |
| 110 | 107 | ||
| 111 | __asm__ __volatile__ ( | 108 | load_gdt(&curgdt); |
| 112 | "lgdtl %0\n" | ||
| 113 | : : "m" (curgdt) | ||
| 114 | ); | ||
| 115 | }; | 109 | }; |
| 116 | 110 | ||
| 117 | static void load_segments(void) | 111 | static void load_segments(void) |
| 118 | { | 112 | { |
| 119 | #define __STR(X) #X | 113 | #define __STR(X) #X |
| 120 | #define STR(X) __STR(X) | 114 | #define STR(X) __STR(X) |
| 121 | 115 | ||
| 122 | __asm__ __volatile__ ( | 116 | __asm__ __volatile__ ( |
| 123 | "\tljmp $"STR(__KERNEL_CS)",$1f\n" | 117 | "\tljmp $"STR(__KERNEL_CS)",$1f\n" |
| 124 | "\t1:\n" | 118 | "\t1:\n" |
| 125 | "\tmovl $"STR(__KERNEL_DS)",%eax\n" | 119 | "\tmovl $"STR(__KERNEL_DS)",%eax\n" |
| 126 | "\tmovl %eax,%ds\n" | 120 | "\tmovl %eax,%ds\n" |
| 127 | "\tmovl %eax,%es\n" | 121 | "\tmovl %eax,%es\n" |
| 128 | "\tmovl %eax,%fs\n" | 122 | "\tmovl %eax,%fs\n" |
| 129 | "\tmovl %eax,%gs\n" | 123 | "\tmovl %eax,%gs\n" |
| 130 | "\tmovl %eax,%ss\n" | 124 | "\tmovl %eax,%ss\n" |
| 131 | ); | 125 | ); |
| 132 | #undef STR | 126 | #undef STR |
| 133 | #undef __STR | 127 | #undef __STR |
| 134 | } | 128 | } |
| 135 | 129 | ||
| 136 | typedef asmlinkage NORET_TYPE void (*relocate_new_kernel_t)( | 130 | typedef asmlinkage NORET_TYPE void (*relocate_new_kernel_t)( |
| 137 | unsigned long indirection_page, | 131 | unsigned long indirection_page, |
| 138 | unsigned long reboot_code_buffer, | 132 | unsigned long reboot_code_buffer, |
| 139 | unsigned long start_address, | 133 | unsigned long start_address, |
| 140 | unsigned int has_pae) ATTRIB_NORET; | 134 | unsigned int has_pae) ATTRIB_NORET; |
| 141 | 135 | ||
| 142 | const extern unsigned char relocate_new_kernel[]; | 136 | const extern unsigned char relocate_new_kernel[]; |
| 143 | extern void relocate_new_kernel_end(void); | 137 | extern void relocate_new_kernel_end(void); |
| 144 | const extern unsigned int relocate_new_kernel_size; | 138 | const extern unsigned int relocate_new_kernel_size; |
| 145 | 139 | ||
| 146 | /* | 140 | /* |
| 147 | * A architecture hook called to validate the | 141 | * A architecture hook called to validate the |
| 148 | * proposed image and prepare the control pages | 142 | * proposed image and prepare the control pages |
| 149 | * as needed. The pages for KEXEC_CONTROL_CODE_SIZE | 143 | * as needed. The pages for KEXEC_CONTROL_CODE_SIZE |
| 150 | * have been allocated, but the segments have yet | 144 | * have been allocated, but the segments have yet |
| 151 | * been copied into the kernel. | 145 | * been copied into the kernel. |
| 152 | * | 146 | * |
| 153 | * Do what every setup is needed on image and the | 147 | * Do what every setup is needed on image and the |
| 154 | * reboot code buffer to allow us to avoid allocations | 148 | * reboot code buffer to allow us to avoid allocations |
| 155 | * later. | 149 | * later. |
| 156 | * | 150 | * |
| 157 | * Currently nothing. | 151 | * Currently nothing. |
| 158 | */ | 152 | */ |
| 159 | int machine_kexec_prepare(struct kimage *image) | 153 | int machine_kexec_prepare(struct kimage *image) |
| 160 | { | 154 | { |
| 161 | return 0; | 155 | return 0; |
| 162 | } | 156 | } |
| 163 | 157 | ||
| 164 | /* | 158 | /* |
| 165 | * Undo anything leftover by machine_kexec_prepare | 159 | * Undo anything leftover by machine_kexec_prepare |
| 166 | * when an image is freed. | 160 | * when an image is freed. |
| 167 | */ | 161 | */ |
| 168 | void machine_kexec_cleanup(struct kimage *image) | 162 | void machine_kexec_cleanup(struct kimage *image) |
| 169 | { | 163 | { |
| 170 | } | 164 | } |
| 171 | 165 | ||
| 172 | /* | 166 | /* |
| 173 | * Do not allocate memory (or fail in any way) in machine_kexec(). | 167 | * Do not allocate memory (or fail in any way) in machine_kexec(). |
| 174 | * We are past the point of no return, committed to rebooting now. | 168 | * We are past the point of no return, committed to rebooting now. |
| 175 | */ | 169 | */ |
| 176 | NORET_TYPE void machine_kexec(struct kimage *image) | 170 | NORET_TYPE void machine_kexec(struct kimage *image) |
| 177 | { | 171 | { |
| 178 | unsigned long page_list; | 172 | unsigned long page_list; |
| 179 | unsigned long reboot_code_buffer; | 173 | unsigned long reboot_code_buffer; |
| 180 | 174 | ||
| 181 | relocate_new_kernel_t rnk; | 175 | relocate_new_kernel_t rnk; |
| 182 | 176 | ||
| 183 | /* Interrupts aren't acceptable while we reboot */ | 177 | /* Interrupts aren't acceptable while we reboot */ |
| 184 | local_irq_disable(); | 178 | local_irq_disable(); |
| 185 | 179 | ||
| 186 | /* Compute some offsets */ | 180 | /* Compute some offsets */ |
| 187 | reboot_code_buffer = page_to_pfn(image->control_code_page) | 181 | reboot_code_buffer = page_to_pfn(image->control_code_page) |
| 188 | << PAGE_SHIFT; | 182 | << PAGE_SHIFT; |
| 189 | page_list = image->head; | 183 | page_list = image->head; |
| 190 | 184 | ||
| 191 | /* Set up an identity mapping for the reboot_code_buffer */ | 185 | /* Set up an identity mapping for the reboot_code_buffer */ |
| 192 | identity_map_page(reboot_code_buffer); | 186 | identity_map_page(reboot_code_buffer); |
| 193 | 187 | ||
| 194 | /* copy it out */ | 188 | /* copy it out */ |
| 195 | memcpy((void *)reboot_code_buffer, relocate_new_kernel, | 189 | memcpy((void *)reboot_code_buffer, relocate_new_kernel, |
| 196 | relocate_new_kernel_size); | 190 | relocate_new_kernel_size); |
| 197 | 191 | ||
| 198 | /* The segment registers are funny things, they are | 192 | /* The segment registers are funny things, they are |
| 199 | * automatically loaded from a table, in memory wherever you | 193 | * automatically loaded from a table, in memory wherever you |
| 200 | * set them to a specific selector, but this table is never | 194 | * set them to a specific selector, but this table is never |
| 201 | * accessed again you set the segment to a different selector. | 195 | * accessed again you set the segment to a different selector. |
| 202 | * | 196 | * |
| 203 | * The more common model is are caches where the behide | 197 | * The more common model is are caches where the behide |
| 204 | * the scenes work is done, but is also dropped at arbitrary | 198 | * the scenes work is done, but is also dropped at arbitrary |
| 205 | * times. | 199 | * times. |
| 206 | * | 200 | * |
| 207 | * I take advantage of this here by force loading the | 201 | * I take advantage of this here by force loading the |
| 208 | * segments, before I zap the gdt with an invalid value. | 202 | * segments, before I zap the gdt with an invalid value. |
| 209 | */ | 203 | */ |
| 210 | load_segments(); | 204 | load_segments(); |
| 211 | /* The gdt & idt are now invalid. | 205 | /* The gdt & idt are now invalid. |
| 212 | * If you want to load them you must set up your own idt & gdt. | 206 | * If you want to load them you must set up your own idt & gdt. |
| 213 | */ | 207 | */ |
| 214 | set_gdt(phys_to_virt(0),0); | 208 | set_gdt(phys_to_virt(0),0); |
| 215 | set_idt(phys_to_virt(0),0); | 209 | set_idt(phys_to_virt(0),0); |
| 216 | 210 | ||
| 217 | /* now call it */ | 211 | /* now call it */ |
| 218 | rnk = (relocate_new_kernel_t) reboot_code_buffer; | 212 | rnk = (relocate_new_kernel_t) reboot_code_buffer; |
| 219 | (*rnk)(page_list, reboot_code_buffer, image->start, cpu_has_pae); | 213 | (*rnk)(page_list, reboot_code_buffer, image->start, cpu_has_pae); |
| 220 | } | 214 | } |
| 221 | 215 |
arch/i386/kernel/msr.c
| 1 | /* ----------------------------------------------------------------------- * | 1 | /* ----------------------------------------------------------------------- * |
| 2 | * | 2 | * |
| 3 | * Copyright 2000 H. Peter Anvin - All Rights Reserved | 3 | * Copyright 2000 H. Peter Anvin - All Rights Reserved |
| 4 | * | 4 | * |
| 5 | * This program is free software; you can redistribute it and/or modify | 5 | * This program is free software; you can redistribute it and/or modify |
| 6 | * it under the terms of the GNU General Public License as published by | 6 | * it under the terms of the GNU General Public License as published by |
| 7 | * the Free Software Foundation, Inc., 675 Mass Ave, Cambridge MA 02139, | 7 | * the Free Software Foundation, Inc., 675 Mass Ave, Cambridge MA 02139, |
| 8 | * USA; either version 2 of the License, or (at your option) any later | 8 | * USA; either version 2 of the License, or (at your option) any later |
| 9 | * version; incorporated herein by reference. | 9 | * version; incorporated herein by reference. |
| 10 | * | 10 | * |
| 11 | * ----------------------------------------------------------------------- */ | 11 | * ----------------------------------------------------------------------- */ |
| 12 | 12 | ||
| 13 | /* | 13 | /* |
| 14 | * msr.c | 14 | * msr.c |
| 15 | * | 15 | * |
| 16 | * x86 MSR access device | 16 | * x86 MSR access device |
| 17 | * | 17 | * |
| 18 | * This device is accessed by lseek() to the appropriate register number | 18 | * This device is accessed by lseek() to the appropriate register number |
| 19 | * and then read/write in chunks of 8 bytes. A larger size means multiple | 19 | * and then read/write in chunks of 8 bytes. A larger size means multiple |
| 20 | * reads or writes of the same register. | 20 | * reads or writes of the same register. |
| 21 | * | 21 | * |
| 22 | * This driver uses /dev/cpu/%d/msr where %d is the minor number, and on | 22 | * This driver uses /dev/cpu/%d/msr where %d is the minor number, and on |
| 23 | * an SMP box will direct the access to CPU %d. | 23 | * an SMP box will direct the access to CPU %d. |
| 24 | */ | 24 | */ |
| 25 | 25 | ||
| 26 | #include <linux/module.h> | 26 | #include <linux/module.h> |
| 27 | #include <linux/config.h> | 27 | #include <linux/config.h> |
| 28 | 28 | ||
| 29 | #include <linux/types.h> | 29 | #include <linux/types.h> |
| 30 | #include <linux/errno.h> | 30 | #include <linux/errno.h> |
| 31 | #include <linux/fcntl.h> | 31 | #include <linux/fcntl.h> |
| 32 | #include <linux/init.h> | 32 | #include <linux/init.h> |
| 33 | #include <linux/poll.h> | 33 | #include <linux/poll.h> |
| 34 | #include <linux/smp.h> | 34 | #include <linux/smp.h> |
| 35 | #include <linux/smp_lock.h> | 35 | #include <linux/smp_lock.h> |
| 36 | #include <linux/major.h> | 36 | #include <linux/major.h> |
| 37 | #include <linux/fs.h> | 37 | #include <linux/fs.h> |
| 38 | #include <linux/device.h> | 38 | #include <linux/device.h> |
| 39 | #include <linux/cpu.h> | 39 | #include <linux/cpu.h> |
| 40 | #include <linux/notifier.h> | 40 | #include <linux/notifier.h> |
| 41 | 41 | ||
| 42 | #include <asm/processor.h> | 42 | #include <asm/processor.h> |
| 43 | #include <asm/msr.h> | 43 | #include <asm/msr.h> |
| 44 | #include <asm/uaccess.h> | 44 | #include <asm/uaccess.h> |
| 45 | #include <asm/system.h> | 45 | #include <asm/system.h> |
| 46 | 46 | ||
| 47 | static struct class *msr_class; | 47 | static struct class *msr_class; |
| 48 | 48 | ||
| 49 | /* Note: "err" is handled in a funny way below. Otherwise one version | ||
| 50 | of gcc or another breaks. */ | ||
| 51 | |||
| 52 | static inline int wrmsr_eio(u32 reg, u32 eax, u32 edx) | 49 | static inline int wrmsr_eio(u32 reg, u32 eax, u32 edx) |
| 53 | { | 50 | { |
| 54 | int err; | 51 | int err; |
| 55 | 52 | ||
| 56 | asm volatile ("1: wrmsr\n" | 53 | err = wrmsr_safe(reg, eax, edx); |
| 57 | "2:\n" | 54 | if (err) |
| 58 | ".section .fixup,\"ax\"\n" | 55 | err = -EIO; |
| 59 | "3: movl %4,%0\n" | ||
| 60 | " jmp 2b\n" | ||
| 61 | ".previous\n" | ||
| 62 | ".section __ex_table,\"a\"\n" | ||
| 63 | " .align 4\n" " .long 1b,3b\n" ".previous":"=&bDS" (err) | ||
| 64 | :"a"(eax), "d"(edx), "c"(reg), "i"(-EIO), "0"(0)); | ||
| 65 | |||
| 66 | return err; | 56 | return err; |
| 67 | } | 57 | } |
| 68 | 58 | ||
| 69 | static inline int rdmsr_eio(u32 reg, u32 *eax, u32 *edx) | 59 | static inline int rdmsr_eio(u32 reg, u32 *eax, u32 *edx) |
| 70 | { | 60 | { |
| 71 | int err; | 61 | int err; |
| 72 | 62 | ||
| 73 | asm volatile ("1: rdmsr\n" | 63 | err = rdmsr_safe(reg, eax, edx); |
| 74 | "2:\n" | 64 | if (err) |
| 75 | ".section .fixup,\"ax\"\n" | 65 | err = -EIO; |
| 76 | "3: movl %4,%0\n" | ||
| 77 | " jmp 2b\n" | ||
| 78 | ".previous\n" | ||
| 79 | ".section __ex_table,\"a\"\n" | ||
| 80 | " .align 4\n" | ||
| 81 | " .long 1b,3b\n" | ||
| 82 | ".previous":"=&bDS" (err), "=a"(*eax), "=d"(*edx) | ||
| 83 | :"c"(reg), "i"(-EIO), "0"(0)); | ||
| 84 | |||
| 85 | return err; | 66 | return err; |
| 86 | } | 67 | } |
| 87 | 68 | ||
| 88 | #ifdef CONFIG_SMP | 69 | #ifdef CONFIG_SMP |
| 89 | 70 | ||
| 90 | struct msr_command { | 71 | struct msr_command { |
| 91 | int cpu; | 72 | int cpu; |
| 92 | int err; | 73 | int err; |
| 93 | u32 reg; | 74 | u32 reg; |
| 94 | u32 data[2]; | 75 | u32 data[2]; |
| 95 | }; | 76 | }; |
| 96 | 77 | ||
| 97 | static void msr_smp_wrmsr(void *cmd_block) | 78 | static void msr_smp_wrmsr(void *cmd_block) |
| 98 | { | 79 | { |
| 99 | struct msr_command *cmd = (struct msr_command *)cmd_block; | 80 | struct msr_command *cmd = (struct msr_command *)cmd_block; |
| 100 | 81 | ||
| 101 | if (cmd->cpu == smp_processor_id()) | 82 | if (cmd->cpu == smp_processor_id()) |
| 102 | cmd->err = wrmsr_eio(cmd->reg, cmd->data[0], cmd->data[1]); | 83 | cmd->err = wrmsr_eio(cmd->reg, cmd->data[0], cmd->data[1]); |
| 103 | } | 84 | } |
| 104 | 85 | ||
| 105 | static void msr_smp_rdmsr(void *cmd_block) | 86 | static void msr_smp_rdmsr(void *cmd_block) |
| 106 | { | 87 | { |
| 107 | struct msr_command *cmd = (struct msr_command *)cmd_block; | 88 | struct msr_command *cmd = (struct msr_command *)cmd_block; |
| 108 | 89 | ||
| 109 | if (cmd->cpu == smp_processor_id()) | 90 | if (cmd->cpu == smp_processor_id()) |
| 110 | cmd->err = rdmsr_eio(cmd->reg, &cmd->data[0], &cmd->data[1]); | 91 | cmd->err = rdmsr_eio(cmd->reg, &cmd->data[0], &cmd->data[1]); |
| 111 | } | 92 | } |
| 112 | 93 | ||
| 113 | static inline int do_wrmsr(int cpu, u32 reg, u32 eax, u32 edx) | 94 | static inline int do_wrmsr(int cpu, u32 reg, u32 eax, u32 edx) |
| 114 | { | 95 | { |
| 115 | struct msr_command cmd; | 96 | struct msr_command cmd; |
| 116 | int ret; | 97 | int ret; |
| 117 | 98 | ||
| 118 | preempt_disable(); | 99 | preempt_disable(); |
| 119 | if (cpu == smp_processor_id()) { | 100 | if (cpu == smp_processor_id()) { |
| 120 | ret = wrmsr_eio(reg, eax, edx); | 101 | ret = wrmsr_eio(reg, eax, edx); |
| 121 | } else { | 102 | } else { |
| 122 | cmd.cpu = cpu; | 103 | cmd.cpu = cpu; |
| 123 | cmd.reg = reg; | 104 | cmd.reg = reg; |
| 124 | cmd.data[0] = eax; | 105 | cmd.data[0] = eax; |
| 125 | cmd.data[1] = edx; | 106 | cmd.data[1] = edx; |
| 126 | 107 | ||
| 127 | smp_call_function(msr_smp_wrmsr, &cmd, 1, 1); | 108 | smp_call_function(msr_smp_wrmsr, &cmd, 1, 1); |
| 128 | ret = cmd.err; | 109 | ret = cmd.err; |
| 129 | } | 110 | } |
| 130 | preempt_enable(); | 111 | preempt_enable(); |
| 131 | return ret; | 112 | return ret; |
| 132 | } | 113 | } |
| 133 | 114 | ||
| 134 | static inline int do_rdmsr(int cpu, u32 reg, u32 * eax, u32 * edx) | 115 | static inline int do_rdmsr(int cpu, u32 reg, u32 * eax, u32 * edx) |
| 135 | { | 116 | { |
| 136 | struct msr_command cmd; | 117 | struct msr_command cmd; |
| 137 | int ret; | 118 | int ret; |
| 138 | 119 | ||
| 139 | preempt_disable(); | 120 | preempt_disable(); |
| 140 | if (cpu == smp_processor_id()) { | 121 | if (cpu == smp_processor_id()) { |
| 141 | ret = rdmsr_eio(reg, eax, edx); | 122 | ret = rdmsr_eio(reg, eax, edx); |
| 142 | } else { | 123 | } else { |
| 143 | cmd.cpu = cpu; | 124 | cmd.cpu = cpu; |
| 144 | cmd.reg = reg; | 125 | cmd.reg = reg; |
| 145 | 126 | ||
| 146 | smp_call_function(msr_smp_rdmsr, &cmd, 1, 1); | 127 | smp_call_function(msr_smp_rdmsr, &cmd, 1, 1); |
| 147 | 128 | ||
| 148 | *eax = cmd.data[0]; | 129 | *eax = cmd.data[0]; |
| 149 | *edx = cmd.data[1]; | 130 | *edx = cmd.data[1]; |
| 150 | 131 | ||
| 151 | ret = cmd.err; | 132 | ret = cmd.err; |
| 152 | } | 133 | } |
| 153 | preempt_enable(); | 134 | preempt_enable(); |
| 154 | return ret; | 135 | return ret; |
| 155 | } | 136 | } |
| 156 | 137 | ||
| 157 | #else /* ! CONFIG_SMP */ | 138 | #else /* ! CONFIG_SMP */ |
| 158 | 139 | ||
| 159 | static inline int do_wrmsr(int cpu, u32 reg, u32 eax, u32 edx) | 140 | static inline int do_wrmsr(int cpu, u32 reg, u32 eax, u32 edx) |
| 160 | { | 141 | { |
| 161 | return wrmsr_eio(reg, eax, edx); | 142 | return wrmsr_eio(reg, eax, edx); |
| 162 | } | 143 | } |
| 163 | 144 | ||
| 164 | static inline int do_rdmsr(int cpu, u32 reg, u32 *eax, u32 *edx) | 145 | static inline int do_rdmsr(int cpu, u32 reg, u32 *eax, u32 *edx) |
| 165 | { | 146 | { |
| 166 | return rdmsr_eio(reg, eax, edx); | 147 | return rdmsr_eio(reg, eax, edx); |
| 167 | } | 148 | } |
| 168 | 149 | ||
| 169 | #endif /* ! CONFIG_SMP */ | 150 | #endif /* ! CONFIG_SMP */ |
| 170 | 151 | ||
| 171 | static loff_t msr_seek(struct file *file, loff_t offset, int orig) | 152 | static loff_t msr_seek(struct file *file, loff_t offset, int orig) |
| 172 | { | 153 | { |
| 173 | loff_t ret = -EINVAL; | 154 | loff_t ret = -EINVAL; |
| 174 | 155 | ||
| 175 | lock_kernel(); | 156 | lock_kernel(); |
| 176 | switch (orig) { | 157 | switch (orig) { |
| 177 | case 0: | 158 | case 0: |
| 178 | file->f_pos = offset; | 159 | file->f_pos = offset; |
| 179 | ret = file->f_pos; | 160 | ret = file->f_pos; |
| 180 | break; | 161 | break; |
| 181 | case 1: | 162 | case 1: |
| 182 | file->f_pos += offset; | 163 | file->f_pos += offset; |
| 183 | ret = file->f_pos; | 164 | ret = file->f_pos; |
| 184 | } | 165 | } |
| 185 | unlock_kernel(); | 166 | unlock_kernel(); |
| 186 | return ret; | 167 | return ret; |
| 187 | } | 168 | } |
| 188 | 169 | ||
| 189 | static ssize_t msr_read(struct file *file, char __user * buf, | 170 | static ssize_t msr_read(struct file *file, char __user * buf, |
| 190 | size_t count, loff_t * ppos) | 171 | size_t count, loff_t * ppos) |
| 191 | { | 172 | { |
| 192 | u32 __user *tmp = (u32 __user *) buf; | 173 | u32 __user *tmp = (u32 __user *) buf; |
| 193 | u32 data[2]; | 174 | u32 data[2]; |
| 194 | size_t rv; | 175 | size_t rv; |
| 195 | u32 reg = *ppos; | 176 | u32 reg = *ppos; |
| 196 | int cpu = iminor(file->f_dentry->d_inode); | 177 | int cpu = iminor(file->f_dentry->d_inode); |
| 197 | int err; | 178 | int err; |
| 198 | 179 | ||
| 199 | if (count % 8) | 180 | if (count % 8) |
| 200 | return -EINVAL; /* Invalid chunk size */ | 181 | return -EINVAL; /* Invalid chunk size */ |
| 201 | 182 | ||
| 202 | for (rv = 0; count; count -= 8) { | 183 | for (rv = 0; count; count -= 8) { |
| 203 | err = do_rdmsr(cpu, reg, &data[0], &data[1]); | 184 | err = do_rdmsr(cpu, reg, &data[0], &data[1]); |
| 204 | if (err) | 185 | if (err) |
| 205 | return err; | 186 | return err; |
| 206 | if (copy_to_user(tmp, &data, 8)) | 187 | if (copy_to_user(tmp, &data, 8)) |
| 207 | return -EFAULT; | 188 | return -EFAULT; |
| 208 | tmp += 2; | 189 | tmp += 2; |
| 209 | } | 190 | } |
| 210 | 191 | ||
| 211 | return ((char __user *)tmp) - buf; | 192 | return ((char __user *)tmp) - buf; |
| 212 | } | 193 | } |
| 213 | 194 | ||
| 214 | static ssize_t msr_write(struct file *file, const char __user *buf, | 195 | static ssize_t msr_write(struct file *file, const char __user *buf, |
| 215 | size_t count, loff_t *ppos) | 196 | size_t count, loff_t *ppos) |
| 216 | { | 197 | { |
| 217 | const u32 __user *tmp = (const u32 __user *)buf; | 198 | const u32 __user *tmp = (const u32 __user *)buf; |
| 218 | u32 data[2]; | 199 | u32 data[2]; |
| 219 | size_t rv; | 200 | size_t rv; |
| 220 | u32 reg = *ppos; | 201 | u32 reg = *ppos; |
| 221 | int cpu = iminor(file->f_dentry->d_inode); | 202 | int cpu = iminor(file->f_dentry->d_inode); |
| 222 | int err; | 203 | int err; |
| 223 | 204 | ||
| 224 | if (count % 8) | 205 | if (count % 8) |
| 225 | return -EINVAL; /* Invalid chunk size */ | 206 | return -EINVAL; /* Invalid chunk size */ |
| 226 | 207 | ||
| 227 | for (rv = 0; count; count -= 8) { | 208 | for (rv = 0; count; count -= 8) { |
| 228 | if (copy_from_user(&data, tmp, 8)) | 209 | if (copy_from_user(&data, tmp, 8)) |
| 229 | return -EFAULT; | 210 | return -EFAULT; |
| 230 | err = do_wrmsr(cpu, reg, data[0], data[1]); | 211 | err = do_wrmsr(cpu, reg, data[0], data[1]); |
| 231 | if (err) | 212 | if (err) |
| 232 | return err; | 213 | return err; |
| 233 | tmp += 2; | 214 | tmp += 2; |
| 234 | } | 215 | } |
| 235 | 216 | ||
| 236 | return ((char __user *)tmp) - buf; | 217 | return ((char __user *)tmp) - buf; |
| 237 | } | 218 | } |
| 238 | 219 | ||
| 239 | static int msr_open(struct inode *inode, struct file *file) | 220 | static int msr_open(struct inode *inode, struct file *file) |
| 240 | { | 221 | { |
| 241 | unsigned int cpu = iminor(file->f_dentry->d_inode); | 222 | unsigned int cpu = iminor(file->f_dentry->d_inode); |
| 242 | struct cpuinfo_x86 *c = &(cpu_data)[cpu]; | 223 | struct cpuinfo_x86 *c = &(cpu_data)[cpu]; |
| 243 | 224 | ||
| 244 | if (cpu >= NR_CPUS || !cpu_online(cpu)) | 225 | if (cpu >= NR_CPUS || !cpu_online(cpu)) |
| 245 | return -ENXIO; /* No such CPU */ | 226 | return -ENXIO; /* No such CPU */ |
| 246 | if (!cpu_has(c, X86_FEATURE_MSR)) | 227 | if (!cpu_has(c, X86_FEATURE_MSR)) |
| 247 | return -EIO; /* MSR not supported */ | 228 | return -EIO; /* MSR not supported */ |
| 248 | 229 | ||
| 249 | return 0; | 230 | return 0; |
| 250 | } | 231 | } |
| 251 | 232 | ||
| 252 | /* | 233 | /* |
| 253 | * File operations we support | 234 | * File operations we support |
| 254 | */ | 235 | */ |
| 255 | static struct file_operations msr_fops = { | 236 | static struct file_operations msr_fops = { |
| 256 | .owner = THIS_MODULE, | 237 | .owner = THIS_MODULE, |
| 257 | .llseek = msr_seek, | 238 | .llseek = msr_seek, |
| 258 | .read = msr_read, | 239 | .read = msr_read, |
| 259 | .write = msr_write, | 240 | .write = msr_write, |
| 260 | .open = msr_open, | 241 | .open = msr_open, |
| 261 | }; | 242 | }; |
| 262 | 243 | ||
| 263 | static int msr_class_device_create(int i) | 244 | static int msr_class_device_create(int i) |
| 264 | { | 245 | { |
| 265 | int err = 0; | 246 | int err = 0; |
| 266 | struct class_device *class_err; | 247 | struct class_device *class_err; |
| 267 | 248 | ||
| 268 | class_err = class_device_create(msr_class, MKDEV(MSR_MAJOR, i), NULL, "msr%d",i); | 249 | class_err = class_device_create(msr_class, MKDEV(MSR_MAJOR, i), NULL, "msr%d",i); |
| 269 | if (IS_ERR(class_err)) | 250 | if (IS_ERR(class_err)) |
| 270 | err = PTR_ERR(class_err); | 251 | err = PTR_ERR(class_err); |
| 271 | return err; | 252 | return err; |
| 272 | } | 253 | } |
| 273 | 254 | ||
| 274 | static int __devinit msr_class_cpu_callback(struct notifier_block *nfb, unsigned long action, void *hcpu) | 255 | static int __devinit msr_class_cpu_callback(struct notifier_block *nfb, unsigned long action, void *hcpu) |
| 275 | { | 256 | { |
| 276 | unsigned int cpu = (unsigned long)hcpu; | 257 | unsigned int cpu = (unsigned long)hcpu; |
| 277 | 258 | ||
| 278 | switch (action) { | 259 | switch (action) { |
| 279 | case CPU_ONLINE: | 260 | case CPU_ONLINE: |
| 280 | msr_class_device_create(cpu); | 261 | msr_class_device_create(cpu); |
| 281 | break; | 262 | break; |
| 282 | case CPU_DEAD: | 263 | case CPU_DEAD: |
| 283 | class_device_destroy(msr_class, MKDEV(MSR_MAJOR, cpu)); | 264 | class_device_destroy(msr_class, MKDEV(MSR_MAJOR, cpu)); |
| 284 | break; | 265 | break; |
| 285 | } | 266 | } |
| 286 | return NOTIFY_OK; | 267 | return NOTIFY_OK; |
| 287 | } | 268 | } |
| 288 | 269 | ||
| 289 | static struct notifier_block msr_class_cpu_notifier = | 270 | static struct notifier_block msr_class_cpu_notifier = |
| 290 | { | 271 | { |
| 291 | .notifier_call = msr_class_cpu_callback, | 272 | .notifier_call = msr_class_cpu_callback, |
| 292 | }; | 273 | }; |
| 293 | 274 | ||
| 294 | static int __init msr_init(void) | 275 | static int __init msr_init(void) |
| 295 | { | 276 | { |
| 296 | int i, err = 0; | 277 | int i, err = 0; |
| 297 | i = 0; | 278 | i = 0; |
| 298 | 279 | ||
| 299 | if (register_chrdev(MSR_MAJOR, "cpu/msr", &msr_fops)) { | 280 | if (register_chrdev(MSR_MAJOR, "cpu/msr", &msr_fops)) { |
| 300 | printk(KERN_ERR "msr: unable to get major %d for msr\n", | 281 | printk(KERN_ERR "msr: unable to get major %d for msr\n", |
| 301 | MSR_MAJOR); | 282 | MSR_MAJOR); |
| 302 | err = -EBUSY; | 283 | err = -EBUSY; |
| 303 | goto out; | 284 | goto out; |
| 304 | } | 285 | } |
| 305 | msr_class = class_create(THIS_MODULE, "msr"); | 286 | msr_class = class_create(THIS_MODULE, "msr"); |
| 306 | if (IS_ERR(msr_class)) { | 287 | if (IS_ERR(msr_class)) { |
| 307 | err = PTR_ERR(msr_class); | 288 | err = PTR_ERR(msr_class); |
| 308 | goto out_chrdev; | 289 | goto out_chrdev; |
| 309 | } | 290 | } |
| 310 | for_each_online_cpu(i) { | 291 | for_each_online_cpu(i) { |
| 311 | err = msr_class_device_create(i); | 292 | err = msr_class_device_create(i); |
| 312 | if (err != 0) | 293 | if (err != 0) |
| 313 | goto out_class; | 294 | goto out_class; |
| 314 | } | 295 | } |
| 315 | register_cpu_notifier(&msr_class_cpu_notifier); | 296 | register_cpu_notifier(&msr_class_cpu_notifier); |
| 316 | 297 | ||
| 317 | err = 0; | 298 | err = 0; |
| 318 | goto out; | 299 | goto out; |
| 319 | 300 | ||
| 320 | out_class: | 301 | out_class: |
| 321 | i = 0; | 302 | i = 0; |
| 322 | for_each_online_cpu(i) | 303 | for_each_online_cpu(i) |
| 323 | class_device_destroy(msr_class, MKDEV(MSR_MAJOR, i)); | 304 | class_device_destroy(msr_class, MKDEV(MSR_MAJOR, i)); |
| 324 | class_destroy(msr_class); | 305 | class_destroy(msr_class); |
| 325 | out_chrdev: | 306 | out_chrdev: |
| 326 | unregister_chrdev(MSR_MAJOR, "cpu/msr"); | 307 | unregister_chrdev(MSR_MAJOR, "cpu/msr"); |
| 327 | out: | 308 | out: |
| 328 | return err; | 309 | return err; |
| 329 | } | 310 | } |
| 330 | 311 | ||
| 331 | static void __exit msr_exit(void) | 312 | static void __exit msr_exit(void) |
| 332 | { | 313 | { |
| 333 | int cpu = 0; | 314 | int cpu = 0; |
| 334 | for_each_online_cpu(cpu) | 315 | for_each_online_cpu(cpu) |
| 335 | class_device_destroy(msr_class, MKDEV(MSR_MAJOR, cpu)); | 316 | class_device_destroy(msr_class, MKDEV(MSR_MAJOR, cpu)); |
| 336 | class_destroy(msr_class); | 317 | class_destroy(msr_class); |
| 337 | unregister_chrdev(MSR_MAJOR, "cpu/msr"); | 318 | unregister_chrdev(MSR_MAJOR, "cpu/msr"); |
| 338 | unregister_cpu_notifier(&msr_class_cpu_notifier); | 319 | unregister_cpu_notifier(&msr_class_cpu_notifier); |
| 339 | } | 320 | } |
| 340 | 321 | ||
| 341 | module_init(msr_init); | 322 | module_init(msr_init); |
| 342 | module_exit(msr_exit) | 323 | module_exit(msr_exit) |
| 343 | 324 | ||
| 344 | MODULE_AUTHOR("H. Peter Anvin <hpa@zytor.com>"); | 325 | MODULE_AUTHOR("H. Peter Anvin <hpa@zytor.com>"); |
| 345 | MODULE_DESCRIPTION("x86 generic MSR driver"); | 326 | MODULE_DESCRIPTION("x86 generic MSR driver"); |
| 346 | MODULE_LICENSE("GPL"); | 327 | MODULE_LICENSE("GPL"); |
| 347 | 328 |
arch/i386/kernel/process.c
| 1 | /* | 1 | /* |
| 2 | * linux/arch/i386/kernel/process.c | 2 | * linux/arch/i386/kernel/process.c |
| 3 | * | 3 | * |
| 4 | * Copyright (C) 1995 Linus Torvalds | 4 | * Copyright (C) 1995 Linus Torvalds |
| 5 | * | 5 | * |
| 6 | * Pentium III FXSR, SSE support | 6 | * Pentium III FXSR, SSE support |
| 7 | * Gareth Hughes <gareth@valinux.com>, May 2000 | 7 | * Gareth Hughes <gareth@valinux.com>, May 2000 |
| 8 | */ | 8 | */ |
| 9 | 9 | ||
| 10 | /* | 10 | /* |
| 11 | * This file handles the architecture-dependent parts of process handling.. | 11 | * This file handles the architecture-dependent parts of process handling.. |
| 12 | */ | 12 | */ |
| 13 | 13 | ||
| 14 | #include <stdarg.h> | 14 | #include <stdarg.h> |
| 15 | 15 | ||
| 16 | #include <linux/cpu.h> | 16 | #include <linux/cpu.h> |
| 17 | #include <linux/errno.h> | 17 | #include <linux/errno.h> |
| 18 | #include <linux/sched.h> | 18 | #include <linux/sched.h> |
| 19 | #include <linux/fs.h> | 19 | #include <linux/fs.h> |
| 20 | #include <linux/kernel.h> | 20 | #include <linux/kernel.h> |
| 21 | #include <linux/mm.h> | 21 | #include <linux/mm.h> |
| 22 | #include <linux/elfcore.h> | 22 | #include <linux/elfcore.h> |
| 23 | #include <linux/smp.h> | 23 | #include <linux/smp.h> |
| 24 | #include <linux/smp_lock.h> | 24 | #include <linux/smp_lock.h> |
| 25 | #include <linux/stddef.h> | 25 | #include <linux/stddef.h> |
| 26 | #include <linux/slab.h> | 26 | #include <linux/slab.h> |
| 27 | #include <linux/vmalloc.h> | 27 | #include <linux/vmalloc.h> |
| 28 | #include <linux/user.h> | 28 | #include <linux/user.h> |
| 29 | #include <linux/a.out.h> | 29 | #include <linux/a.out.h> |
| 30 | #include <linux/interrupt.h> | 30 | #include <linux/interrupt.h> |
| 31 | #include <linux/config.h> | 31 | #include <linux/config.h> |
| 32 | #include <linux/utsname.h> | 32 | #include <linux/utsname.h> |
| 33 | #include <linux/delay.h> | 33 | #include <linux/delay.h> |
| 34 | #include <linux/reboot.h> | 34 | #include <linux/reboot.h> |
| 35 | #include <linux/init.h> | 35 | #include <linux/init.h> |
| 36 | #include <linux/mc146818rtc.h> | 36 | #include <linux/mc146818rtc.h> |
| 37 | #include <linux/module.h> | 37 | #include <linux/module.h> |
| 38 | #include <linux/kallsyms.h> | 38 | #include <linux/kallsyms.h> |
| 39 | #include <linux/ptrace.h> | 39 | #include <linux/ptrace.h> |
| 40 | #include <linux/random.h> | 40 | #include <linux/random.h> |
| 41 | #include <linux/kprobes.h> | 41 | #include <linux/kprobes.h> |
| 42 | 42 | ||
| 43 | #include <asm/uaccess.h> | 43 | #include <asm/uaccess.h> |
| 44 | #include <asm/pgtable.h> | 44 | #include <asm/pgtable.h> |
| 45 | #include <asm/system.h> | 45 | #include <asm/system.h> |
| 46 | #include <asm/io.h> | 46 | #include <asm/io.h> |
| 47 | #include <asm/ldt.h> | 47 | #include <asm/ldt.h> |
| 48 | #include <asm/processor.h> | 48 | #include <asm/processor.h> |
| 49 | #include <asm/i387.h> | 49 | #include <asm/i387.h> |
| 50 | #include <asm/irq.h> | 50 | #include <asm/irq.h> |
| 51 | #include <asm/desc.h> | 51 | #include <asm/desc.h> |
| 52 | #ifdef CONFIG_MATH_EMULATION | 52 | #ifdef CONFIG_MATH_EMULATION |
| 53 | #include <asm/math_emu.h> | 53 | #include <asm/math_emu.h> |
| 54 | #endif | 54 | #endif |
| 55 | 55 | ||
| 56 | #include <linux/irq.h> | 56 | #include <linux/irq.h> |
| 57 | #include <linux/err.h> | 57 | #include <linux/err.h> |
| 58 | 58 | ||
| 59 | #include <asm/tlbflush.h> | 59 | #include <asm/tlbflush.h> |
| 60 | #include <asm/cpu.h> | 60 | #include <asm/cpu.h> |
| 61 | 61 | ||
| 62 | asmlinkage void ret_from_fork(void) __asm__("ret_from_fork"); | 62 | asmlinkage void ret_from_fork(void) __asm__("ret_from_fork"); |
| 63 | 63 | ||
| 64 | static int hlt_counter; | 64 | static int hlt_counter; |
| 65 | 65 | ||
| 66 | unsigned long boot_option_idle_override = 0; | 66 | unsigned long boot_option_idle_override = 0; |
| 67 | EXPORT_SYMBOL(boot_option_idle_override); | 67 | EXPORT_SYMBOL(boot_option_idle_override); |
| 68 | 68 | ||
| 69 | /* | 69 | /* |
| 70 | * Return saved PC of a blocked thread. | 70 | * Return saved PC of a blocked thread. |
| 71 | */ | 71 | */ |
| 72 | unsigned long thread_saved_pc(struct task_struct *tsk) | 72 | unsigned long thread_saved_pc(struct task_struct *tsk) |
| 73 | { | 73 | { |
| 74 | return ((unsigned long *)tsk->thread.esp)[3]; | 74 | return ((unsigned long *)tsk->thread.esp)[3]; |
| 75 | } | 75 | } |
| 76 | 76 | ||
| 77 | /* | 77 | /* |
| 78 | * Powermanagement idle function, if any.. | 78 | * Powermanagement idle function, if any.. |
| 79 | */ | 79 | */ |
| 80 | void (*pm_idle)(void); | 80 | void (*pm_idle)(void); |
| 81 | EXPORT_SYMBOL(pm_idle); | 81 | EXPORT_SYMBOL(pm_idle); |
| 82 | static DEFINE_PER_CPU(unsigned int, cpu_idle_state); | 82 | static DEFINE_PER_CPU(unsigned int, cpu_idle_state); |
| 83 | 83 | ||
| 84 | void disable_hlt(void) | 84 | void disable_hlt(void) |
| 85 | { | 85 | { |
| 86 | hlt_counter++; | 86 | hlt_counter++; |
| 87 | } | 87 | } |
| 88 | 88 | ||
| 89 | EXPORT_SYMBOL(disable_hlt); | 89 | EXPORT_SYMBOL(disable_hlt); |
| 90 | 90 | ||
| 91 | void enable_hlt(void) | 91 | void enable_hlt(void) |
| 92 | { | 92 | { |
| 93 | hlt_counter--; | 93 | hlt_counter--; |
| 94 | } | 94 | } |
| 95 | 95 | ||
| 96 | EXPORT_SYMBOL(enable_hlt); | 96 | EXPORT_SYMBOL(enable_hlt); |
| 97 | 97 | ||
| 98 | /* | 98 | /* |
| 99 | * We use this if we don't have any better | 99 | * We use this if we don't have any better |
| 100 | * idle routine.. | 100 | * idle routine.. |
| 101 | */ | 101 | */ |
| 102 | void default_idle(void) | 102 | void default_idle(void) |
| 103 | { | 103 | { |
| 104 | if (!hlt_counter && boot_cpu_data.hlt_works_ok) { | 104 | if (!hlt_counter && boot_cpu_data.hlt_works_ok) { |
| 105 | local_irq_disable(); | 105 | local_irq_disable(); |
| 106 | if (!need_resched()) | 106 | if (!need_resched()) |
| 107 | safe_halt(); | 107 | safe_halt(); |
| 108 | else | 108 | else |
| 109 | local_irq_enable(); | 109 | local_irq_enable(); |
| 110 | } else { | 110 | } else { |
| 111 | cpu_relax(); | 111 | cpu_relax(); |
| 112 | } | 112 | } |
| 113 | } | 113 | } |
| 114 | #ifdef CONFIG_APM_MODULE | 114 | #ifdef CONFIG_APM_MODULE |
| 115 | EXPORT_SYMBOL(default_idle); | 115 | EXPORT_SYMBOL(default_idle); |
| 116 | #endif | 116 | #endif |
| 117 | 117 | ||
| 118 | /* | 118 | /* |
| 119 | * On SMP it's slightly faster (but much more power-consuming!) | 119 | * On SMP it's slightly faster (but much more power-consuming!) |
| 120 | * to poll the ->work.need_resched flag instead of waiting for the | 120 | * to poll the ->work.need_resched flag instead of waiting for the |
| 121 | * cross-CPU IPI to arrive. Use this option with caution. | 121 | * cross-CPU IPI to arrive. Use this option with caution. |
| 122 | */ | 122 | */ |
| 123 | static void poll_idle (void) | 123 | static void poll_idle (void) |
| 124 | { | 124 | { |
| 125 | int oldval; | 125 | int oldval; |
| 126 | 126 | ||
| 127 | local_irq_enable(); | 127 | local_irq_enable(); |
| 128 | 128 | ||
| 129 | /* | 129 | /* |
| 130 | * Deal with another CPU just having chosen a thread to | 130 | * Deal with another CPU just having chosen a thread to |
| 131 | * run here: | 131 | * run here: |
| 132 | */ | 132 | */ |
| 133 | oldval = test_and_clear_thread_flag(TIF_NEED_RESCHED); | 133 | oldval = test_and_clear_thread_flag(TIF_NEED_RESCHED); |
| 134 | 134 | ||
| 135 | if (!oldval) { | 135 | if (!oldval) { |
| 136 | set_thread_flag(TIF_POLLING_NRFLAG); | 136 | set_thread_flag(TIF_POLLING_NRFLAG); |
| 137 | asm volatile( | 137 | asm volatile( |
| 138 | "2:" | 138 | "2:" |
| 139 | "testl %0, %1;" | 139 | "testl %0, %1;" |
| 140 | "rep; nop;" | 140 | "rep; nop;" |
| 141 | "je 2b;" | 141 | "je 2b;" |
| 142 | : : "i"(_TIF_NEED_RESCHED), "m" (current_thread_info()->flags)); | 142 | : : "i"(_TIF_NEED_RESCHED), "m" (current_thread_info()->flags)); |
| 143 | 143 | ||
| 144 | clear_thread_flag(TIF_POLLING_NRFLAG); | 144 | clear_thread_flag(TIF_POLLING_NRFLAG); |
| 145 | } else { | 145 | } else { |
| 146 | set_need_resched(); | 146 | set_need_resched(); |
| 147 | } | 147 | } |
| 148 | } | 148 | } |
| 149 | 149 | ||
| 150 | #ifdef CONFIG_HOTPLUG_CPU | 150 | #ifdef CONFIG_HOTPLUG_CPU |
| 151 | #include <asm/nmi.h> | 151 | #include <asm/nmi.h> |
| 152 | /* We don't actually take CPU down, just spin without interrupts. */ | 152 | /* We don't actually take CPU down, just spin without interrupts. */ |
| 153 | static inline void play_dead(void) | 153 | static inline void play_dead(void) |
| 154 | { | 154 | { |
| 155 | /* This must be done before dead CPU ack */ | 155 | /* This must be done before dead CPU ack */ |
| 156 | cpu_exit_clear(); | 156 | cpu_exit_clear(); |
| 157 | wbinvd(); | 157 | wbinvd(); |
| 158 | mb(); | 158 | mb(); |
| 159 | /* Ack it */ | 159 | /* Ack it */ |
| 160 | __get_cpu_var(cpu_state) = CPU_DEAD; | 160 | __get_cpu_var(cpu_state) = CPU_DEAD; |
| 161 | 161 | ||
| 162 | /* | 162 | /* |
| 163 | * With physical CPU hotplug, we should halt the cpu | 163 | * With physical CPU hotplug, we should halt the cpu |
| 164 | */ | 164 | */ |
| 165 | local_irq_disable(); | 165 | local_irq_disable(); |
| 166 | while (1) | 166 | while (1) |
| 167 | __asm__ __volatile__("hlt":::"memory"); | 167 | halt(); |
| 168 | } | 168 | } |
| 169 | #else | 169 | #else |
| 170 | static inline void play_dead(void) | 170 | static inline void play_dead(void) |
| 171 | { | 171 | { |
| 172 | BUG(); | 172 | BUG(); |
| 173 | } | 173 | } |
| 174 | #endif /* CONFIG_HOTPLUG_CPU */ | 174 | #endif /* CONFIG_HOTPLUG_CPU */ |
| 175 | 175 | ||
| 176 | /* | 176 | /* |
| 177 | * The idle thread. There's no useful work to be | 177 | * The idle thread. There's no useful work to be |
| 178 | * done, so just try to conserve power and have a | 178 | * done, so just try to conserve power and have a |
| 179 | * low exit latency (ie sit in a loop waiting for | 179 | * low exit latency (ie sit in a loop waiting for |
| 180 | * somebody to say that they'd like to reschedule) | 180 | * somebody to say that they'd like to reschedule) |
| 181 | */ | 181 | */ |
| 182 | void cpu_idle(void) | 182 | void cpu_idle(void) |
| 183 | { | 183 | { |
| 184 | int cpu = raw_smp_processor_id(); | 184 | int cpu = raw_smp_processor_id(); |
| 185 | 185 | ||
| 186 | /* endless idle loop with no priority at all */ | 186 | /* endless idle loop with no priority at all */ |
| 187 | while (1) { | 187 | while (1) { |
| 188 | while (!need_resched()) { | 188 | while (!need_resched()) { |
| 189 | void (*idle)(void); | 189 | void (*idle)(void); |
| 190 | 190 | ||
| 191 | if (__get_cpu_var(cpu_idle_state)) | 191 | if (__get_cpu_var(cpu_idle_state)) |
| 192 | __get_cpu_var(cpu_idle_state) = 0; | 192 | __get_cpu_var(cpu_idle_state) = 0; |
| 193 | 193 | ||
| 194 | rmb(); | 194 | rmb(); |
| 195 | idle = pm_idle; | 195 | idle = pm_idle; |
| 196 | 196 | ||
| 197 | if (!idle) | 197 | if (!idle) |
| 198 | idle = default_idle; | 198 | idle = default_idle; |
| 199 | 199 | ||
| 200 | if (cpu_is_offline(cpu)) | 200 | if (cpu_is_offline(cpu)) |
| 201 | play_dead(); | 201 | play_dead(); |
| 202 | 202 | ||
| 203 | __get_cpu_var(irq_stat).idle_timestamp = jiffies; | 203 | __get_cpu_var(irq_stat).idle_timestamp = jiffies; |
| 204 | idle(); | 204 | idle(); |
| 205 | } | 205 | } |
| 206 | schedule(); | 206 | schedule(); |
| 207 | } | 207 | } |
| 208 | } | 208 | } |
| 209 | 209 | ||
| 210 | void cpu_idle_wait(void) | 210 | void cpu_idle_wait(void) |
| 211 | { | 211 | { |
| 212 | unsigned int cpu, this_cpu = get_cpu(); | 212 | unsigned int cpu, this_cpu = get_cpu(); |
| 213 | cpumask_t map; | 213 | cpumask_t map; |
| 214 | 214 | ||
| 215 | set_cpus_allowed(current, cpumask_of_cpu(this_cpu)); | 215 | set_cpus_allowed(current, cpumask_of_cpu(this_cpu)); |
| 216 | put_cpu(); | 216 | put_cpu(); |
| 217 | 217 | ||
| 218 | cpus_clear(map); | 218 | cpus_clear(map); |
| 219 | for_each_online_cpu(cpu) { | 219 | for_each_online_cpu(cpu) { |
| 220 | per_cpu(cpu_idle_state, cpu) = 1; | 220 | per_cpu(cpu_idle_state, cpu) = 1; |
| 221 | cpu_set(cpu, map); | 221 | cpu_set(cpu, map); |
| 222 | } | 222 | } |
| 223 | 223 | ||
| 224 | __get_cpu_var(cpu_idle_state) = 0; | 224 | __get_cpu_var(cpu_idle_state) = 0; |
| 225 | 225 | ||
| 226 | wmb(); | 226 | wmb(); |
| 227 | do { | 227 | do { |
| 228 | ssleep(1); | 228 | ssleep(1); |
| 229 | for_each_online_cpu(cpu) { | 229 | for_each_online_cpu(cpu) { |
| 230 | if (cpu_isset(cpu, map) && !per_cpu(cpu_idle_state, cpu)) | 230 | if (cpu_isset(cpu, map) && !per_cpu(cpu_idle_state, cpu)) |
| 231 | cpu_clear(cpu, map); | 231 | cpu_clear(cpu, map); |
| 232 | } | 232 | } |
| 233 | cpus_and(map, map, cpu_online_map); | 233 | cpus_and(map, map, cpu_online_map); |
| 234 | } while (!cpus_empty(map)); | 234 | } while (!cpus_empty(map)); |
| 235 | } | 235 | } |
| 236 | EXPORT_SYMBOL_GPL(cpu_idle_wait); | 236 | EXPORT_SYMBOL_GPL(cpu_idle_wait); |
| 237 | 237 | ||
| 238 | /* | 238 | /* |
| 239 | * This uses new MONITOR/MWAIT instructions on P4 processors with PNI, | 239 | * This uses new MONITOR/MWAIT instructions on P4 processors with PNI, |
| 240 | * which can obviate IPI to trigger checking of need_resched. | 240 | * which can obviate IPI to trigger checking of need_resched. |
| 241 | * We execute MONITOR against need_resched and enter optimized wait state | 241 | * We execute MONITOR against need_resched and enter optimized wait state |
| 242 | * through MWAIT. Whenever someone changes need_resched, we would be woken | 242 | * through MWAIT. Whenever someone changes need_resched, we would be woken |
| 243 | * up from MWAIT (without an IPI). | 243 | * up from MWAIT (without an IPI). |
| 244 | */ | 244 | */ |
| 245 | static void mwait_idle(void) | 245 | static void mwait_idle(void) |
| 246 | { | 246 | { |
| 247 | local_irq_enable(); | 247 | local_irq_enable(); |
| 248 | 248 | ||
| 249 | if (!need_resched()) { | 249 | if (!need_resched()) { |
| 250 | set_thread_flag(TIF_POLLING_NRFLAG); | 250 | set_thread_flag(TIF_POLLING_NRFLAG); |
| 251 | do { | 251 | do { |
| 252 | __monitor((void *)¤t_thread_info()->flags, 0, 0); | 252 | __monitor((void *)¤t_thread_info()->flags, 0, 0); |
| 253 | if (need_resched()) | 253 | if (need_resched()) |
| 254 | break; | 254 | break; |
| 255 | __mwait(0, 0); | 255 | __mwait(0, 0); |
| 256 | } while (!need_resched()); | 256 | } while (!need_resched()); |
| 257 | clear_thread_flag(TIF_POLLING_NRFLAG); | 257 | clear_thread_flag(TIF_POLLING_NRFLAG); |
| 258 | } | 258 | } |
| 259 | } | 259 | } |
| 260 | 260 | ||
| 261 | void __devinit select_idle_routine(const struct cpuinfo_x86 *c) | 261 | void __devinit select_idle_routine(const struct cpuinfo_x86 *c) |
| 262 | { | 262 | { |
| 263 | if (cpu_has(c, X86_FEATURE_MWAIT)) { | 263 | if (cpu_has(c, X86_FEATURE_MWAIT)) { |
| 264 | printk("monitor/mwait feature present.\n"); | 264 | printk("monitor/mwait feature present.\n"); |
| 265 | /* | 265 | /* |
| 266 | * Skip, if setup has overridden idle. | 266 | * Skip, if setup has overridden idle. |
| 267 | * One CPU supports mwait => All CPUs supports mwait | 267 | * One CPU supports mwait => All CPUs supports mwait |
| 268 | */ | 268 | */ |
| 269 | if (!pm_idle) { | 269 | if (!pm_idle) { |
| 270 | printk("using mwait in idle threads.\n"); | 270 | printk("using mwait in idle threads.\n"); |
| 271 | pm_idle = mwait_idle; | 271 | pm_idle = mwait_idle; |
| 272 | } | 272 | } |
| 273 | } | 273 | } |
| 274 | } | 274 | } |
| 275 | 275 | ||
| 276 | static int __init idle_setup (char *str) | 276 | static int __init idle_setup (char *str) |
| 277 | { | 277 | { |
| 278 | if (!strncmp(str, "poll", 4)) { | 278 | if (!strncmp(str, "poll", 4)) { |
| 279 | printk("using polling idle threads.\n"); | 279 | printk("using polling idle threads.\n"); |
| 280 | pm_idle = poll_idle; | 280 | pm_idle = poll_idle; |
| 281 | #ifdef CONFIG_X86_SMP | 281 | #ifdef CONFIG_X86_SMP |
| 282 | if (smp_num_siblings > 1) | 282 | if (smp_num_siblings > 1) |
| 283 | printk("WARNING: polling idle and HT enabled, performance may degrade.\n"); | 283 | printk("WARNING: polling idle and HT enabled, performance may degrade.\n"); |
| 284 | #endif | 284 | #endif |
| 285 | } else if (!strncmp(str, "halt", 4)) { | 285 | } else if (!strncmp(str, "halt", 4)) { |
| 286 | printk("using halt in idle threads.\n"); | 286 | printk("using halt in idle threads.\n"); |
| 287 | pm_idle = default_idle; | 287 | pm_idle = default_idle; |
| 288 | } | 288 | } |
| 289 | 289 | ||
| 290 | boot_option_idle_override = 1; | 290 | boot_option_idle_override = 1; |
| 291 | return 1; | 291 | return 1; |
| 292 | } | 292 | } |
| 293 | 293 | ||
| 294 | __setup("idle=", idle_setup); | 294 | __setup("idle=", idle_setup); |
| 295 | 295 | ||
| 296 | void show_regs(struct pt_regs * regs) | 296 | void show_regs(struct pt_regs * regs) |
| 297 | { | 297 | { |
| 298 | unsigned long cr0 = 0L, cr2 = 0L, cr3 = 0L, cr4 = 0L; | 298 | unsigned long cr0 = 0L, cr2 = 0L, cr3 = 0L, cr4 = 0L; |
| 299 | 299 | ||
| 300 | printk("\n"); | 300 | printk("\n"); |
| 301 | printk("Pid: %d, comm: %20s\n", current->pid, current->comm); | 301 | printk("Pid: %d, comm: %20s\n", current->pid, current->comm); |
| 302 | printk("EIP: %04x:[<%08lx>] CPU: %d\n",0xffff & regs->xcs,regs->eip, smp_processor_id()); | 302 | printk("EIP: %04x:[<%08lx>] CPU: %d\n",0xffff & regs->xcs,regs->eip, smp_processor_id()); |
| 303 | print_symbol("EIP is at %s\n", regs->eip); | 303 | print_symbol("EIP is at %s\n", regs->eip); |
| 304 | 304 | ||
| 305 | if (user_mode(regs)) | 305 | if (user_mode(regs)) |
| 306 | printk(" ESP: %04x:%08lx",0xffff & regs->xss,regs->esp); | 306 | printk(" ESP: %04x:%08lx",0xffff & regs->xss,regs->esp); |
| 307 | printk(" EFLAGS: %08lx %s (%s)\n", | 307 | printk(" EFLAGS: %08lx %s (%s)\n", |
| 308 | regs->eflags, print_tainted(), system_utsname.release); | 308 | regs->eflags, print_tainted(), system_utsname.release); |
| 309 | printk("EAX: %08lx EBX: %08lx ECX: %08lx EDX: %08lx\n", | 309 | printk("EAX: %08lx EBX: %08lx ECX: %08lx EDX: %08lx\n", |
| 310 | regs->eax,regs->ebx,regs->ecx,regs->edx); | 310 | regs->eax,regs->ebx,regs->ecx,regs->edx); |
| 311 | printk("ESI: %08lx EDI: %08lx EBP: %08lx", | 311 | printk("ESI: %08lx EDI: %08lx EBP: %08lx", |
| 312 | regs->esi, regs->edi, regs->ebp); | 312 | regs->esi, regs->edi, regs->ebp); |
| 313 | printk(" DS: %04x ES: %04x\n", | 313 | printk(" DS: %04x ES: %04x\n", |
| 314 | 0xffff & regs->xds,0xffff & regs->xes); | 314 | 0xffff & regs->xds,0xffff & regs->xes); |
| 315 | 315 | ||
| 316 | cr0 = read_cr0(); | 316 | cr0 = read_cr0(); |
| 317 | cr2 = read_cr2(); | 317 | cr2 = read_cr2(); |
| 318 | cr3 = read_cr3(); | 318 | cr3 = read_cr3(); |
| 319 | if (current_cpu_data.x86 > 4) { | 319 | if (current_cpu_data.x86 > 4) { |
| 320 | cr4 = read_cr4(); | 320 | cr4 = read_cr4(); |
| 321 | } | 321 | } |
| 322 | printk("CR0: %08lx CR2: %08lx CR3: %08lx CR4: %08lx\n", cr0, cr2, cr3, cr4); | 322 | printk("CR0: %08lx CR2: %08lx CR3: %08lx CR4: %08lx\n", cr0, cr2, cr3, cr4); |
| 323 | show_trace(NULL, ®s->esp); | 323 | show_trace(NULL, ®s->esp); |
| 324 | } | 324 | } |
| 325 | 325 | ||
| 326 | /* | 326 | /* |
| 327 | * This gets run with %ebx containing the | 327 | * This gets run with %ebx containing the |
| 328 | * function to call, and %edx containing | 328 | * function to call, and %edx containing |
| 329 | * the "args". | 329 | * the "args". |
| 330 | */ | 330 | */ |
| 331 | extern void kernel_thread_helper(void); | 331 | extern void kernel_thread_helper(void); |
| 332 | __asm__(".section .text\n" | 332 | __asm__(".section .text\n" |
| 333 | ".align 4\n" | 333 | ".align 4\n" |
| 334 | "kernel_thread_helper:\n\t" | 334 | "kernel_thread_helper:\n\t" |
| 335 | "movl %edx,%eax\n\t" | 335 | "movl %edx,%eax\n\t" |
| 336 | "pushl %edx\n\t" | 336 | "pushl %edx\n\t" |
| 337 | "call *%ebx\n\t" | 337 | "call *%ebx\n\t" |
| 338 | "pushl %eax\n\t" | 338 | "pushl %eax\n\t" |
| 339 | "call do_exit\n" | 339 | "call do_exit\n" |
| 340 | ".previous"); | 340 | ".previous"); |
| 341 | 341 | ||
| 342 | /* | 342 | /* |
| 343 | * Create a kernel thread | 343 | * Create a kernel thread |
| 344 | */ | 344 | */ |
| 345 | int kernel_thread(int (*fn)(void *), void * arg, unsigned long flags) | 345 | int kernel_thread(int (*fn)(void *), void * arg, unsigned long flags) |
| 346 | { | 346 | { |
| 347 | struct pt_regs regs; | 347 | struct pt_regs regs; |
| 348 | 348 | ||
| 349 | memset(®s, 0, sizeof(regs)); | 349 | memset(®s, 0, sizeof(regs)); |
| 350 | 350 | ||
| 351 | regs.ebx = (unsigned long) fn; | 351 | regs.ebx = (unsigned long) fn; |
| 352 | regs.edx = (unsigned long) arg; | 352 | regs.edx = (unsigned long) arg; |
| 353 | 353 | ||
| 354 | regs.xds = __USER_DS; | 354 | regs.xds = __USER_DS; |
| 355 | regs.xes = __USER_DS; | 355 | regs.xes = __USER_DS; |
| 356 | regs.orig_eax = -1; | 356 | regs.orig_eax = -1; |
| 357 | regs.eip = (unsigned long) kernel_thread_helper; | 357 | regs.eip = (unsigned long) kernel_thread_helper; |
| 358 | regs.xcs = __KERNEL_CS; | 358 | regs.xcs = __KERNEL_CS; |
| 359 | regs.eflags = X86_EFLAGS_IF | X86_EFLAGS_SF | X86_EFLAGS_PF | 0x2; | 359 | regs.eflags = X86_EFLAGS_IF | X86_EFLAGS_SF | X86_EFLAGS_PF | 0x2; |
| 360 | 360 | ||
| 361 | /* Ok, create the new process.. */ | 361 | /* Ok, create the new process.. */ |
| 362 | return do_fork(flags | CLONE_VM | CLONE_UNTRACED, 0, ®s, 0, NULL, NULL); | 362 | return do_fork(flags | CLONE_VM | CLONE_UNTRACED, 0, ®s, 0, NULL, NULL); |
| 363 | } | 363 | } |
| 364 | EXPORT_SYMBOL(kernel_thread); | 364 | EXPORT_SYMBOL(kernel_thread); |
| 365 | 365 | ||
| 366 | /* | 366 | /* |
| 367 | * Free current thread data structures etc.. | 367 | * Free current thread data structures etc.. |
| 368 | */ | 368 | */ |
| 369 | void exit_thread(void) | 369 | void exit_thread(void) |
| 370 | { | 370 | { |
| 371 | struct task_struct *tsk = current; | 371 | struct task_struct *tsk = current; |
| 372 | struct thread_struct *t = &tsk->thread; | 372 | struct thread_struct *t = &tsk->thread; |
| 373 | 373 | ||
| 374 | /* | 374 | /* |
| 375 | * Remove function-return probe instances associated with this task | 375 | * Remove function-return probe instances associated with this task |
| 376 | * and put them back on the free list. Do not insert an exit probe for | 376 | * and put them back on the free list. Do not insert an exit probe for |
| 377 | * this function, it will be disabled by kprobe_flush_task if you do. | 377 | * this function, it will be disabled by kprobe_flush_task if you do. |
| 378 | */ | 378 | */ |
| 379 | kprobe_flush_task(tsk); | 379 | kprobe_flush_task(tsk); |
| 380 | 380 | ||
| 381 | /* The process may have allocated an io port bitmap... nuke it. */ | 381 | /* The process may have allocated an io port bitmap... nuke it. */ |
| 382 | if (unlikely(NULL != t->io_bitmap_ptr)) { | 382 | if (unlikely(NULL != t->io_bitmap_ptr)) { |
| 383 | int cpu = get_cpu(); | 383 | int cpu = get_cpu(); |
| 384 | struct tss_struct *tss = &per_cpu(init_tss, cpu); | 384 | struct tss_struct *tss = &per_cpu(init_tss, cpu); |
| 385 | 385 | ||
| 386 | kfree(t->io_bitmap_ptr); | 386 | kfree(t->io_bitmap_ptr); |
| 387 | t->io_bitmap_ptr = NULL; | 387 | t->io_bitmap_ptr = NULL; |
| 388 | /* | 388 | /* |
| 389 | * Careful, clear this in the TSS too: | 389 | * Careful, clear this in the TSS too: |
| 390 | */ | 390 | */ |
| 391 | memset(tss->io_bitmap, 0xff, tss->io_bitmap_max); | 391 | memset(tss->io_bitmap, 0xff, tss->io_bitmap_max); |
| 392 | t->io_bitmap_max = 0; | 392 | t->io_bitmap_max = 0; |
| 393 | tss->io_bitmap_owner = NULL; | 393 | tss->io_bitmap_owner = NULL; |
| 394 | tss->io_bitmap_max = 0; | 394 | tss->io_bitmap_max = 0; |
| 395 | tss->io_bitmap_base = INVALID_IO_BITMAP_OFFSET; | 395 | tss->io_bitmap_base = INVALID_IO_BITMAP_OFFSET; |
| 396 | put_cpu(); | 396 | put_cpu(); |
| 397 | } | 397 | } |
| 398 | } | 398 | } |
| 399 | 399 | ||
| 400 | void flush_thread(void) | 400 | void flush_thread(void) |
| 401 | { | 401 | { |
| 402 | struct task_struct *tsk = current; | 402 | struct task_struct *tsk = current; |
| 403 | 403 | ||
| 404 | /* | 404 | /* |
| 405 | * Remove function-return probe instances associated with this task | 405 | * Remove function-return probe instances associated with this task |
| 406 | * and put them back on the free list. Do not insert an exit probe for | 406 | * and put them back on the free list. Do not insert an exit probe for |
| 407 | * this function, it will be disabled by kprobe_flush_task if you do. | 407 | * this function, it will be disabled by kprobe_flush_task if you do. |
| 408 | */ | 408 | */ |
| 409 | kprobe_flush_task(tsk); | 409 | kprobe_flush_task(tsk); |
| 410 | 410 | ||
| 411 | memset(tsk->thread.debugreg, 0, sizeof(unsigned long)*8); | 411 | memset(tsk->thread.debugreg, 0, sizeof(unsigned long)*8); |
| 412 | memset(tsk->thread.tls_array, 0, sizeof(tsk->thread.tls_array)); | 412 | memset(tsk->thread.tls_array, 0, sizeof(tsk->thread.tls_array)); |
| 413 | /* | 413 | /* |
| 414 | * Forget coprocessor state.. | 414 | * Forget coprocessor state.. |
| 415 | */ | 415 | */ |
| 416 | clear_fpu(tsk); | 416 | clear_fpu(tsk); |
| 417 | clear_used_math(); | 417 | clear_used_math(); |
| 418 | } | 418 | } |
| 419 | 419 | ||
| 420 | void release_thread(struct task_struct *dead_task) | 420 | void release_thread(struct task_struct *dead_task) |
| 421 | { | 421 | { |
| 422 | if (dead_task->mm) { | 422 | if (dead_task->mm) { |
| 423 | // temporary debugging check | 423 | // temporary debugging check |
| 424 | if (dead_task->mm->context.size) { | 424 | if (dead_task->mm->context.size) { |
| 425 | printk("WARNING: dead process %8s still has LDT? <%p/%d>\n", | 425 | printk("WARNING: dead process %8s still has LDT? <%p/%d>\n", |
| 426 | dead_task->comm, | 426 | dead_task->comm, |
| 427 | dead_task->mm->context.ldt, | 427 | dead_task->mm->context.ldt, |
| 428 | dead_task->mm->context.size); | 428 | dead_task->mm->context.size); |
| 429 | BUG(); | 429 | BUG(); |
| 430 | } | 430 | } |
| 431 | } | 431 | } |
| 432 | 432 | ||
| 433 | release_vm86_irqs(dead_task); | 433 | release_vm86_irqs(dead_task); |
| 434 | } | 434 | } |
| 435 | 435 | ||
| 436 | /* | 436 | /* |
| 437 | * This gets called before we allocate a new thread and copy | 437 | * This gets called before we allocate a new thread and copy |
| 438 | * the current task into it. | 438 | * the current task into it. |
| 439 | */ | 439 | */ |
| 440 | void prepare_to_copy(struct task_struct *tsk) | 440 | void prepare_to_copy(struct task_struct *tsk) |
| 441 | { | 441 | { |
| 442 | unlazy_fpu(tsk); | 442 | unlazy_fpu(tsk); |
| 443 | } | 443 | } |
| 444 | 444 | ||
| 445 | int copy_thread(int nr, unsigned long clone_flags, unsigned long esp, | 445 | int copy_thread(int nr, unsigned long clone_flags, unsigned long esp, |
| 446 | unsigned long unused, | 446 | unsigned long unused, |
| 447 | struct task_struct * p, struct pt_regs * regs) | 447 | struct task_struct * p, struct pt_regs * regs) |
| 448 | { | 448 | { |
| 449 | struct pt_regs * childregs; | 449 | struct pt_regs * childregs; |
| 450 | struct task_struct *tsk; | 450 | struct task_struct *tsk; |
| 451 | int err; | 451 | int err; |
| 452 | 452 | ||
| 453 | childregs = ((struct pt_regs *) (THREAD_SIZE + (unsigned long) p->thread_info)) - 1; | 453 | childregs = ((struct pt_regs *) (THREAD_SIZE + (unsigned long) p->thread_info)) - 1; |
| 454 | /* | 454 | /* |
| 455 | * The below -8 is to reserve 8 bytes on top of the ring0 stack. | 455 | * The below -8 is to reserve 8 bytes on top of the ring0 stack. |
| 456 | * This is necessary to guarantee that the entire "struct pt_regs" | 456 | * This is necessary to guarantee that the entire "struct pt_regs" |
| 457 | * is accessable even if the CPU haven't stored the SS/ESP registers | 457 | * is accessable even if the CPU haven't stored the SS/ESP registers |
| 458 | * on the stack (interrupt gate does not save these registers | 458 | * on the stack (interrupt gate does not save these registers |
| 459 | * when switching to the same priv ring). | 459 | * when switching to the same priv ring). |
| 460 | * Therefore beware: accessing the xss/esp fields of the | 460 | * Therefore beware: accessing the xss/esp fields of the |
| 461 | * "struct pt_regs" is possible, but they may contain the | 461 | * "struct pt_regs" is possible, but they may contain the |
| 462 | * completely wrong values. | 462 | * completely wrong values. |
| 463 | */ | 463 | */ |
| 464 | childregs = (struct pt_regs *) ((unsigned long) childregs - 8); | 464 | childregs = (struct pt_regs *) ((unsigned long) childregs - 8); |
| 465 | *childregs = *regs; | 465 | *childregs = *regs; |
| 466 | childregs->eax = 0; | 466 | childregs->eax = 0; |
| 467 | childregs->esp = esp; | 467 | childregs->esp = esp; |
| 468 | 468 | ||
| 469 | p->thread.esp = (unsigned long) childregs; | 469 | p->thread.esp = (unsigned long) childregs; |
| 470 | p->thread.esp0 = (unsigned long) (childregs+1); | 470 | p->thread.esp0 = (unsigned long) (childregs+1); |
| 471 | 471 | ||
| 472 | p->thread.eip = (unsigned long) ret_from_fork; | 472 | p->thread.eip = (unsigned long) ret_from_fork; |
| 473 | 473 | ||
| 474 | savesegment(fs,p->thread.fs); | 474 | savesegment(fs,p->thread.fs); |
| 475 | savesegment(gs,p->thread.gs); | 475 | savesegment(gs,p->thread.gs); |
| 476 | 476 | ||
| 477 | tsk = current; | 477 | tsk = current; |
| 478 | if (unlikely(NULL != tsk->thread.io_bitmap_ptr)) { | 478 | if (unlikely(NULL != tsk->thread.io_bitmap_ptr)) { |
| 479 | p->thread.io_bitmap_ptr = kmalloc(IO_BITMAP_BYTES, GFP_KERNEL); | 479 | p->thread.io_bitmap_ptr = kmalloc(IO_BITMAP_BYTES, GFP_KERNEL); |
| 480 | if (!p->thread.io_bitmap_ptr) { | 480 | if (!p->thread.io_bitmap_ptr) { |
| 481 | p->thread.io_bitmap_max = 0; | 481 | p->thread.io_bitmap_max = 0; |
| 482 | return -ENOMEM; | 482 | return -ENOMEM; |
| 483 | } | 483 | } |
| 484 | memcpy(p->thread.io_bitmap_ptr, tsk->thread.io_bitmap_ptr, | 484 | memcpy(p->thread.io_bitmap_ptr, tsk->thread.io_bitmap_ptr, |
| 485 | IO_BITMAP_BYTES); | 485 | IO_BITMAP_BYTES); |
| 486 | } | 486 | } |
| 487 | 487 | ||
| 488 | /* | 488 | /* |
| 489 | * Set a new TLS for the child thread? | 489 | * Set a new TLS for the child thread? |
| 490 | */ | 490 | */ |
| 491 | if (clone_flags & CLONE_SETTLS) { | 491 | if (clone_flags & CLONE_SETTLS) { |
| 492 | struct desc_struct *desc; | 492 | struct desc_struct *desc; |
| 493 | struct user_desc info; | 493 | struct user_desc info; |
| 494 | int idx; | 494 | int idx; |
| 495 | 495 | ||
| 496 | err = -EFAULT; | 496 | err = -EFAULT; |
| 497 | if (copy_from_user(&info, (void __user *)childregs->esi, sizeof(info))) | 497 | if (copy_from_user(&info, (void __user *)childregs->esi, sizeof(info))) |
| 498 | goto out; | 498 | goto out; |
| 499 | err = -EINVAL; | 499 | err = -EINVAL; |
| 500 | if (LDT_empty(&info)) | 500 | if (LDT_empty(&info)) |
| 501 | goto out; | 501 | goto out; |
| 502 | 502 | ||
| 503 | idx = info.entry_number; | 503 | idx = info.entry_number; |
| 504 | if (idx < GDT_ENTRY_TLS_MIN || idx > GDT_ENTRY_TLS_MAX) | 504 | if (idx < GDT_ENTRY_TLS_MIN || idx > GDT_ENTRY_TLS_MAX) |
| 505 | goto out; | 505 | goto out; |
| 506 | 506 | ||
| 507 | desc = p->thread.tls_array + idx - GDT_ENTRY_TLS_MIN; | 507 | desc = p->thread.tls_array + idx - GDT_ENTRY_TLS_MIN; |
| 508 | desc->a = LDT_entry_a(&info); | 508 | desc->a = LDT_entry_a(&info); |
| 509 | desc->b = LDT_entry_b(&info); | 509 | desc->b = LDT_entry_b(&info); |
| 510 | } | 510 | } |
| 511 | 511 | ||
| 512 | err = 0; | 512 | err = 0; |
| 513 | out: | 513 | out: |
| 514 | if (err && p->thread.io_bitmap_ptr) { | 514 | if (err && p->thread.io_bitmap_ptr) { |
| 515 | kfree(p->thread.io_bitmap_ptr); | 515 | kfree(p->thread.io_bitmap_ptr); |
| 516 | p->thread.io_bitmap_max = 0; | 516 | p->thread.io_bitmap_max = 0; |
| 517 | } | 517 | } |
| 518 | return err; | 518 | return err; |
| 519 | } | 519 | } |
| 520 | 520 | ||
| 521 | /* | 521 | /* |
| 522 | * fill in the user structure for a core dump.. | 522 | * fill in the user structure for a core dump.. |
| 523 | */ | 523 | */ |
| 524 | void dump_thread(struct pt_regs * regs, struct user * dump) | 524 | void dump_thread(struct pt_regs * regs, struct user * dump) |
| 525 | { | 525 | { |
| 526 | int i; | 526 | int i; |
| 527 | 527 | ||
| 528 | /* changed the size calculations - should hopefully work better. lbt */ | 528 | /* changed the size calculations - should hopefully work better. lbt */ |
| 529 | dump->magic = CMAGIC; | 529 | dump->magic = CMAGIC; |
| 530 | dump->start_code = 0; | 530 | dump->start_code = 0; |
| 531 | dump->start_stack = regs->esp & ~(PAGE_SIZE - 1); | 531 | dump->start_stack = regs->esp & ~(PAGE_SIZE - 1); |
| 532 | dump->u_tsize = ((unsigned long) current->mm->end_code) >> PAGE_SHIFT; | 532 | dump->u_tsize = ((unsigned long) current->mm->end_code) >> PAGE_SHIFT; |
| 533 | dump->u_dsize = ((unsigned long) (current->mm->brk + (PAGE_SIZE-1))) >> PAGE_SHIFT; | 533 | dump->u_dsize = ((unsigned long) (current->mm->brk + (PAGE_SIZE-1))) >> PAGE_SHIFT; |
| 534 | dump->u_dsize -= dump->u_tsize; | 534 | dump->u_dsize -= dump->u_tsize; |
| 535 | dump->u_ssize = 0; | 535 | dump->u_ssize = 0; |
| 536 | for (i = 0; i < 8; i++) | 536 | for (i = 0; i < 8; i++) |
| 537 | dump->u_debugreg[i] = current->thread.debugreg[i]; | 537 | dump->u_debugreg[i] = current->thread.debugreg[i]; |
| 538 | 538 | ||
| 539 | if (dump->start_stack < TASK_SIZE) | 539 | if (dump->start_stack < TASK_SIZE) |
| 540 | dump->u_ssize = ((unsigned long) (TASK_SIZE - dump->start_stack)) >> PAGE_SHIFT; | 540 | dump->u_ssize = ((unsigned long) (TASK_SIZE - dump->start_stack)) >> PAGE_SHIFT; |
| 541 | 541 | ||
| 542 | dump->regs.ebx = regs->ebx; | 542 | dump->regs.ebx = regs->ebx; |
| 543 | dump->regs.ecx = regs->ecx; | 543 | dump->regs.ecx = regs->ecx; |
| 544 | dump->regs.edx = regs->edx; | 544 | dump->regs.edx = regs->edx; |
| 545 | dump->regs.esi = regs->esi; | 545 | dump->regs.esi = regs->esi; |
| 546 | dump->regs.edi = regs->edi; | 546 | dump->regs.edi = regs->edi; |
| 547 | dump->regs.ebp = regs->ebp; | 547 | dump->regs.ebp = regs->ebp; |
| 548 | dump->regs.eax = regs->eax; | 548 | dump->regs.eax = regs->eax; |
| 549 | dump->regs.ds = regs->xds; | 549 | dump->regs.ds = regs->xds; |
| 550 | dump->regs.es = regs->xes; | 550 | dump->regs.es = regs->xes; |
| 551 | savesegment(fs,dump->regs.fs); | 551 | savesegment(fs,dump->regs.fs); |
| 552 | savesegment(gs,dump->regs.gs); | 552 | savesegment(gs,dump->regs.gs); |
| 553 | dump->regs.orig_eax = regs->orig_eax; | 553 | dump->regs.orig_eax = regs->orig_eax; |
| 554 | dump->regs.eip = regs->eip; | 554 | dump->regs.eip = regs->eip; |
| 555 | dump->regs.cs = regs->xcs; | 555 | dump->regs.cs = regs->xcs; |
| 556 | dump->regs.eflags = regs->eflags; | 556 | dump->regs.eflags = regs->eflags; |
| 557 | dump->regs.esp = regs->esp; | 557 | dump->regs.esp = regs->esp; |
| 558 | dump->regs.ss = regs->xss; | 558 | dump->regs.ss = regs->xss; |
| 559 | 559 | ||
| 560 | dump->u_fpvalid = dump_fpu (regs, &dump->i387); | 560 | dump->u_fpvalid = dump_fpu (regs, &dump->i387); |
| 561 | } | 561 | } |
| 562 | EXPORT_SYMBOL(dump_thread); | 562 | EXPORT_SYMBOL(dump_thread); |
| 563 | 563 | ||
| 564 | /* | 564 | /* |
| 565 | * Capture the user space registers if the task is not running (in user space) | 565 | * Capture the user space registers if the task is not running (in user space) |
| 566 | */ | 566 | */ |
| 567 | int dump_task_regs(struct task_struct *tsk, elf_gregset_t *regs) | 567 | int dump_task_regs(struct task_struct *tsk, elf_gregset_t *regs) |
| 568 | { | 568 | { |
| 569 | struct pt_regs ptregs; | 569 | struct pt_regs ptregs; |
| 570 | 570 | ||
| 571 | ptregs = *(struct pt_regs *) | 571 | ptregs = *(struct pt_regs *) |
| 572 | ((unsigned long)tsk->thread_info+THREAD_SIZE - sizeof(ptregs)); | 572 | ((unsigned long)tsk->thread_info+THREAD_SIZE - sizeof(ptregs)); |
| 573 | ptregs.xcs &= 0xffff; | 573 | ptregs.xcs &= 0xffff; |
| 574 | ptregs.xds &= 0xffff; | 574 | ptregs.xds &= 0xffff; |
| 575 | ptregs.xes &= 0xffff; | 575 | ptregs.xes &= 0xffff; |
| 576 | ptregs.xss &= 0xffff; | 576 | ptregs.xss &= 0xffff; |
| 577 | 577 | ||
| 578 | elf_core_copy_regs(regs, &ptregs); | 578 | elf_core_copy_regs(regs, &ptregs); |
| 579 | 579 | ||
| 580 | return 1; | 580 | return 1; |
| 581 | } | 581 | } |
| 582 | 582 | ||
| 583 | static inline void | 583 | static inline void |
| 584 | handle_io_bitmap(struct thread_struct *next, struct tss_struct *tss) | 584 | handle_io_bitmap(struct thread_struct *next, struct tss_struct *tss) |
| 585 | { | 585 | { |
| 586 | if (!next->io_bitmap_ptr) { | 586 | if (!next->io_bitmap_ptr) { |
| 587 | /* | 587 | /* |
| 588 | * Disable the bitmap via an invalid offset. We still cache | 588 | * Disable the bitmap via an invalid offset. We still cache |
| 589 | * the previous bitmap owner and the IO bitmap contents: | 589 | * the previous bitmap owner and the IO bitmap contents: |
| 590 | */ | 590 | */ |
| 591 | tss->io_bitmap_base = INVALID_IO_BITMAP_OFFSET; | 591 | tss->io_bitmap_base = INVALID_IO_BITMAP_OFFSET; |
| 592 | return; | 592 | return; |
| 593 | } | 593 | } |
| 594 | if (likely(next == tss->io_bitmap_owner)) { | 594 | if (likely(next == tss->io_bitmap_owner)) { |
| 595 | /* | 595 | /* |
| 596 | * Previous owner of the bitmap (hence the bitmap content) | 596 | * Previous owner of the bitmap (hence the bitmap content) |
| 597 | * matches the next task, we dont have to do anything but | 597 | * matches the next task, we dont have to do anything but |
| 598 | * to set a valid offset in the TSS: | 598 | * to set a valid offset in the TSS: |
| 599 | */ | 599 | */ |
| 600 | tss->io_bitmap_base = IO_BITMAP_OFFSET; | 600 | tss->io_bitmap_base = IO_BITMAP_OFFSET; |
| 601 | return; | 601 | return; |
| 602 | } | 602 | } |
| 603 | /* | 603 | /* |
| 604 | * Lazy TSS's I/O bitmap copy. We set an invalid offset here | 604 | * Lazy TSS's I/O bitmap copy. We set an invalid offset here |
| 605 | * and we let the task to get a GPF in case an I/O instruction | 605 | * and we let the task to get a GPF in case an I/O instruction |
| 606 | * is performed. The handler of the GPF will verify that the | 606 | * is performed. The handler of the GPF will verify that the |
| 607 | * faulting task has a valid I/O bitmap and, it true, does the | 607 | * faulting task has a valid I/O bitmap and, it true, does the |
| 608 | * real copy and restart the instruction. This will save us | 608 | * real copy and restart the instruction. This will save us |
| 609 | * redundant copies when the currently switched task does not | 609 | * redundant copies when the currently switched task does not |
| 610 | * perform any I/O during its timeslice. | 610 | * perform any I/O during its timeslice. |
| 611 | */ | 611 | */ |
| 612 | tss->io_bitmap_base = INVALID_IO_BITMAP_OFFSET_LAZY; | 612 | tss->io_bitmap_base = INVALID_IO_BITMAP_OFFSET_LAZY; |
| 613 | } | 613 | } |
| 614 | 614 | ||
| 615 | /* | 615 | /* |
| 616 | * This function selects if the context switch from prev to next | 616 | * This function selects if the context switch from prev to next |
| 617 | * has to tweak the TSC disable bit in the cr4. | 617 | * has to tweak the TSC disable bit in the cr4. |
| 618 | */ | 618 | */ |
| 619 | static inline void disable_tsc(struct task_struct *prev_p, | 619 | static inline void disable_tsc(struct task_struct *prev_p, |
| 620 | struct task_struct *next_p) | 620 | struct task_struct *next_p) |
| 621 | { | 621 | { |
| 622 | struct thread_info *prev, *next; | 622 | struct thread_info *prev, *next; |
| 623 | 623 | ||
| 624 | /* | 624 | /* |
| 625 | * gcc should eliminate the ->thread_info dereference if | 625 | * gcc should eliminate the ->thread_info dereference if |
| 626 | * has_secure_computing returns 0 at compile time (SECCOMP=n). | 626 | * has_secure_computing returns 0 at compile time (SECCOMP=n). |
| 627 | */ | 627 | */ |
| 628 | prev = prev_p->thread_info; | 628 | prev = prev_p->thread_info; |
| 629 | next = next_p->thread_info; | 629 | next = next_p->thread_info; |
| 630 | 630 | ||
| 631 | if (has_secure_computing(prev) || has_secure_computing(next)) { | 631 | if (has_secure_computing(prev) || has_secure_computing(next)) { |
| 632 | /* slow path here */ | 632 | /* slow path here */ |
| 633 | if (has_secure_computing(prev) && | 633 | if (has_secure_computing(prev) && |
| 634 | !has_secure_computing(next)) { | 634 | !has_secure_computing(next)) { |
| 635 | write_cr4(read_cr4() & ~X86_CR4_TSD); | 635 | write_cr4(read_cr4() & ~X86_CR4_TSD); |
| 636 | } else if (!has_secure_computing(prev) && | 636 | } else if (!has_secure_computing(prev) && |
| 637 | has_secure_computing(next)) | 637 | has_secure_computing(next)) |
| 638 | write_cr4(read_cr4() | X86_CR4_TSD); | 638 | write_cr4(read_cr4() | X86_CR4_TSD); |
| 639 | } | 639 | } |
| 640 | } | 640 | } |
| 641 | 641 | ||
| 642 | /* | 642 | /* |
| 643 | * switch_to(x,yn) should switch tasks from x to y. | 643 | * switch_to(x,yn) should switch tasks from x to y. |
| 644 | * | 644 | * |
| 645 | * We fsave/fwait so that an exception goes off at the right time | 645 | * We fsave/fwait so that an exception goes off at the right time |
| 646 | * (as a call from the fsave or fwait in effect) rather than to | 646 | * (as a call from the fsave or fwait in effect) rather than to |
| 647 | * the wrong process. Lazy FP saving no longer makes any sense | 647 | * the wrong process. Lazy FP saving no longer makes any sense |
| 648 | * with modern CPU's, and this simplifies a lot of things (SMP | 648 | * with modern CPU's, and this simplifies a lot of things (SMP |
| 649 | * and UP become the same). | 649 | * and UP become the same). |
| 650 | * | 650 | * |
| 651 | * NOTE! We used to use the x86 hardware context switching. The | 651 | * NOTE! We used to use the x86 hardware context switching. The |
| 652 | * reason for not using it any more becomes apparent when you | 652 | * reason for not using it any more becomes apparent when you |
| 653 | * try to recover gracefully from saved state that is no longer | 653 | * try to recover gracefully from saved state that is no longer |
| 654 | * valid (stale segment register values in particular). With the | 654 | * valid (stale segment register values in particular). With the |
| 655 | * hardware task-switch, there is no way to fix up bad state in | 655 | * hardware task-switch, there is no way to fix up bad state in |
| 656 | * a reasonable manner. | 656 | * a reasonable manner. |
| 657 | * | 657 | * |
| 658 | * The fact that Intel documents the hardware task-switching to | 658 | * The fact that Intel documents the hardware task-switching to |
| 659 | * be slow is a fairly red herring - this code is not noticeably | 659 | * be slow is a fairly red herring - this code is not noticeably |
| 660 | * faster. However, there _is_ some room for improvement here, | 660 | * faster. However, there _is_ some room for improvement here, |
| 661 | * so the performance issues may eventually be a valid point. | 661 | * so the performance issues may eventually be a valid point. |
| 662 | * More important, however, is the fact that this allows us much | 662 | * More important, however, is the fact that this allows us much |
| 663 | * more flexibility. | 663 | * more flexibility. |
| 664 | * | 664 | * |
| 665 | * The return value (in %eax) will be the "prev" task after | 665 | * The return value (in %eax) will be the "prev" task after |
| 666 | * the task-switch, and shows up in ret_from_fork in entry.S, | 666 | * the task-switch, and shows up in ret_from_fork in entry.S, |
| 667 | * for example. | 667 | * for example. |
| 668 | */ | 668 | */ |
| 669 | struct task_struct fastcall * __switch_to(struct task_struct *prev_p, struct task_struct *next_p) | 669 | struct task_struct fastcall * __switch_to(struct task_struct *prev_p, struct task_struct *next_p) |
| 670 | { | 670 | { |
| 671 | struct thread_struct *prev = &prev_p->thread, | 671 | struct thread_struct *prev = &prev_p->thread, |
| 672 | *next = &next_p->thread; | 672 | *next = &next_p->thread; |
| 673 | int cpu = smp_processor_id(); | 673 | int cpu = smp_processor_id(); |
| 674 | struct tss_struct *tss = &per_cpu(init_tss, cpu); | 674 | struct tss_struct *tss = &per_cpu(init_tss, cpu); |
| 675 | 675 | ||
| 676 | /* never put a printk in __switch_to... printk() calls wake_up*() indirectly */ | 676 | /* never put a printk in __switch_to... printk() calls wake_up*() indirectly */ |
| 677 | 677 | ||
| 678 | __unlazy_fpu(prev_p); | 678 | __unlazy_fpu(prev_p); |
| 679 | 679 | ||
| 680 | /* | 680 | /* |
| 681 | * Reload esp0. | 681 | * Reload esp0. |
| 682 | */ | 682 | */ |
| 683 | load_esp0(tss, next); | 683 | load_esp0(tss, next); |
| 684 | 684 | ||
| 685 | /* | 685 | /* |
| 686 | * Save away %fs and %gs. No need to save %es and %ds, as | 686 | * Save away %fs and %gs. No need to save %es and %ds, as |
| 687 | * those are always kernel segments while inside the kernel. | 687 | * those are always kernel segments while inside the kernel. |
| 688 | * Doing this before setting the new TLS descriptors avoids | 688 | * Doing this before setting the new TLS descriptors avoids |
| 689 | * the situation where we temporarily have non-reloadable | 689 | * the situation where we temporarily have non-reloadable |
| 690 | * segments in %fs and %gs. This could be an issue if the | 690 | * segments in %fs and %gs. This could be an issue if the |
| 691 | * NMI handler ever used %fs or %gs (it does not today), or | 691 | * NMI handler ever used %fs or %gs (it does not today), or |
| 692 | * if the kernel is running inside of a hypervisor layer. | 692 | * if the kernel is running inside of a hypervisor layer. |
| 693 | */ | 693 | */ |
| 694 | savesegment(fs, prev->fs); | 694 | savesegment(fs, prev->fs); |
| 695 | savesegment(gs, prev->gs); | 695 | savesegment(gs, prev->gs); |
| 696 | 696 | ||
| 697 | /* | 697 | /* |
| 698 | * Load the per-thread Thread-Local Storage descriptor. | 698 | * Load the per-thread Thread-Local Storage descriptor. |
| 699 | */ | 699 | */ |
| 700 | load_TLS(next, cpu); | 700 | load_TLS(next, cpu); |
| 701 | 701 | ||
| 702 | /* | 702 | /* |
| 703 | * Restore %fs and %gs if needed. | 703 | * Restore %fs and %gs if needed. |
| 704 | * | 704 | * |
| 705 | * Glibc normally makes %fs be zero, and %gs is one of | 705 | * Glibc normally makes %fs be zero, and %gs is one of |
| 706 | * the TLS segments. | 706 | * the TLS segments. |
| 707 | */ | 707 | */ |
| 708 | if (unlikely(prev->fs | next->fs)) | 708 | if (unlikely(prev->fs | next->fs)) |
| 709 | loadsegment(fs, next->fs); | 709 | loadsegment(fs, next->fs); |
| 710 | 710 | ||
| 711 | if (prev->gs | next->gs) | 711 | if (prev->gs | next->gs) |
| 712 | loadsegment(gs, next->gs); | 712 | loadsegment(gs, next->gs); |
| 713 | 713 | ||
| 714 | /* | 714 | /* |
| 715 | * Now maybe reload the debug registers | 715 | * Now maybe reload the debug registers |
| 716 | */ | 716 | */ |
| 717 | if (unlikely(next->debugreg[7])) { | 717 | if (unlikely(next->debugreg[7])) { |
| 718 | set_debugreg(next->debugreg[0], 0); | 718 | set_debugreg(next->debugreg[0], 0); |
| 719 | set_debugreg(next->debugreg[1], 1); | 719 | set_debugreg(next->debugreg[1], 1); |
| 720 | set_debugreg(next->debugreg[2], 2); | 720 | set_debugreg(next->debugreg[2], 2); |
| 721 | set_debugreg(next->debugreg[3], 3); | 721 | set_debugreg(next->debugreg[3], 3); |
| 722 | /* no 4 and 5 */ | 722 | /* no 4 and 5 */ |
| 723 | set_debugreg(next->debugreg[6], 6); | 723 | set_debugreg(next->debugreg[6], 6); |
| 724 | set_debugreg(next->debugreg[7], 7); | 724 | set_debugreg(next->debugreg[7], 7); |
| 725 | } | 725 | } |
| 726 | 726 | ||
| 727 | if (unlikely(prev->io_bitmap_ptr || next->io_bitmap_ptr)) | 727 | if (unlikely(prev->io_bitmap_ptr || next->io_bitmap_ptr)) |
| 728 | handle_io_bitmap(next, tss); | 728 | handle_io_bitmap(next, tss); |
| 729 | 729 | ||
| 730 | disable_tsc(prev_p, next_p); | 730 | disable_tsc(prev_p, next_p); |
| 731 | 731 | ||
| 732 | return prev_p; | 732 | return prev_p; |
| 733 | } | 733 | } |
| 734 | 734 | ||
| 735 | asmlinkage int sys_fork(struct pt_regs regs) | 735 | asmlinkage int sys_fork(struct pt_regs regs) |
| 736 | { | 736 | { |
| 737 | return do_fork(SIGCHLD, regs.esp, ®s, 0, NULL, NULL); | 737 | return do_fork(SIGCHLD, regs.esp, ®s, 0, NULL, NULL); |
| 738 | } | 738 | } |
| 739 | 739 | ||
| 740 | asmlinkage int sys_clone(struct pt_regs regs) | 740 | asmlinkage int sys_clone(struct pt_regs regs) |
| 741 | { | 741 | { |
| 742 | unsigned long clone_flags; | 742 | unsigned long clone_flags; |
| 743 | unsigned long newsp; | 743 | unsigned long newsp; |
| 744 | int __user *parent_tidptr, *child_tidptr; | 744 | int __user *parent_tidptr, *child_tidptr; |
| 745 | 745 | ||
| 746 | clone_flags = regs.ebx; | 746 | clone_flags = regs.ebx; |
| 747 | newsp = regs.ecx; | 747 | newsp = regs.ecx; |
| 748 | parent_tidptr = (int __user *)regs.edx; | 748 | parent_tidptr = (int __user *)regs.edx; |
| 749 | child_tidptr = (int __user *)regs.edi; | 749 | child_tidptr = (int __user *)regs.edi; |
| 750 | if (!newsp) | 750 | if (!newsp) |
| 751 | newsp = regs.esp; | 751 | newsp = regs.esp; |
| 752 | return do_fork(clone_flags, newsp, ®s, 0, parent_tidptr, child_tidptr); | 752 | return do_fork(clone_flags, newsp, ®s, 0, parent_tidptr, child_tidptr); |
| 753 | } | 753 | } |
| 754 | 754 | ||
| 755 | /* | 755 | /* |
| 756 | * This is trivial, and on the face of it looks like it | 756 | * This is trivial, and on the face of it looks like it |
| 757 | * could equally well be done in user mode. | 757 | * could equally well be done in user mode. |
| 758 | * | 758 | * |
| 759 | * Not so, for quite unobvious reasons - register pressure. | 759 | * Not so, for quite unobvious reasons - register pressure. |
| 760 | * In user mode vfork() cannot have a stack frame, and if | 760 | * In user mode vfork() cannot have a stack frame, and if |
| 761 | * done by calling the "clone()" system call directly, you | 761 | * done by calling the "clone()" system call directly, you |
| 762 | * do not have enough call-clobbered registers to hold all | 762 | * do not have enough call-clobbered registers to hold all |
| 763 | * the information you need. | 763 | * the information you need. |
| 764 | */ | 764 | */ |
| 765 | asmlinkage int sys_vfork(struct pt_regs regs) | 765 | asmlinkage int sys_vfork(struct pt_regs regs) |
| 766 | { | 766 | { |
| 767 | return do_fork(CLONE_VFORK | CLONE_VM | SIGCHLD, regs.esp, ®s, 0, NULL, NULL); | 767 | return do_fork(CLONE_VFORK | CLONE_VM | SIGCHLD, regs.esp, ®s, 0, NULL, NULL); |
| 768 | } | 768 | } |
| 769 | 769 | ||
| 770 | /* | 770 | /* |
| 771 | * sys_execve() executes a new program. | 771 | * sys_execve() executes a new program. |
| 772 | */ | 772 | */ |
| 773 | asmlinkage int sys_execve(struct pt_regs regs) | 773 | asmlinkage int sys_execve(struct pt_regs regs) |
| 774 | { | 774 | { |
| 775 | int error; | 775 | int error; |
| 776 | char * filename; | 776 | char * filename; |
| 777 | 777 | ||
| 778 | filename = getname((char __user *) regs.ebx); | 778 | filename = getname((char __user *) regs.ebx); |
| 779 | error = PTR_ERR(filename); | 779 | error = PTR_ERR(filename); |
| 780 | if (IS_ERR(filename)) | 780 | if (IS_ERR(filename)) |
| 781 | goto out; | 781 | goto out; |
| 782 | error = do_execve(filename, | 782 | error = do_execve(filename, |
| 783 | (char __user * __user *) regs.ecx, | 783 | (char __user * __user *) regs.ecx, |
| 784 | (char __user * __user *) regs.edx, | 784 | (char __user * __user *) regs.edx, |
| 785 | ®s); | 785 | ®s); |
| 786 | if (error == 0) { | 786 | if (error == 0) { |
| 787 | task_lock(current); | 787 | task_lock(current); |
| 788 | current->ptrace &= ~PT_DTRACE; | 788 | current->ptrace &= ~PT_DTRACE; |
| 789 | task_unlock(current); | 789 | task_unlock(current); |
| 790 | /* Make sure we don't return using sysenter.. */ | 790 | /* Make sure we don't return using sysenter.. */ |
| 791 | set_thread_flag(TIF_IRET); | 791 | set_thread_flag(TIF_IRET); |
| 792 | } | 792 | } |
| 793 | putname(filename); | 793 | putname(filename); |
| 794 | out: | 794 | out: |
| 795 | return error; | 795 | return error; |
| 796 | } | 796 | } |
| 797 | 797 | ||
| 798 | #define top_esp (THREAD_SIZE - sizeof(unsigned long)) | 798 | #define top_esp (THREAD_SIZE - sizeof(unsigned long)) |
| 799 | #define top_ebp (THREAD_SIZE - 2*sizeof(unsigned long)) | 799 | #define top_ebp (THREAD_SIZE - 2*sizeof(unsigned long)) |
| 800 | 800 | ||
| 801 | unsigned long get_wchan(struct task_struct *p) | 801 | unsigned long get_wchan(struct task_struct *p) |
| 802 | { | 802 | { |
| 803 | unsigned long ebp, esp, eip; | 803 | unsigned long ebp, esp, eip; |
| 804 | unsigned long stack_page; | 804 | unsigned long stack_page; |
| 805 | int count = 0; | 805 | int count = 0; |
| 806 | if (!p || p == current || p->state == TASK_RUNNING) | 806 | if (!p || p == current || p->state == TASK_RUNNING) |
| 807 | return 0; | 807 | return 0; |
| 808 | stack_page = (unsigned long)p->thread_info; | 808 | stack_page = (unsigned long)p->thread_info; |
| 809 | esp = p->thread.esp; | 809 | esp = p->thread.esp; |
| 810 | if (!stack_page || esp < stack_page || esp > top_esp+stack_page) | 810 | if (!stack_page || esp < stack_page || esp > top_esp+stack_page) |
| 811 | return 0; | 811 | return 0; |
| 812 | /* include/asm-i386/system.h:switch_to() pushes ebp last. */ | 812 | /* include/asm-i386/system.h:switch_to() pushes ebp last. */ |
| 813 | ebp = *(unsigned long *) esp; | 813 | ebp = *(unsigned long *) esp; |
| 814 | do { | 814 | do { |
| 815 | if (ebp < stack_page || ebp > top_ebp+stack_page) | 815 | if (ebp < stack_page || ebp > top_ebp+stack_page) |
| 816 | return 0; | 816 | return 0; |
| 817 | eip = *(unsigned long *) (ebp+4); | 817 | eip = *(unsigned long *) (ebp+4); |
| 818 | if (!in_sched_functions(eip)) | 818 | if (!in_sched_functions(eip)) |
| 819 | return eip; | 819 | return eip; |
| 820 | ebp = *(unsigned long *) ebp; | 820 | ebp = *(unsigned long *) ebp; |
| 821 | } while (count++ < 16); | 821 | } while (count++ < 16); |
| 822 | return 0; | 822 | return 0; |
| 823 | } | 823 | } |
| 824 | EXPORT_SYMBOL(get_wchan); | 824 | EXPORT_SYMBOL(get_wchan); |
| 825 | 825 | ||
| 826 | /* | 826 | /* |
| 827 | * sys_alloc_thread_area: get a yet unused TLS descriptor index. | 827 | * sys_alloc_thread_area: get a yet unused TLS descriptor index. |
| 828 | */ | 828 | */ |
| 829 | static int get_free_idx(void) | 829 | static int get_free_idx(void) |
| 830 | { | 830 | { |
| 831 | struct thread_struct *t = ¤t->thread; | 831 | struct thread_struct *t = ¤t->thread; |
| 832 | int idx; | 832 | int idx; |
| 833 | 833 | ||
| 834 | for (idx = 0; idx < GDT_ENTRY_TLS_ENTRIES; idx++) | 834 | for (idx = 0; idx < GDT_ENTRY_TLS_ENTRIES; idx++) |
| 835 | if (desc_empty(t->tls_array + idx)) | 835 | if (desc_empty(t->tls_array + idx)) |
| 836 | return idx + GDT_ENTRY_TLS_MIN; | 836 | return idx + GDT_ENTRY_TLS_MIN; |
| 837 | return -ESRCH; | 837 | return -ESRCH; |
| 838 | } | 838 | } |
| 839 | 839 | ||
| 840 | /* | 840 | /* |
| 841 | * Set a given TLS descriptor: | 841 | * Set a given TLS descriptor: |
| 842 | */ | 842 | */ |
| 843 | asmlinkage int sys_set_thread_area(struct user_desc __user *u_info) | 843 | asmlinkage int sys_set_thread_area(struct user_desc __user *u_info) |
| 844 | { | 844 | { |
| 845 | struct thread_struct *t = ¤t->thread; | 845 | struct thread_struct *t = ¤t->thread; |
| 846 | struct user_desc info; | 846 | struct user_desc info; |
| 847 | struct desc_struct *desc; | 847 | struct desc_struct *desc; |
| 848 | int cpu, idx; | 848 | int cpu, idx; |
| 849 | 849 | ||
| 850 | if (copy_from_user(&info, u_info, sizeof(info))) | 850 | if (copy_from_user(&info, u_info, sizeof(info))) |
| 851 | return -EFAULT; | 851 | return -EFAULT; |
| 852 | idx = info.entry_number; | 852 | idx = info.entry_number; |
| 853 | 853 | ||
| 854 | /* | 854 | /* |
| 855 | * index -1 means the kernel should try to find and | 855 | * index -1 means the kernel should try to find and |
| 856 | * allocate an empty descriptor: | 856 | * allocate an empty descriptor: |
| 857 | */ | 857 | */ |
| 858 | if (idx == -1) { | 858 | if (idx == -1) { |
| 859 | idx = get_free_idx(); | 859 | idx = get_free_idx(); |
| 860 | if (idx < 0) | 860 | if (idx < 0) |
| 861 | return idx; | 861 | return idx; |
| 862 | if (put_user(idx, &u_info->entry_number)) | 862 | if (put_user(idx, &u_info->entry_number)) |
| 863 | return -EFAULT; | 863 | return -EFAULT; |
| 864 | } | 864 | } |
| 865 | 865 | ||
| 866 | if (idx < GDT_ENTRY_TLS_MIN || idx > GDT_ENTRY_TLS_MAX) | 866 | if (idx < GDT_ENTRY_TLS_MIN || idx > GDT_ENTRY_TLS_MAX) |
| 867 | return -EINVAL; | 867 | return -EINVAL; |
| 868 | 868 | ||
| 869 | desc = t->tls_array + idx - GDT_ENTRY_TLS_MIN; | 869 | desc = t->tls_array + idx - GDT_ENTRY_TLS_MIN; |
| 870 | 870 | ||
| 871 | /* | 871 | /* |
| 872 | * We must not get preempted while modifying the TLS. | 872 | * We must not get preempted while modifying the TLS. |
| 873 | */ | 873 | */ |
| 874 | cpu = get_cpu(); | 874 | cpu = get_cpu(); |
| 875 | 875 | ||
| 876 | if (LDT_empty(&info)) { | 876 | if (LDT_empty(&info)) { |
| 877 | desc->a = 0; | 877 | desc->a = 0; |
| 878 | desc->b = 0; | 878 | desc->b = 0; |
| 879 | } else { | 879 | } else { |
| 880 | desc->a = LDT_entry_a(&info); | 880 | desc->a = LDT_entry_a(&info); |
| 881 | desc->b = LDT_entry_b(&info); | 881 | desc->b = LDT_entry_b(&info); |
| 882 | } | 882 | } |
| 883 | load_TLS(t, cpu); | 883 | load_TLS(t, cpu); |
| 884 | 884 | ||
| 885 | put_cpu(); | 885 | put_cpu(); |
| 886 | 886 | ||
| 887 | return 0; | 887 | return 0; |
| 888 | } | 888 | } |
| 889 | 889 | ||
| 890 | /* | 890 | /* |
| 891 | * Get the current Thread-Local Storage area: | 891 | * Get the current Thread-Local Storage area: |
| 892 | */ | 892 | */ |
| 893 | 893 | ||
| 894 | #define GET_BASE(desc) ( \ | 894 | #define GET_BASE(desc) ( \ |
| 895 | (((desc)->a >> 16) & 0x0000ffff) | \ | 895 | (((desc)->a >> 16) & 0x0000ffff) | \ |
| 896 | (((desc)->b << 16) & 0x00ff0000) | \ | 896 | (((desc)->b << 16) & 0x00ff0000) | \ |
| 897 | ( (desc)->b & 0xff000000) ) | 897 | ( (desc)->b & 0xff000000) ) |
| 898 | 898 | ||
| 899 | #define GET_LIMIT(desc) ( \ | 899 | #define GET_LIMIT(desc) ( \ |
| 900 | ((desc)->a & 0x0ffff) | \ | 900 | ((desc)->a & 0x0ffff) | \ |
| 901 | ((desc)->b & 0xf0000) ) | 901 | ((desc)->b & 0xf0000) ) |
| 902 | 902 | ||
| 903 | #define GET_32BIT(desc) (((desc)->b >> 22) & 1) | 903 | #define GET_32BIT(desc) (((desc)->b >> 22) & 1) |
| 904 | #define GET_CONTENTS(desc) (((desc)->b >> 10) & 3) | 904 | #define GET_CONTENTS(desc) (((desc)->b >> 10) & 3) |
| 905 | #define GET_WRITABLE(desc) (((desc)->b >> 9) & 1) | 905 | #define GET_WRITABLE(desc) (((desc)->b >> 9) & 1) |
| 906 | #define GET_LIMIT_PAGES(desc) (((desc)->b >> 23) & 1) | 906 | #define GET_LIMIT_PAGES(desc) (((desc)->b >> 23) & 1) |
| 907 | #define GET_PRESENT(desc) (((desc)->b >> 15) & 1) | 907 | #define GET_PRESENT(desc) (((desc)->b >> 15) & 1) |
| 908 | #define GET_USEABLE(desc) (((desc)->b >> 20) & 1) | 908 | #define GET_USEABLE(desc) (((desc)->b >> 20) & 1) |
| 909 | 909 | ||
| 910 | asmlinkage int sys_get_thread_area(struct user_desc __user *u_info) | 910 | asmlinkage int sys_get_thread_area(struct user_desc __user *u_info) |
| 911 | { | 911 | { |
| 912 | struct user_desc info; | 912 | struct user_desc info; |
| 913 | struct desc_struct *desc; | 913 | struct desc_struct *desc; |
| 914 | int idx; | 914 | int idx; |
| 915 | 915 | ||
| 916 | if (get_user(idx, &u_info->entry_number)) | 916 | if (get_user(idx, &u_info->entry_number)) |
| 917 | return -EFAULT; | 917 | return -EFAULT; |
| 918 | if (idx < GDT_ENTRY_TLS_MIN || idx > GDT_ENTRY_TLS_MAX) | 918 | if (idx < GDT_ENTRY_TLS_MIN || idx > GDT_ENTRY_TLS_MAX) |
| 919 | return -EINVAL; | 919 | return -EINVAL; |
| 920 | 920 | ||
| 921 | memset(&info, 0, sizeof(info)); | 921 | memset(&info, 0, sizeof(info)); |
| 922 | 922 | ||
| 923 | desc = current->thread.tls_array + idx - GDT_ENTRY_TLS_MIN; | 923 | desc = current->thread.tls_array + idx - GDT_ENTRY_TLS_MIN; |
| 924 | 924 | ||
| 925 | info.entry_number = idx; | 925 | info.entry_number = idx; |
| 926 | info.base_addr = GET_BASE(desc); | 926 | info.base_addr = GET_BASE(desc); |
| 927 | info.limit = GET_LIMIT(desc); | 927 | info.limit = GET_LIMIT(desc); |
| 928 | info.seg_32bit = GET_32BIT(desc); | 928 | info.seg_32bit = GET_32BIT(desc); |
| 929 | info.contents = GET_CONTENTS(desc); | 929 | info.contents = GET_CONTENTS(desc); |
| 930 | info.read_exec_only = !GET_WRITABLE(desc); | 930 | info.read_exec_only = !GET_WRITABLE(desc); |
| 931 | info.limit_in_pages = GET_LIMIT_PAGES(desc); | 931 | info.limit_in_pages = GET_LIMIT_PAGES(desc); |
| 932 | info.seg_not_present = !GET_PRESENT(desc); | 932 | info.seg_not_present = !GET_PRESENT(desc); |
| 933 | info.useable = GET_USEABLE(desc); | 933 | info.useable = GET_USEABLE(desc); |
| 934 | 934 | ||
| 935 | if (copy_to_user(u_info, &info, sizeof(info))) | 935 | if (copy_to_user(u_info, &info, sizeof(info))) |
| 936 | return -EFAULT; | 936 | return -EFAULT; |
| 937 | return 0; | 937 | return 0; |
| 938 | } | 938 | } |
| 939 | 939 | ||
| 940 | unsigned long arch_align_stack(unsigned long sp) | 940 | unsigned long arch_align_stack(unsigned long sp) |
| 941 | { | 941 | { |
| 942 | if (randomize_va_space) | 942 | if (randomize_va_space) |
| 943 | sp -= get_random_int() % 8192; | 943 | sp -= get_random_int() % 8192; |
| 944 | return sp & ~0xf; | 944 | return sp & ~0xf; |
| 945 | } | 945 | } |
| 946 | 946 |
arch/i386/mach-voyager/voyager_basic.c
| 1 | /* Copyright (C) 1999,2001 | 1 | /* Copyright (C) 1999,2001 |
| 2 | * | 2 | * |
| 3 | * Author: J.E.J.Bottomley@HansenPartnership.com | 3 | * Author: J.E.J.Bottomley@HansenPartnership.com |
| 4 | * | 4 | * |
| 5 | * linux/arch/i386/kernel/voyager.c | 5 | * linux/arch/i386/kernel/voyager.c |
| 6 | * | 6 | * |
| 7 | * This file contains all the voyager specific routines for getting | 7 | * This file contains all the voyager specific routines for getting |
| 8 | * initialisation of the architecture to function. For additional | 8 | * initialisation of the architecture to function. For additional |
| 9 | * features see: | 9 | * features see: |
| 10 | * | 10 | * |
| 11 | * voyager_cat.c - Voyager CAT bus interface | 11 | * voyager_cat.c - Voyager CAT bus interface |
| 12 | * voyager_smp.c - Voyager SMP hal (emulates linux smp.c) | 12 | * voyager_smp.c - Voyager SMP hal (emulates linux smp.c) |
| 13 | */ | 13 | */ |
| 14 | 14 | ||
| 15 | #include <linux/config.h> | 15 | #include <linux/config.h> |
| 16 | #include <linux/module.h> | 16 | #include <linux/module.h> |
| 17 | #include <linux/types.h> | 17 | #include <linux/types.h> |
| 18 | #include <linux/sched.h> | 18 | #include <linux/sched.h> |
| 19 | #include <linux/ptrace.h> | 19 | #include <linux/ptrace.h> |
| 20 | #include <linux/ioport.h> | 20 | #include <linux/ioport.h> |
| 21 | #include <linux/interrupt.h> | 21 | #include <linux/interrupt.h> |
| 22 | #include <linux/init.h> | 22 | #include <linux/init.h> |
| 23 | #include <linux/delay.h> | 23 | #include <linux/delay.h> |
| 24 | #include <linux/reboot.h> | 24 | #include <linux/reboot.h> |
| 25 | #include <linux/sysrq.h> | 25 | #include <linux/sysrq.h> |
| 26 | #include <asm/io.h> | 26 | #include <asm/io.h> |
| 27 | #include <asm/voyager.h> | 27 | #include <asm/voyager.h> |
| 28 | #include <asm/vic.h> | 28 | #include <asm/vic.h> |
| 29 | #include <linux/pm.h> | 29 | #include <linux/pm.h> |
| 30 | #include <linux/irq.h> | 30 | #include <linux/irq.h> |
| 31 | #include <asm/tlbflush.h> | 31 | #include <asm/tlbflush.h> |
| 32 | #include <asm/arch_hooks.h> | 32 | #include <asm/arch_hooks.h> |
| 33 | #include <asm/i8253.h> | 33 | #include <asm/i8253.h> |
| 34 | 34 | ||
| 35 | /* | 35 | /* |
| 36 | * Power off function, if any | 36 | * Power off function, if any |
| 37 | */ | 37 | */ |
| 38 | void (*pm_power_off)(void); | 38 | void (*pm_power_off)(void); |
| 39 | EXPORT_SYMBOL(pm_power_off); | 39 | EXPORT_SYMBOL(pm_power_off); |
| 40 | 40 | ||
| 41 | int voyager_level = 0; | 41 | int voyager_level = 0; |
| 42 | 42 | ||
| 43 | struct voyager_SUS *voyager_SUS = NULL; | 43 | struct voyager_SUS *voyager_SUS = NULL; |
| 44 | 44 | ||
| 45 | #ifdef CONFIG_SMP | 45 | #ifdef CONFIG_SMP |
| 46 | static void | 46 | static void |
| 47 | voyager_dump(int dummy1, struct pt_regs *dummy2, struct tty_struct *dummy3) | 47 | voyager_dump(int dummy1, struct pt_regs *dummy2, struct tty_struct *dummy3) |
| 48 | { | 48 | { |
| 49 | /* get here via a sysrq */ | 49 | /* get here via a sysrq */ |
| 50 | voyager_smp_dump(); | 50 | voyager_smp_dump(); |
| 51 | } | 51 | } |
| 52 | 52 | ||
| 53 | static struct sysrq_key_op sysrq_voyager_dump_op = { | 53 | static struct sysrq_key_op sysrq_voyager_dump_op = { |
| 54 | .handler = voyager_dump, | 54 | .handler = voyager_dump, |
| 55 | .help_msg = "Voyager", | 55 | .help_msg = "Voyager", |
| 56 | .action_msg = "Dump Voyager Status", | 56 | .action_msg = "Dump Voyager Status", |
| 57 | }; | 57 | }; |
| 58 | #endif | 58 | #endif |
| 59 | 59 | ||
| 60 | void | 60 | void |
| 61 | voyager_detect(struct voyager_bios_info *bios) | 61 | voyager_detect(struct voyager_bios_info *bios) |
| 62 | { | 62 | { |
| 63 | if(bios->len != 0xff) { | 63 | if(bios->len != 0xff) { |
| 64 | int class = (bios->class_1 << 8) | 64 | int class = (bios->class_1 << 8) |
| 65 | | (bios->class_2 & 0xff); | 65 | | (bios->class_2 & 0xff); |
| 66 | 66 | ||
| 67 | printk("Voyager System detected.\n" | 67 | printk("Voyager System detected.\n" |
| 68 | " Class %x, Revision %d.%d\n", | 68 | " Class %x, Revision %d.%d\n", |
| 69 | class, bios->major, bios->minor); | 69 | class, bios->major, bios->minor); |
| 70 | if(class == VOYAGER_LEVEL4) | 70 | if(class == VOYAGER_LEVEL4) |
| 71 | voyager_level = 4; | 71 | voyager_level = 4; |
| 72 | else if(class < VOYAGER_LEVEL5_AND_ABOVE) | 72 | else if(class < VOYAGER_LEVEL5_AND_ABOVE) |
| 73 | voyager_level = 3; | 73 | voyager_level = 3; |
| 74 | else | 74 | else |
| 75 | voyager_level = 5; | 75 | voyager_level = 5; |
| 76 | printk(" Architecture Level %d\n", voyager_level); | 76 | printk(" Architecture Level %d\n", voyager_level); |
| 77 | if(voyager_level < 4) | 77 | if(voyager_level < 4) |
| 78 | printk("\n**WARNING**: Voyager HAL only supports Levels 4 and 5 Architectures at the moment\n\n"); | 78 | printk("\n**WARNING**: Voyager HAL only supports Levels 4 and 5 Architectures at the moment\n\n"); |
| 79 | /* install the power off handler */ | 79 | /* install the power off handler */ |
| 80 | pm_power_off = voyager_power_off; | 80 | pm_power_off = voyager_power_off; |
| 81 | #ifdef CONFIG_SMP | 81 | #ifdef CONFIG_SMP |
| 82 | register_sysrq_key('v', &sysrq_voyager_dump_op); | 82 | register_sysrq_key('v', &sysrq_voyager_dump_op); |
| 83 | #endif | 83 | #endif |
| 84 | } else { | 84 | } else { |
| 85 | printk("\n\n**WARNING**: No Voyager Subsystem Found\n"); | 85 | printk("\n\n**WARNING**: No Voyager Subsystem Found\n"); |
| 86 | } | 86 | } |
| 87 | } | 87 | } |
| 88 | 88 | ||
| 89 | void | 89 | void |
| 90 | voyager_system_interrupt(int cpl, void *dev_id, struct pt_regs *regs) | 90 | voyager_system_interrupt(int cpl, void *dev_id, struct pt_regs *regs) |
| 91 | { | 91 | { |
| 92 | printk("Voyager: detected system interrupt\n"); | 92 | printk("Voyager: detected system interrupt\n"); |
| 93 | } | 93 | } |
| 94 | 94 | ||
| 95 | /* Routine to read information from the extended CMOS area */ | 95 | /* Routine to read information from the extended CMOS area */ |
| 96 | __u8 | 96 | __u8 |
| 97 | voyager_extended_cmos_read(__u16 addr) | 97 | voyager_extended_cmos_read(__u16 addr) |
| 98 | { | 98 | { |
| 99 | outb(addr & 0xff, 0x74); | 99 | outb(addr & 0xff, 0x74); |
| 100 | outb((addr >> 8) & 0xff, 0x75); | 100 | outb((addr >> 8) & 0xff, 0x75); |
| 101 | return inb(0x76); | 101 | return inb(0x76); |
| 102 | } | 102 | } |
| 103 | 103 | ||
| 104 | /* internal definitions for the SUS Click Map of memory */ | 104 | /* internal definitions for the SUS Click Map of memory */ |
| 105 | 105 | ||
| 106 | #define CLICK_ENTRIES 16 | 106 | #define CLICK_ENTRIES 16 |
| 107 | #define CLICK_SIZE 4096 /* click to byte conversion for Length */ | 107 | #define CLICK_SIZE 4096 /* click to byte conversion for Length */ |
| 108 | 108 | ||
| 109 | typedef struct ClickMap { | 109 | typedef struct ClickMap { |
| 110 | struct Entry { | 110 | struct Entry { |
| 111 | __u32 Address; | 111 | __u32 Address; |
| 112 | __u32 Length; | 112 | __u32 Length; |
| 113 | } Entry[CLICK_ENTRIES]; | 113 | } Entry[CLICK_ENTRIES]; |
| 114 | } ClickMap_t; | 114 | } ClickMap_t; |
| 115 | 115 | ||
| 116 | 116 | ||
| 117 | /* This routine is pretty much an awful hack to read the bios clickmap by | 117 | /* This routine is pretty much an awful hack to read the bios clickmap by |
| 118 | * mapping it into page 0. There are usually three regions in the map: | 118 | * mapping it into page 0. There are usually three regions in the map: |
| 119 | * Base Memory | 119 | * Base Memory |
| 120 | * Extended Memory | 120 | * Extended Memory |
| 121 | * zero length marker for end of map | 121 | * zero length marker for end of map |
| 122 | * | 122 | * |
| 123 | * Returns are 0 for failure and 1 for success on extracting region. | 123 | * Returns are 0 for failure and 1 for success on extracting region. |
| 124 | */ | 124 | */ |
| 125 | int __init | 125 | int __init |
| 126 | voyager_memory_detect(int region, __u32 *start, __u32 *length) | 126 | voyager_memory_detect(int region, __u32 *start, __u32 *length) |
| 127 | { | 127 | { |
| 128 | int i; | 128 | int i; |
| 129 | int retval = 0; | 129 | int retval = 0; |
| 130 | __u8 cmos[4]; | 130 | __u8 cmos[4]; |
| 131 | ClickMap_t *map; | 131 | ClickMap_t *map; |
| 132 | unsigned long map_addr; | 132 | unsigned long map_addr; |
| 133 | unsigned long old; | 133 | unsigned long old; |
| 134 | 134 | ||
| 135 | if(region >= CLICK_ENTRIES) { | 135 | if(region >= CLICK_ENTRIES) { |
| 136 | printk("Voyager: Illegal ClickMap region %d\n", region); | 136 | printk("Voyager: Illegal ClickMap region %d\n", region); |
| 137 | return 0; | 137 | return 0; |
| 138 | } | 138 | } |
| 139 | 139 | ||
| 140 | for(i = 0; i < sizeof(cmos); i++) | 140 | for(i = 0; i < sizeof(cmos); i++) |
| 141 | cmos[i] = voyager_extended_cmos_read(VOYAGER_MEMORY_CLICKMAP + i); | 141 | cmos[i] = voyager_extended_cmos_read(VOYAGER_MEMORY_CLICKMAP + i); |
| 142 | 142 | ||
| 143 | map_addr = *(unsigned long *)cmos; | 143 | map_addr = *(unsigned long *)cmos; |
| 144 | 144 | ||
| 145 | /* steal page 0 for this */ | 145 | /* steal page 0 for this */ |
| 146 | old = pg0[0]; | 146 | old = pg0[0]; |
| 147 | pg0[0] = ((map_addr & PAGE_MASK) | _PAGE_RW | _PAGE_PRESENT); | 147 | pg0[0] = ((map_addr & PAGE_MASK) | _PAGE_RW | _PAGE_PRESENT); |
| 148 | local_flush_tlb(); | 148 | local_flush_tlb(); |
| 149 | /* now clear everything out but page 0 */ | 149 | /* now clear everything out but page 0 */ |
| 150 | map = (ClickMap_t *)(map_addr & (~PAGE_MASK)); | 150 | map = (ClickMap_t *)(map_addr & (~PAGE_MASK)); |
| 151 | 151 | ||
| 152 | /* zero length is the end of the clickmap */ | 152 | /* zero length is the end of the clickmap */ |
| 153 | if(map->Entry[region].Length != 0) { | 153 | if(map->Entry[region].Length != 0) { |
| 154 | *length = map->Entry[region].Length * CLICK_SIZE; | 154 | *length = map->Entry[region].Length * CLICK_SIZE; |
| 155 | *start = map->Entry[region].Address; | 155 | *start = map->Entry[region].Address; |
| 156 | retval = 1; | 156 | retval = 1; |
| 157 | } | 157 | } |
| 158 | 158 | ||
| 159 | /* replace the mapping */ | 159 | /* replace the mapping */ |
| 160 | pg0[0] = old; | 160 | pg0[0] = old; |
| 161 | local_flush_tlb(); | 161 | local_flush_tlb(); |
| 162 | return retval; | 162 | return retval; |
| 163 | } | 163 | } |
| 164 | 164 | ||
| 165 | /* voyager specific handling code for timer interrupts. Used to hand | 165 | /* voyager specific handling code for timer interrupts. Used to hand |
| 166 | * off the timer tick to the SMP code, since the VIC doesn't have an | 166 | * off the timer tick to the SMP code, since the VIC doesn't have an |
| 167 | * internal timer (The QIC does, but that's another story). */ | 167 | * internal timer (The QIC does, but that's another story). */ |
| 168 | void | 168 | void |
| 169 | voyager_timer_interrupt(struct pt_regs *regs) | 169 | voyager_timer_interrupt(struct pt_regs *regs) |
| 170 | { | 170 | { |
| 171 | if((jiffies & 0x3ff) == 0) { | 171 | if((jiffies & 0x3ff) == 0) { |
| 172 | 172 | ||
| 173 | /* There seems to be something flaky in either | 173 | /* There seems to be something flaky in either |
| 174 | * hardware or software that is resetting the timer 0 | 174 | * hardware or software that is resetting the timer 0 |
| 175 | * count to something much higher than it should be | 175 | * count to something much higher than it should be |
| 176 | * This seems to occur in the boot sequence, just | 176 | * This seems to occur in the boot sequence, just |
| 177 | * before root is mounted. Therefore, every 10 | 177 | * before root is mounted. Therefore, every 10 |
| 178 | * seconds or so, we sanity check the timer zero count | 178 | * seconds or so, we sanity check the timer zero count |
| 179 | * and kick it back to where it should be. | 179 | * and kick it back to where it should be. |
| 180 | * | 180 | * |
| 181 | * FIXME: This is the most awful hack yet seen. I | 181 | * FIXME: This is the most awful hack yet seen. I |
| 182 | * should work out exactly what is interfering with | 182 | * should work out exactly what is interfering with |
| 183 | * the timer count settings early in the boot sequence | 183 | * the timer count settings early in the boot sequence |
| 184 | * and swiftly introduce it to something sharp and | 184 | * and swiftly introduce it to something sharp and |
| 185 | * pointy. */ | 185 | * pointy. */ |
| 186 | __u16 val; | 186 | __u16 val; |
| 187 | 187 | ||
| 188 | spin_lock(&i8253_lock); | 188 | spin_lock(&i8253_lock); |
| 189 | 189 | ||
| 190 | outb_p(0x00, 0x43); | 190 | outb_p(0x00, 0x43); |
| 191 | val = inb_p(0x40); | 191 | val = inb_p(0x40); |
| 192 | val |= inb(0x40) << 8; | 192 | val |= inb(0x40) << 8; |
| 193 | spin_unlock(&i8253_lock); | 193 | spin_unlock(&i8253_lock); |
| 194 | 194 | ||
| 195 | if(val > LATCH) { | 195 | if(val > LATCH) { |
| 196 | printk("\nVOYAGER: countdown timer value too high (%d), resetting\n\n", val); | 196 | printk("\nVOYAGER: countdown timer value too high (%d), resetting\n\n", val); |
| 197 | spin_lock(&i8253_lock); | 197 | spin_lock(&i8253_lock); |
| 198 | outb(0x34,0x43); | 198 | outb(0x34,0x43); |
| 199 | outb_p(LATCH & 0xff , 0x40); /* LSB */ | 199 | outb_p(LATCH & 0xff , 0x40); /* LSB */ |
| 200 | outb(LATCH >> 8 , 0x40); /* MSB */ | 200 | outb(LATCH >> 8 , 0x40); /* MSB */ |
| 201 | spin_unlock(&i8253_lock); | 201 | spin_unlock(&i8253_lock); |
| 202 | } | 202 | } |
| 203 | } | 203 | } |
| 204 | #ifdef CONFIG_SMP | 204 | #ifdef CONFIG_SMP |
| 205 | smp_vic_timer_interrupt(regs); | 205 | smp_vic_timer_interrupt(regs); |
| 206 | #endif | 206 | #endif |
| 207 | } | 207 | } |
| 208 | 208 | ||
| 209 | void | 209 | void |
| 210 | voyager_power_off(void) | 210 | voyager_power_off(void) |
| 211 | { | 211 | { |
| 212 | printk("VOYAGER Power Off\n"); | 212 | printk("VOYAGER Power Off\n"); |
| 213 | 213 | ||
| 214 | if(voyager_level == 5) { | 214 | if(voyager_level == 5) { |
| 215 | voyager_cat_power_off(); | 215 | voyager_cat_power_off(); |
| 216 | } else if(voyager_level == 4) { | 216 | } else if(voyager_level == 4) { |
| 217 | /* This doesn't apparently work on most L4 machines, | 217 | /* This doesn't apparently work on most L4 machines, |
| 218 | * but the specs say to do this to get automatic power | 218 | * but the specs say to do this to get automatic power |
| 219 | * off. Unfortunately, if it doesn't power off the | 219 | * off. Unfortunately, if it doesn't power off the |
| 220 | * machine, it ends up doing a cold restart, which | 220 | * machine, it ends up doing a cold restart, which |
| 221 | * isn't really intended, so comment out the code */ | 221 | * isn't really intended, so comment out the code */ |
| 222 | #if 0 | 222 | #if 0 |
| 223 | int port; | 223 | int port; |
| 224 | 224 | ||
| 225 | 225 | ||
| 226 | /* enable the voyager Configuration Space */ | 226 | /* enable the voyager Configuration Space */ |
| 227 | outb((inb(VOYAGER_MC_SETUP) & 0xf0) | 0x8, | 227 | outb((inb(VOYAGER_MC_SETUP) & 0xf0) | 0x8, |
| 228 | VOYAGER_MC_SETUP); | 228 | VOYAGER_MC_SETUP); |
| 229 | /* the port for the power off flag is an offset from the | 229 | /* the port for the power off flag is an offset from the |
| 230 | floating base */ | 230 | floating base */ |
| 231 | port = (inb(VOYAGER_SSPB_RELOCATION_PORT) << 8) + 0x21; | 231 | port = (inb(VOYAGER_SSPB_RELOCATION_PORT) << 8) + 0x21; |
| 232 | /* set the power off flag */ | 232 | /* set the power off flag */ |
| 233 | outb(inb(port) | 0x1, port); | 233 | outb(inb(port) | 0x1, port); |
| 234 | #endif | 234 | #endif |
| 235 | } | 235 | } |
| 236 | /* and wait for it to happen */ | 236 | /* and wait for it to happen */ |
| 237 | for(;;) { | 237 | local_irq_disable(); |
| 238 | __asm("cli"); | 238 | for(;;) |
| 239 | __asm("hlt"); | 239 | halt(); |
| 240 | } | ||
| 241 | } | 240 | } |
| 242 | 241 | ||
| 243 | /* copied from process.c */ | 242 | /* copied from process.c */ |
| 244 | static inline void | 243 | static inline void |
| 245 | kb_wait(void) | 244 | kb_wait(void) |
| 246 | { | 245 | { |
| 247 | int i; | 246 | int i; |
| 248 | 247 | ||
| 249 | for (i=0; i<0x10000; i++) | 248 | for (i=0; i<0x10000; i++) |
| 250 | if ((inb_p(0x64) & 0x02) == 0) | 249 | if ((inb_p(0x64) & 0x02) == 0) |
| 251 | break; | 250 | break; |
| 252 | } | 251 | } |
| 253 | 252 | ||
| 254 | void | 253 | void |
| 255 | machine_shutdown(void) | 254 | machine_shutdown(void) |
| 256 | { | 255 | { |
| 257 | /* Architecture specific shutdown needed before a kexec */ | 256 | /* Architecture specific shutdown needed before a kexec */ |
| 258 | } | 257 | } |
| 259 | 258 | ||
| 260 | void | 259 | void |
| 261 | machine_restart(char *cmd) | 260 | machine_restart(char *cmd) |
| 262 | { | 261 | { |
| 263 | printk("Voyager Warm Restart\n"); | 262 | printk("Voyager Warm Restart\n"); |
| 264 | kb_wait(); | 263 | kb_wait(); |
| 265 | 264 | ||
| 266 | if(voyager_level == 5) { | 265 | if(voyager_level == 5) { |
| 267 | /* write magic values to the RTC to inform system that | 266 | /* write magic values to the RTC to inform system that |
| 268 | * shutdown is beginning */ | 267 | * shutdown is beginning */ |
| 269 | outb(0x8f, 0x70); | 268 | outb(0x8f, 0x70); |
| 270 | outb(0x5 , 0x71); | 269 | outb(0x5 , 0x71); |
| 271 | 270 | ||
| 272 | udelay(50); | 271 | udelay(50); |
| 273 | outb(0xfe,0x64); /* pull reset low */ | 272 | outb(0xfe,0x64); /* pull reset low */ |
| 274 | } else if(voyager_level == 4) { | 273 | } else if(voyager_level == 4) { |
| 275 | __u16 catbase = inb(VOYAGER_SSPB_RELOCATION_PORT)<<8; | 274 | __u16 catbase = inb(VOYAGER_SSPB_RELOCATION_PORT)<<8; |
| 276 | __u8 basebd = inb(VOYAGER_MC_SETUP); | 275 | __u8 basebd = inb(VOYAGER_MC_SETUP); |
| 277 | 276 | ||
| 278 | outb(basebd | 0x08, VOYAGER_MC_SETUP); | 277 | outb(basebd | 0x08, VOYAGER_MC_SETUP); |
| 279 | outb(0x02, catbase + 0x21); | 278 | outb(0x02, catbase + 0x21); |
| 280 | } | 279 | } |
| 281 | for(;;) { | 280 | local_irq_disable(); |
| 282 | asm("cli"); | 281 | for(;;) |
| 283 | asm("hlt"); | 282 | halt(); |
| 284 | } | ||
| 285 | } | 283 | } |
| 286 | 284 | ||
| 287 | void | 285 | void |
| 288 | machine_emergency_restart(void) | 286 | machine_emergency_restart(void) |
| 289 | { | 287 | { |
| 290 | /*for now, just hook this to a warm restart */ | 288 | /*for now, just hook this to a warm restart */ |
| 291 | machine_restart(NULL); | 289 | machine_restart(NULL); |
| 292 | } | 290 | } |
| 293 | 291 | ||
| 294 | void | 292 | void |
| 295 | mca_nmi_hook(void) | 293 | mca_nmi_hook(void) |
| 296 | { | 294 | { |
| 297 | __u8 dumpval __attribute__((unused)) = inb(0xf823); | 295 | __u8 dumpval __attribute__((unused)) = inb(0xf823); |
| 298 | __u8 swnmi __attribute__((unused)) = inb(0xf813); | 296 | __u8 swnmi __attribute__((unused)) = inb(0xf813); |
| 299 | 297 | ||
| 300 | /* FIXME: assume dump switch pressed */ | 298 | /* FIXME: assume dump switch pressed */ |
| 301 | /* check to see if the dump switch was pressed */ | 299 | /* check to see if the dump switch was pressed */ |
| 302 | VDEBUG(("VOYAGER: dumpval = 0x%x, swnmi = 0x%x\n", dumpval, swnmi)); | 300 | VDEBUG(("VOYAGER: dumpval = 0x%x, swnmi = 0x%x\n", dumpval, swnmi)); |
| 303 | /* clear swnmi */ | 301 | /* clear swnmi */ |
| 304 | outb(0xff, 0xf813); | 302 | outb(0xff, 0xf813); |
| 305 | /* tell SUS to ignore dump */ | 303 | /* tell SUS to ignore dump */ |
| 306 | if(voyager_level == 5 && voyager_SUS != NULL) { | 304 | if(voyager_level == 5 && voyager_SUS != NULL) { |
| 307 | if(voyager_SUS->SUS_mbox == VOYAGER_DUMP_BUTTON_NMI) { | 305 | if(voyager_SUS->SUS_mbox == VOYAGER_DUMP_BUTTON_NMI) { |
| 308 | voyager_SUS->kernel_mbox = VOYAGER_NO_COMMAND; | 306 | voyager_SUS->kernel_mbox = VOYAGER_NO_COMMAND; |
| 309 | voyager_SUS->kernel_flags |= VOYAGER_OS_IN_PROGRESS; | 307 | voyager_SUS->kernel_flags |= VOYAGER_OS_IN_PROGRESS; |
| 310 | udelay(1000); | 308 | udelay(1000); |
| 311 | voyager_SUS->kernel_mbox = VOYAGER_IGNORE_DUMP; | 309 | voyager_SUS->kernel_mbox = VOYAGER_IGNORE_DUMP; |
| 312 | voyager_SUS->kernel_flags &= ~VOYAGER_OS_IN_PROGRESS; | 310 | voyager_SUS->kernel_flags &= ~VOYAGER_OS_IN_PROGRESS; |
| 313 | } | 311 | } |
| 314 | } | 312 | } |
| 315 | printk(KERN_ERR "VOYAGER: Dump switch pressed, printing CPU%d tracebacks\n", smp_processor_id()); | 313 | printk(KERN_ERR "VOYAGER: Dump switch pressed, printing CPU%d tracebacks\n", smp_processor_id()); |
| 316 | show_stack(NULL, NULL); | 314 | show_stack(NULL, NULL); |
| 317 | show_state(); | 315 | show_state(); |
| 318 | } | 316 | } |
| 319 | 317 | ||
| 320 | 318 | ||
| 321 | 319 | ||
| 322 | void | 320 | void |
| 323 | machine_halt(void) | 321 | machine_halt(void) |
| 324 | { | 322 | { |
| 325 | /* treat a halt like a power off */ | 323 | /* treat a halt like a power off */ |
| 326 | machine_power_off(); | 324 | machine_power_off(); |
| 327 | } | 325 | } |
| 328 | 326 | ||
| 329 | void machine_power_off(void) | 327 | void machine_power_off(void) |
| 330 | { | 328 | { |
| 331 | if (pm_power_off) | 329 | if (pm_power_off) |
| 332 | pm_power_off(); | 330 | pm_power_off(); |
| 333 | } | 331 | } |
| 334 | 332 | ||
| 335 | 333 |
arch/i386/mach-voyager/voyager_smp.c
| 1 | /* -*- mode: c; c-basic-offset: 8 -*- */ | 1 | /* -*- mode: c; c-basic-offset: 8 -*- */ |
| 2 | 2 | ||
| 3 | /* Copyright (C) 1999,2001 | 3 | /* Copyright (C) 1999,2001 |
| 4 | * | 4 | * |
| 5 | * Author: J.E.J.Bottomley@HansenPartnership.com | 5 | * Author: J.E.J.Bottomley@HansenPartnership.com |
| 6 | * | 6 | * |
| 7 | * linux/arch/i386/kernel/voyager_smp.c | 7 | * linux/arch/i386/kernel/voyager_smp.c |
| 8 | * | 8 | * |
| 9 | * This file provides all the same external entries as smp.c but uses | 9 | * This file provides all the same external entries as smp.c but uses |
| 10 | * the voyager hal to provide the functionality | 10 | * the voyager hal to provide the functionality |
| 11 | */ | 11 | */ |
| 12 | #include <linux/config.h> | 12 | #include <linux/config.h> |
| 13 | #include <linux/module.h> | 13 | #include <linux/module.h> |
| 14 | #include <linux/mm.h> | 14 | #include <linux/mm.h> |
| 15 | #include <linux/kernel_stat.h> | 15 | #include <linux/kernel_stat.h> |
| 16 | #include <linux/delay.h> | 16 | #include <linux/delay.h> |
| 17 | #include <linux/mc146818rtc.h> | 17 | #include <linux/mc146818rtc.h> |
| 18 | #include <linux/cache.h> | 18 | #include <linux/cache.h> |
| 19 | #include <linux/interrupt.h> | 19 | #include <linux/interrupt.h> |
| 20 | #include <linux/smp_lock.h> | 20 | #include <linux/smp_lock.h> |
| 21 | #include <linux/init.h> | 21 | #include <linux/init.h> |
| 22 | #include <linux/kernel.h> | 22 | #include <linux/kernel.h> |
| 23 | #include <linux/bootmem.h> | 23 | #include <linux/bootmem.h> |
| 24 | #include <linux/completion.h> | 24 | #include <linux/completion.h> |
| 25 | #include <asm/desc.h> | 25 | #include <asm/desc.h> |
| 26 | #include <asm/voyager.h> | 26 | #include <asm/voyager.h> |
| 27 | #include <asm/vic.h> | 27 | #include <asm/vic.h> |
| 28 | #include <asm/mtrr.h> | 28 | #include <asm/mtrr.h> |
| 29 | #include <asm/pgalloc.h> | 29 | #include <asm/pgalloc.h> |
| 30 | #include <asm/tlbflush.h> | 30 | #include <asm/tlbflush.h> |
| 31 | #include <asm/arch_hooks.h> | 31 | #include <asm/arch_hooks.h> |
| 32 | 32 | ||
| 33 | #include <linux/irq.h> | 33 | #include <linux/irq.h> |
| 34 | 34 | ||
| 35 | /* TLB state -- visible externally, indexed physically */ | 35 | /* TLB state -- visible externally, indexed physically */ |
| 36 | DEFINE_PER_CPU(struct tlb_state, cpu_tlbstate) ____cacheline_aligned = { &init_mm, 0 }; | 36 | DEFINE_PER_CPU(struct tlb_state, cpu_tlbstate) ____cacheline_aligned = { &init_mm, 0 }; |
| 37 | 37 | ||
| 38 | /* CPU IRQ affinity -- set to all ones initially */ | 38 | /* CPU IRQ affinity -- set to all ones initially */ |
| 39 | static unsigned long cpu_irq_affinity[NR_CPUS] __cacheline_aligned = { [0 ... NR_CPUS-1] = ~0UL }; | 39 | static unsigned long cpu_irq_affinity[NR_CPUS] __cacheline_aligned = { [0 ... NR_CPUS-1] = ~0UL }; |
| 40 | 40 | ||
| 41 | /* per CPU data structure (for /proc/cpuinfo et al), visible externally | 41 | /* per CPU data structure (for /proc/cpuinfo et al), visible externally |
| 42 | * indexed physically */ | 42 | * indexed physically */ |
| 43 | struct cpuinfo_x86 cpu_data[NR_CPUS] __cacheline_aligned; | 43 | struct cpuinfo_x86 cpu_data[NR_CPUS] __cacheline_aligned; |
| 44 | EXPORT_SYMBOL(cpu_data); | 44 | EXPORT_SYMBOL(cpu_data); |
| 45 | 45 | ||
| 46 | /* physical ID of the CPU used to boot the system */ | 46 | /* physical ID of the CPU used to boot the system */ |
| 47 | unsigned char boot_cpu_id; | 47 | unsigned char boot_cpu_id; |
| 48 | 48 | ||
| 49 | /* The memory line addresses for the Quad CPIs */ | 49 | /* The memory line addresses for the Quad CPIs */ |
| 50 | struct voyager_qic_cpi *voyager_quad_cpi_addr[NR_CPUS] __cacheline_aligned; | 50 | struct voyager_qic_cpi *voyager_quad_cpi_addr[NR_CPUS] __cacheline_aligned; |
| 51 | 51 | ||
| 52 | /* The masks for the Extended VIC processors, filled in by cat_init */ | 52 | /* The masks for the Extended VIC processors, filled in by cat_init */ |
| 53 | __u32 voyager_extended_vic_processors = 0; | 53 | __u32 voyager_extended_vic_processors = 0; |
| 54 | 54 | ||
| 55 | /* Masks for the extended Quad processors which cannot be VIC booted */ | 55 | /* Masks for the extended Quad processors which cannot be VIC booted */ |
| 56 | __u32 voyager_allowed_boot_processors = 0; | 56 | __u32 voyager_allowed_boot_processors = 0; |
| 57 | 57 | ||
| 58 | /* The mask for the Quad Processors (both extended and non-extended) */ | 58 | /* The mask for the Quad Processors (both extended and non-extended) */ |
| 59 | __u32 voyager_quad_processors = 0; | 59 | __u32 voyager_quad_processors = 0; |
| 60 | 60 | ||
| 61 | /* Total count of live CPUs, used in process.c to display | 61 | /* Total count of live CPUs, used in process.c to display |
| 62 | * the CPU information and in irq.c for the per CPU irq | 62 | * the CPU information and in irq.c for the per CPU irq |
| 63 | * activity count. Finally exported by i386_ksyms.c */ | 63 | * activity count. Finally exported by i386_ksyms.c */ |
| 64 | static int voyager_extended_cpus = 1; | 64 | static int voyager_extended_cpus = 1; |
| 65 | 65 | ||
| 66 | /* Have we found an SMP box - used by time.c to do the profiling | 66 | /* Have we found an SMP box - used by time.c to do the profiling |
| 67 | interrupt for timeslicing; do not set to 1 until the per CPU timer | 67 | interrupt for timeslicing; do not set to 1 until the per CPU timer |
| 68 | interrupt is active */ | 68 | interrupt is active */ |
| 69 | int smp_found_config = 0; | 69 | int smp_found_config = 0; |
| 70 | 70 | ||
| 71 | /* Used for the invalidate map that's also checked in the spinlock */ | 71 | /* Used for the invalidate map that's also checked in the spinlock */ |
| 72 | static volatile unsigned long smp_invalidate_needed; | 72 | static volatile unsigned long smp_invalidate_needed; |
| 73 | 73 | ||
| 74 | /* Bitmask of currently online CPUs - used by setup.c for | 74 | /* Bitmask of currently online CPUs - used by setup.c for |
| 75 | /proc/cpuinfo, visible externally but still physical */ | 75 | /proc/cpuinfo, visible externally but still physical */ |
| 76 | cpumask_t cpu_online_map = CPU_MASK_NONE; | 76 | cpumask_t cpu_online_map = CPU_MASK_NONE; |
| 77 | EXPORT_SYMBOL(cpu_online_map); | 77 | EXPORT_SYMBOL(cpu_online_map); |
| 78 | 78 | ||
| 79 | /* Bitmask of CPUs present in the system - exported by i386_syms.c, used | 79 | /* Bitmask of CPUs present in the system - exported by i386_syms.c, used |
| 80 | * by scheduler but indexed physically */ | 80 | * by scheduler but indexed physically */ |
| 81 | cpumask_t phys_cpu_present_map = CPU_MASK_NONE; | 81 | cpumask_t phys_cpu_present_map = CPU_MASK_NONE; |
| 82 | 82 | ||
| 83 | 83 | ||
| 84 | /* The internal functions */ | 84 | /* The internal functions */ |
| 85 | static void send_CPI(__u32 cpuset, __u8 cpi); | 85 | static void send_CPI(__u32 cpuset, __u8 cpi); |
| 86 | static void ack_CPI(__u8 cpi); | 86 | static void ack_CPI(__u8 cpi); |
| 87 | static int ack_QIC_CPI(__u8 cpi); | 87 | static int ack_QIC_CPI(__u8 cpi); |
| 88 | static void ack_special_QIC_CPI(__u8 cpi); | 88 | static void ack_special_QIC_CPI(__u8 cpi); |
| 89 | static void ack_VIC_CPI(__u8 cpi); | 89 | static void ack_VIC_CPI(__u8 cpi); |
| 90 | static void send_CPI_allbutself(__u8 cpi); | 90 | static void send_CPI_allbutself(__u8 cpi); |
| 91 | static void enable_vic_irq(unsigned int irq); | 91 | static void enable_vic_irq(unsigned int irq); |
| 92 | static void disable_vic_irq(unsigned int irq); | 92 | static void disable_vic_irq(unsigned int irq); |
| 93 | static unsigned int startup_vic_irq(unsigned int irq); | 93 | static unsigned int startup_vic_irq(unsigned int irq); |
| 94 | static void enable_local_vic_irq(unsigned int irq); | 94 | static void enable_local_vic_irq(unsigned int irq); |
| 95 | static void disable_local_vic_irq(unsigned int irq); | 95 | static void disable_local_vic_irq(unsigned int irq); |
| 96 | static void before_handle_vic_irq(unsigned int irq); | 96 | static void before_handle_vic_irq(unsigned int irq); |
| 97 | static void after_handle_vic_irq(unsigned int irq); | 97 | static void after_handle_vic_irq(unsigned int irq); |
| 98 | static void set_vic_irq_affinity(unsigned int irq, cpumask_t mask); | 98 | static void set_vic_irq_affinity(unsigned int irq, cpumask_t mask); |
| 99 | static void ack_vic_irq(unsigned int irq); | 99 | static void ack_vic_irq(unsigned int irq); |
| 100 | static void vic_enable_cpi(void); | 100 | static void vic_enable_cpi(void); |
| 101 | static void do_boot_cpu(__u8 cpuid); | 101 | static void do_boot_cpu(__u8 cpuid); |
| 102 | static void do_quad_bootstrap(void); | 102 | static void do_quad_bootstrap(void); |
| 103 | 103 | ||
| 104 | int hard_smp_processor_id(void); | 104 | int hard_smp_processor_id(void); |
| 105 | 105 | ||
| 106 | /* Inline functions */ | 106 | /* Inline functions */ |
| 107 | static inline void | 107 | static inline void |
| 108 | send_one_QIC_CPI(__u8 cpu, __u8 cpi) | 108 | send_one_QIC_CPI(__u8 cpu, __u8 cpi) |
| 109 | { | 109 | { |
| 110 | voyager_quad_cpi_addr[cpu]->qic_cpi[cpi].cpi = | 110 | voyager_quad_cpi_addr[cpu]->qic_cpi[cpi].cpi = |
| 111 | (smp_processor_id() << 16) + cpi; | 111 | (smp_processor_id() << 16) + cpi; |
| 112 | } | 112 | } |
| 113 | 113 | ||
| 114 | static inline void | 114 | static inline void |
| 115 | send_QIC_CPI(__u32 cpuset, __u8 cpi) | 115 | send_QIC_CPI(__u32 cpuset, __u8 cpi) |
| 116 | { | 116 | { |
| 117 | int cpu; | 117 | int cpu; |
| 118 | 118 | ||
| 119 | for_each_online_cpu(cpu) { | 119 | for_each_online_cpu(cpu) { |
| 120 | if(cpuset & (1<<cpu)) { | 120 | if(cpuset & (1<<cpu)) { |
| 121 | #ifdef VOYAGER_DEBUG | 121 | #ifdef VOYAGER_DEBUG |
| 122 | if(!cpu_isset(cpu, cpu_online_map)) | 122 | if(!cpu_isset(cpu, cpu_online_map)) |
| 123 | VDEBUG(("CPU%d sending cpi %d to CPU%d not in cpu_online_map\n", hard_smp_processor_id(), cpi, cpu)); | 123 | VDEBUG(("CPU%d sending cpi %d to CPU%d not in cpu_online_map\n", hard_smp_processor_id(), cpi, cpu)); |
| 124 | #endif | 124 | #endif |
| 125 | send_one_QIC_CPI(cpu, cpi - QIC_CPI_OFFSET); | 125 | send_one_QIC_CPI(cpu, cpi - QIC_CPI_OFFSET); |
| 126 | } | 126 | } |
| 127 | } | 127 | } |
| 128 | } | 128 | } |
| 129 | 129 | ||
| 130 | static inline void | 130 | static inline void |
| 131 | wrapper_smp_local_timer_interrupt(struct pt_regs *regs) | 131 | wrapper_smp_local_timer_interrupt(struct pt_regs *regs) |
| 132 | { | 132 | { |
| 133 | irq_enter(); | 133 | irq_enter(); |
| 134 | smp_local_timer_interrupt(regs); | 134 | smp_local_timer_interrupt(regs); |
| 135 | irq_exit(); | 135 | irq_exit(); |
| 136 | } | 136 | } |
| 137 | 137 | ||
| 138 | static inline void | 138 | static inline void |
| 139 | send_one_CPI(__u8 cpu, __u8 cpi) | 139 | send_one_CPI(__u8 cpu, __u8 cpi) |
| 140 | { | 140 | { |
| 141 | if(voyager_quad_processors & (1<<cpu)) | 141 | if(voyager_quad_processors & (1<<cpu)) |
| 142 | send_one_QIC_CPI(cpu, cpi - QIC_CPI_OFFSET); | 142 | send_one_QIC_CPI(cpu, cpi - QIC_CPI_OFFSET); |
| 143 | else | 143 | else |
| 144 | send_CPI(1<<cpu, cpi); | 144 | send_CPI(1<<cpu, cpi); |
| 145 | } | 145 | } |
| 146 | 146 | ||
| 147 | static inline void | 147 | static inline void |
| 148 | send_CPI_allbutself(__u8 cpi) | 148 | send_CPI_allbutself(__u8 cpi) |
| 149 | { | 149 | { |
| 150 | __u8 cpu = smp_processor_id(); | 150 | __u8 cpu = smp_processor_id(); |
| 151 | __u32 mask = cpus_addr(cpu_online_map)[0] & ~(1 << cpu); | 151 | __u32 mask = cpus_addr(cpu_online_map)[0] & ~(1 << cpu); |
| 152 | send_CPI(mask, cpi); | 152 | send_CPI(mask, cpi); |
| 153 | } | 153 | } |
| 154 | 154 | ||
| 155 | static inline int | 155 | static inline int |
| 156 | is_cpu_quad(void) | 156 | is_cpu_quad(void) |
| 157 | { | 157 | { |
| 158 | __u8 cpumask = inb(VIC_PROC_WHO_AM_I); | 158 | __u8 cpumask = inb(VIC_PROC_WHO_AM_I); |
| 159 | return ((cpumask & QUAD_IDENTIFIER) == QUAD_IDENTIFIER); | 159 | return ((cpumask & QUAD_IDENTIFIER) == QUAD_IDENTIFIER); |
| 160 | } | 160 | } |
| 161 | 161 | ||
| 162 | static inline int | 162 | static inline int |
| 163 | is_cpu_extended(void) | 163 | is_cpu_extended(void) |
| 164 | { | 164 | { |
| 165 | __u8 cpu = hard_smp_processor_id(); | 165 | __u8 cpu = hard_smp_processor_id(); |
| 166 | 166 | ||
| 167 | return(voyager_extended_vic_processors & (1<<cpu)); | 167 | return(voyager_extended_vic_processors & (1<<cpu)); |
| 168 | } | 168 | } |
| 169 | 169 | ||
| 170 | static inline int | 170 | static inline int |
| 171 | is_cpu_vic_boot(void) | 171 | is_cpu_vic_boot(void) |
| 172 | { | 172 | { |
| 173 | __u8 cpu = hard_smp_processor_id(); | 173 | __u8 cpu = hard_smp_processor_id(); |
| 174 | 174 | ||
| 175 | return(voyager_extended_vic_processors | 175 | return(voyager_extended_vic_processors |
| 176 | & voyager_allowed_boot_processors & (1<<cpu)); | 176 | & voyager_allowed_boot_processors & (1<<cpu)); |
| 177 | } | 177 | } |
| 178 | 178 | ||
| 179 | 179 | ||
| 180 | static inline void | 180 | static inline void |
| 181 | ack_CPI(__u8 cpi) | 181 | ack_CPI(__u8 cpi) |
| 182 | { | 182 | { |
| 183 | switch(cpi) { | 183 | switch(cpi) { |
| 184 | case VIC_CPU_BOOT_CPI: | 184 | case VIC_CPU_BOOT_CPI: |
| 185 | if(is_cpu_quad() && !is_cpu_vic_boot()) | 185 | if(is_cpu_quad() && !is_cpu_vic_boot()) |
| 186 | ack_QIC_CPI(cpi); | 186 | ack_QIC_CPI(cpi); |
| 187 | else | 187 | else |
| 188 | ack_VIC_CPI(cpi); | 188 | ack_VIC_CPI(cpi); |
| 189 | break; | 189 | break; |
| 190 | case VIC_SYS_INT: | 190 | case VIC_SYS_INT: |
| 191 | case VIC_CMN_INT: | 191 | case VIC_CMN_INT: |
| 192 | /* These are slightly strange. Even on the Quad card, | 192 | /* These are slightly strange. Even on the Quad card, |
| 193 | * They are vectored as VIC CPIs */ | 193 | * They are vectored as VIC CPIs */ |
| 194 | if(is_cpu_quad()) | 194 | if(is_cpu_quad()) |
| 195 | ack_special_QIC_CPI(cpi); | 195 | ack_special_QIC_CPI(cpi); |
| 196 | else | 196 | else |
| 197 | ack_VIC_CPI(cpi); | 197 | ack_VIC_CPI(cpi); |
| 198 | break; | 198 | break; |
| 199 | default: | 199 | default: |
| 200 | printk("VOYAGER ERROR: CPI%d is in common CPI code\n", cpi); | 200 | printk("VOYAGER ERROR: CPI%d is in common CPI code\n", cpi); |
| 201 | break; | 201 | break; |
| 202 | } | 202 | } |
| 203 | } | 203 | } |
| 204 | 204 | ||
| 205 | /* local variables */ | 205 | /* local variables */ |
| 206 | 206 | ||
| 207 | /* The VIC IRQ descriptors -- these look almost identical to the | 207 | /* The VIC IRQ descriptors -- these look almost identical to the |
| 208 | * 8259 IRQs except that masks and things must be kept per processor | 208 | * 8259 IRQs except that masks and things must be kept per processor |
| 209 | */ | 209 | */ |
| 210 | static struct hw_interrupt_type vic_irq_type = { | 210 | static struct hw_interrupt_type vic_irq_type = { |
| 211 | .typename = "VIC-level", | 211 | .typename = "VIC-level", |
| 212 | .startup = startup_vic_irq, | 212 | .startup = startup_vic_irq, |
| 213 | .shutdown = disable_vic_irq, | 213 | .shutdown = disable_vic_irq, |
| 214 | .enable = enable_vic_irq, | 214 | .enable = enable_vic_irq, |
| 215 | .disable = disable_vic_irq, | 215 | .disable = disable_vic_irq, |
| 216 | .ack = before_handle_vic_irq, | 216 | .ack = before_handle_vic_irq, |
| 217 | .end = after_handle_vic_irq, | 217 | .end = after_handle_vic_irq, |
| 218 | .set_affinity = set_vic_irq_affinity, | 218 | .set_affinity = set_vic_irq_affinity, |
| 219 | }; | 219 | }; |
| 220 | 220 | ||
| 221 | /* used to count up as CPUs are brought on line (starts at 0) */ | 221 | /* used to count up as CPUs are brought on line (starts at 0) */ |
| 222 | static int cpucount = 0; | 222 | static int cpucount = 0; |
| 223 | 223 | ||
| 224 | /* steal a page from the bottom of memory for the trampoline and | 224 | /* steal a page from the bottom of memory for the trampoline and |
| 225 | * squirrel its address away here. This will be in kernel virtual | 225 | * squirrel its address away here. This will be in kernel virtual |
| 226 | * space */ | 226 | * space */ |
| 227 | static __u32 trampoline_base; | 227 | static __u32 trampoline_base; |
| 228 | 228 | ||
| 229 | /* The per cpu profile stuff - used in smp_local_timer_interrupt */ | 229 | /* The per cpu profile stuff - used in smp_local_timer_interrupt */ |
| 230 | static DEFINE_PER_CPU(int, prof_multiplier) = 1; | 230 | static DEFINE_PER_CPU(int, prof_multiplier) = 1; |
| 231 | static DEFINE_PER_CPU(int, prof_old_multiplier) = 1; | 231 | static DEFINE_PER_CPU(int, prof_old_multiplier) = 1; |
| 232 | static DEFINE_PER_CPU(int, prof_counter) = 1; | 232 | static DEFINE_PER_CPU(int, prof_counter) = 1; |
| 233 | 233 | ||
| 234 | /* the map used to check if a CPU has booted */ | 234 | /* the map used to check if a CPU has booted */ |
| 235 | static __u32 cpu_booted_map; | 235 | static __u32 cpu_booted_map; |
| 236 | 236 | ||
| 237 | /* the synchronize flag used to hold all secondary CPUs spinning in | 237 | /* the synchronize flag used to hold all secondary CPUs spinning in |
| 238 | * a tight loop until the boot sequence is ready for them */ | 238 | * a tight loop until the boot sequence is ready for them */ |
| 239 | static cpumask_t smp_commenced_mask = CPU_MASK_NONE; | 239 | static cpumask_t smp_commenced_mask = CPU_MASK_NONE; |
| 240 | 240 | ||
| 241 | /* This is for the new dynamic CPU boot code */ | 241 | /* This is for the new dynamic CPU boot code */ |
| 242 | cpumask_t cpu_callin_map = CPU_MASK_NONE; | 242 | cpumask_t cpu_callin_map = CPU_MASK_NONE; |
| 243 | cpumask_t cpu_callout_map = CPU_MASK_NONE; | 243 | cpumask_t cpu_callout_map = CPU_MASK_NONE; |
| 244 | EXPORT_SYMBOL(cpu_callout_map); | 244 | EXPORT_SYMBOL(cpu_callout_map); |
| 245 | 245 | ||
| 246 | /* The per processor IRQ masks (these are usually kept in sync) */ | 246 | /* The per processor IRQ masks (these are usually kept in sync) */ |
| 247 | static __u16 vic_irq_mask[NR_CPUS] __cacheline_aligned; | 247 | static __u16 vic_irq_mask[NR_CPUS] __cacheline_aligned; |
| 248 | 248 | ||
| 249 | /* the list of IRQs to be enabled by the VIC_ENABLE_IRQ_CPI */ | 249 | /* the list of IRQs to be enabled by the VIC_ENABLE_IRQ_CPI */ |
| 250 | static __u16 vic_irq_enable_mask[NR_CPUS] __cacheline_aligned = { 0 }; | 250 | static __u16 vic_irq_enable_mask[NR_CPUS] __cacheline_aligned = { 0 }; |
| 251 | 251 | ||
| 252 | /* Lock for enable/disable of VIC interrupts */ | 252 | /* Lock for enable/disable of VIC interrupts */ |
| 253 | static __cacheline_aligned DEFINE_SPINLOCK(vic_irq_lock); | 253 | static __cacheline_aligned DEFINE_SPINLOCK(vic_irq_lock); |
| 254 | 254 | ||
| 255 | /* The boot processor is correctly set up in PC mode when it | 255 | /* The boot processor is correctly set up in PC mode when it |
| 256 | * comes up, but the secondaries need their master/slave 8259 | 256 | * comes up, but the secondaries need their master/slave 8259 |
| 257 | * pairs initializing correctly */ | 257 | * pairs initializing correctly */ |
| 258 | 258 | ||
| 259 | /* Interrupt counters (per cpu) and total - used to try to | 259 | /* Interrupt counters (per cpu) and total - used to try to |
| 260 | * even up the interrupt handling routines */ | 260 | * even up the interrupt handling routines */ |
| 261 | static long vic_intr_total = 0; | 261 | static long vic_intr_total = 0; |
| 262 | static long vic_intr_count[NR_CPUS] __cacheline_aligned = { 0 }; | 262 | static long vic_intr_count[NR_CPUS] __cacheline_aligned = { 0 }; |
| 263 | static unsigned long vic_tick[NR_CPUS] __cacheline_aligned = { 0 }; | 263 | static unsigned long vic_tick[NR_CPUS] __cacheline_aligned = { 0 }; |
| 264 | 264 | ||
| 265 | /* Since we can only use CPI0, we fake all the other CPIs */ | 265 | /* Since we can only use CPI0, we fake all the other CPIs */ |
| 266 | static unsigned long vic_cpi_mailbox[NR_CPUS] __cacheline_aligned; | 266 | static unsigned long vic_cpi_mailbox[NR_CPUS] __cacheline_aligned; |
| 267 | 267 | ||
| 268 | /* debugging routine to read the isr of the cpu's pic */ | 268 | /* debugging routine to read the isr of the cpu's pic */ |
| 269 | static inline __u16 | 269 | static inline __u16 |
| 270 | vic_read_isr(void) | 270 | vic_read_isr(void) |
| 271 | { | 271 | { |
| 272 | __u16 isr; | 272 | __u16 isr; |
| 273 | 273 | ||
| 274 | outb(0x0b, 0xa0); | 274 | outb(0x0b, 0xa0); |
| 275 | isr = inb(0xa0) << 8; | 275 | isr = inb(0xa0) << 8; |
| 276 | outb(0x0b, 0x20); | 276 | outb(0x0b, 0x20); |
| 277 | isr |= inb(0x20); | 277 | isr |= inb(0x20); |
| 278 | 278 | ||
| 279 | return isr; | 279 | return isr; |
| 280 | } | 280 | } |
| 281 | 281 | ||
| 282 | static __init void | 282 | static __init void |
| 283 | qic_setup(void) | 283 | qic_setup(void) |
| 284 | { | 284 | { |
| 285 | if(!is_cpu_quad()) { | 285 | if(!is_cpu_quad()) { |
| 286 | /* not a quad, no setup */ | 286 | /* not a quad, no setup */ |
| 287 | return; | 287 | return; |
| 288 | } | 288 | } |
| 289 | outb(QIC_DEFAULT_MASK0, QIC_MASK_REGISTER0); | 289 | outb(QIC_DEFAULT_MASK0, QIC_MASK_REGISTER0); |
| 290 | outb(QIC_CPI_ENABLE, QIC_MASK_REGISTER1); | 290 | outb(QIC_CPI_ENABLE, QIC_MASK_REGISTER1); |
| 291 | 291 | ||
| 292 | if(is_cpu_extended()) { | 292 | if(is_cpu_extended()) { |
| 293 | /* the QIC duplicate of the VIC base register */ | 293 | /* the QIC duplicate of the VIC base register */ |
| 294 | outb(VIC_DEFAULT_CPI_BASE, QIC_VIC_CPI_BASE_REGISTER); | 294 | outb(VIC_DEFAULT_CPI_BASE, QIC_VIC_CPI_BASE_REGISTER); |
| 295 | outb(QIC_DEFAULT_CPI_BASE, QIC_CPI_BASE_REGISTER); | 295 | outb(QIC_DEFAULT_CPI_BASE, QIC_CPI_BASE_REGISTER); |
| 296 | 296 | ||
| 297 | /* FIXME: should set up the QIC timer and memory parity | 297 | /* FIXME: should set up the QIC timer and memory parity |
| 298 | * error vectors here */ | 298 | * error vectors here */ |
| 299 | } | 299 | } |
| 300 | } | 300 | } |
| 301 | 301 | ||
| 302 | static __init void | 302 | static __init void |
| 303 | vic_setup_pic(void) | 303 | vic_setup_pic(void) |
| 304 | { | 304 | { |
| 305 | outb(1, VIC_REDIRECT_REGISTER_1); | 305 | outb(1, VIC_REDIRECT_REGISTER_1); |
| 306 | /* clear the claim registers for dynamic routing */ | 306 | /* clear the claim registers for dynamic routing */ |
| 307 | outb(0, VIC_CLAIM_REGISTER_0); | 307 | outb(0, VIC_CLAIM_REGISTER_0); |
| 308 | outb(0, VIC_CLAIM_REGISTER_1); | 308 | outb(0, VIC_CLAIM_REGISTER_1); |
| 309 | 309 | ||
| 310 | outb(0, VIC_PRIORITY_REGISTER); | 310 | outb(0, VIC_PRIORITY_REGISTER); |
| 311 | /* Set the Primary and Secondary Microchannel vector | 311 | /* Set the Primary and Secondary Microchannel vector |
| 312 | * bases to be the same as the ordinary interrupts | 312 | * bases to be the same as the ordinary interrupts |
| 313 | * | 313 | * |
| 314 | * FIXME: This would be more efficient using separate | 314 | * FIXME: This would be more efficient using separate |
| 315 | * vectors. */ | 315 | * vectors. */ |
| 316 | outb(FIRST_EXTERNAL_VECTOR, VIC_PRIMARY_MC_BASE); | 316 | outb(FIRST_EXTERNAL_VECTOR, VIC_PRIMARY_MC_BASE); |
| 317 | outb(FIRST_EXTERNAL_VECTOR, VIC_SECONDARY_MC_BASE); | 317 | outb(FIRST_EXTERNAL_VECTOR, VIC_SECONDARY_MC_BASE); |
| 318 | /* Now initiallise the master PIC belonging to this CPU by | 318 | /* Now initiallise the master PIC belonging to this CPU by |
| 319 | * sending the four ICWs */ | 319 | * sending the four ICWs */ |
| 320 | 320 | ||
| 321 | /* ICW1: level triggered, ICW4 needed */ | 321 | /* ICW1: level triggered, ICW4 needed */ |
| 322 | outb(0x19, 0x20); | 322 | outb(0x19, 0x20); |
| 323 | 323 | ||
| 324 | /* ICW2: vector base */ | 324 | /* ICW2: vector base */ |
| 325 | outb(FIRST_EXTERNAL_VECTOR, 0x21); | 325 | outb(FIRST_EXTERNAL_VECTOR, 0x21); |
| 326 | 326 | ||
| 327 | /* ICW3: slave at line 2 */ | 327 | /* ICW3: slave at line 2 */ |
| 328 | outb(0x04, 0x21); | 328 | outb(0x04, 0x21); |
| 329 | 329 | ||
| 330 | /* ICW4: 8086 mode */ | 330 | /* ICW4: 8086 mode */ |
| 331 | outb(0x01, 0x21); | 331 | outb(0x01, 0x21); |
| 332 | 332 | ||
| 333 | /* now the same for the slave PIC */ | 333 | /* now the same for the slave PIC */ |
| 334 | 334 | ||
| 335 | /* ICW1: level trigger, ICW4 needed */ | 335 | /* ICW1: level trigger, ICW4 needed */ |
| 336 | outb(0x19, 0xA0); | 336 | outb(0x19, 0xA0); |
| 337 | 337 | ||
| 338 | /* ICW2: slave vector base */ | 338 | /* ICW2: slave vector base */ |
| 339 | outb(FIRST_EXTERNAL_VECTOR + 8, 0xA1); | 339 | outb(FIRST_EXTERNAL_VECTOR + 8, 0xA1); |
| 340 | 340 | ||
| 341 | /* ICW3: slave ID */ | 341 | /* ICW3: slave ID */ |
| 342 | outb(0x02, 0xA1); | 342 | outb(0x02, 0xA1); |
| 343 | 343 | ||
| 344 | /* ICW4: 8086 mode */ | 344 | /* ICW4: 8086 mode */ |
| 345 | outb(0x01, 0xA1); | 345 | outb(0x01, 0xA1); |
| 346 | } | 346 | } |
| 347 | 347 | ||
| 348 | static void | 348 | static void |
| 349 | do_quad_bootstrap(void) | 349 | do_quad_bootstrap(void) |
| 350 | { | 350 | { |
| 351 | if(is_cpu_quad() && is_cpu_vic_boot()) { | 351 | if(is_cpu_quad() && is_cpu_vic_boot()) { |
| 352 | int i; | 352 | int i; |
| 353 | unsigned long flags; | 353 | unsigned long flags; |
| 354 | __u8 cpuid = hard_smp_processor_id(); | 354 | __u8 cpuid = hard_smp_processor_id(); |
| 355 | 355 | ||
| 356 | local_irq_save(flags); | 356 | local_irq_save(flags); |
| 357 | 357 | ||
| 358 | for(i = 0; i<4; i++) { | 358 | for(i = 0; i<4; i++) { |
| 359 | /* FIXME: this would be >>3 &0x7 on the 32 way */ | 359 | /* FIXME: this would be >>3 &0x7 on the 32 way */ |
| 360 | if(((cpuid >> 2) & 0x03) == i) | 360 | if(((cpuid >> 2) & 0x03) == i) |
| 361 | /* don't lower our own mask! */ | 361 | /* don't lower our own mask! */ |
| 362 | continue; | 362 | continue; |
| 363 | 363 | ||
| 364 | /* masquerade as local Quad CPU */ | 364 | /* masquerade as local Quad CPU */ |
| 365 | outb(QIC_CPUID_ENABLE | i, QIC_PROCESSOR_ID); | 365 | outb(QIC_CPUID_ENABLE | i, QIC_PROCESSOR_ID); |
| 366 | /* enable the startup CPI */ | 366 | /* enable the startup CPI */ |
| 367 | outb(QIC_BOOT_CPI_MASK, QIC_MASK_REGISTER1); | 367 | outb(QIC_BOOT_CPI_MASK, QIC_MASK_REGISTER1); |
| 368 | /* restore cpu id */ | 368 | /* restore cpu id */ |
| 369 | outb(0, QIC_PROCESSOR_ID); | 369 | outb(0, QIC_PROCESSOR_ID); |
| 370 | } | 370 | } |
| 371 | local_irq_restore(flags); | 371 | local_irq_restore(flags); |
| 372 | } | 372 | } |
| 373 | } | 373 | } |
| 374 | 374 | ||
| 375 | 375 | ||
| 376 | /* Set up all the basic stuff: read the SMP config and make all the | 376 | /* Set up all the basic stuff: read the SMP config and make all the |
| 377 | * SMP information reflect only the boot cpu. All others will be | 377 | * SMP information reflect only the boot cpu. All others will be |
| 378 | * brought on-line later. */ | 378 | * brought on-line later. */ |
| 379 | void __init | 379 | void __init |
| 380 | find_smp_config(void) | 380 | find_smp_config(void) |
| 381 | { | 381 | { |
| 382 | int i; | 382 | int i; |
| 383 | 383 | ||
| 384 | boot_cpu_id = hard_smp_processor_id(); | 384 | boot_cpu_id = hard_smp_processor_id(); |
| 385 | 385 | ||
| 386 | printk("VOYAGER SMP: Boot cpu is %d\n", boot_cpu_id); | 386 | printk("VOYAGER SMP: Boot cpu is %d\n", boot_cpu_id); |
| 387 | 387 | ||
| 388 | /* initialize the CPU structures (moved from smp_boot_cpus) */ | 388 | /* initialize the CPU structures (moved from smp_boot_cpus) */ |
| 389 | for(i=0; i<NR_CPUS; i++) { | 389 | for(i=0; i<NR_CPUS; i++) { |
| 390 | cpu_irq_affinity[i] = ~0; | 390 | cpu_irq_affinity[i] = ~0; |
| 391 | } | 391 | } |
| 392 | cpu_online_map = cpumask_of_cpu(boot_cpu_id); | 392 | cpu_online_map = cpumask_of_cpu(boot_cpu_id); |
| 393 | 393 | ||
| 394 | /* The boot CPU must be extended */ | 394 | /* The boot CPU must be extended */ |
| 395 | voyager_extended_vic_processors = 1<<boot_cpu_id; | 395 | voyager_extended_vic_processors = 1<<boot_cpu_id; |
| 396 | /* initially, all of the first 8 cpu's can boot */ | 396 | /* initially, all of the first 8 cpu's can boot */ |
| 397 | voyager_allowed_boot_processors = 0xff; | 397 | voyager_allowed_boot_processors = 0xff; |
| 398 | /* set up everything for just this CPU, we can alter | 398 | /* set up everything for just this CPU, we can alter |
| 399 | * this as we start the other CPUs later */ | 399 | * this as we start the other CPUs later */ |
| 400 | /* now get the CPU disposition from the extended CMOS */ | 400 | /* now get the CPU disposition from the extended CMOS */ |
| 401 | cpus_addr(phys_cpu_present_map)[0] = voyager_extended_cmos_read(VOYAGER_PROCESSOR_PRESENT_MASK); | 401 | cpus_addr(phys_cpu_present_map)[0] = voyager_extended_cmos_read(VOYAGER_PROCESSOR_PRESENT_MASK); |
| 402 | cpus_addr(phys_cpu_present_map)[0] |= voyager_extended_cmos_read(VOYAGER_PROCESSOR_PRESENT_MASK + 1) << 8; | 402 | cpus_addr(phys_cpu_present_map)[0] |= voyager_extended_cmos_read(VOYAGER_PROCESSOR_PRESENT_MASK + 1) << 8; |
| 403 | cpus_addr(phys_cpu_present_map)[0] |= voyager_extended_cmos_read(VOYAGER_PROCESSOR_PRESENT_MASK + 2) << 16; | 403 | cpus_addr(phys_cpu_present_map)[0] |= voyager_extended_cmos_read(VOYAGER_PROCESSOR_PRESENT_MASK + 2) << 16; |
| 404 | cpus_addr(phys_cpu_present_map)[0] |= voyager_extended_cmos_read(VOYAGER_PROCESSOR_PRESENT_MASK + 3) << 24; | 404 | cpus_addr(phys_cpu_present_map)[0] |= voyager_extended_cmos_read(VOYAGER_PROCESSOR_PRESENT_MASK + 3) << 24; |
| 405 | printk("VOYAGER SMP: phys_cpu_present_map = 0x%lx\n", cpus_addr(phys_cpu_present_map)[0]); | 405 | printk("VOYAGER SMP: phys_cpu_present_map = 0x%lx\n", cpus_addr(phys_cpu_present_map)[0]); |
| 406 | /* Here we set up the VIC to enable SMP */ | 406 | /* Here we set up the VIC to enable SMP */ |
| 407 | /* enable the CPIs by writing the base vector to their register */ | 407 | /* enable the CPIs by writing the base vector to their register */ |
| 408 | outb(VIC_DEFAULT_CPI_BASE, VIC_CPI_BASE_REGISTER); | 408 | outb(VIC_DEFAULT_CPI_BASE, VIC_CPI_BASE_REGISTER); |
| 409 | outb(1, VIC_REDIRECT_REGISTER_1); | 409 | outb(1, VIC_REDIRECT_REGISTER_1); |
| 410 | /* set the claim registers for static routing --- Boot CPU gets | 410 | /* set the claim registers for static routing --- Boot CPU gets |
| 411 | * all interrupts untill all other CPUs started */ | 411 | * all interrupts untill all other CPUs started */ |
| 412 | outb(0xff, VIC_CLAIM_REGISTER_0); | 412 | outb(0xff, VIC_CLAIM_REGISTER_0); |
| 413 | outb(0xff, VIC_CLAIM_REGISTER_1); | 413 | outb(0xff, VIC_CLAIM_REGISTER_1); |
| 414 | /* Set the Primary and Secondary Microchannel vector | 414 | /* Set the Primary and Secondary Microchannel vector |
| 415 | * bases to be the same as the ordinary interrupts | 415 | * bases to be the same as the ordinary interrupts |
| 416 | * | 416 | * |
| 417 | * FIXME: This would be more efficient using separate | 417 | * FIXME: This would be more efficient using separate |
| 418 | * vectors. */ | 418 | * vectors. */ |
| 419 | outb(FIRST_EXTERNAL_VECTOR, VIC_PRIMARY_MC_BASE); | 419 | outb(FIRST_EXTERNAL_VECTOR, VIC_PRIMARY_MC_BASE); |
| 420 | outb(FIRST_EXTERNAL_VECTOR, VIC_SECONDARY_MC_BASE); | 420 | outb(FIRST_EXTERNAL_VECTOR, VIC_SECONDARY_MC_BASE); |
| 421 | 421 | ||
| 422 | /* Finally tell the firmware that we're driving */ | 422 | /* Finally tell the firmware that we're driving */ |
| 423 | outb(inb(VOYAGER_SUS_IN_CONTROL_PORT) | VOYAGER_IN_CONTROL_FLAG, | 423 | outb(inb(VOYAGER_SUS_IN_CONTROL_PORT) | VOYAGER_IN_CONTROL_FLAG, |
| 424 | VOYAGER_SUS_IN_CONTROL_PORT); | 424 | VOYAGER_SUS_IN_CONTROL_PORT); |
| 425 | 425 | ||
| 426 | current_thread_info()->cpu = boot_cpu_id; | 426 | current_thread_info()->cpu = boot_cpu_id; |
| 427 | } | 427 | } |
| 428 | 428 | ||
| 429 | /* | 429 | /* |
| 430 | * The bootstrap kernel entry code has set these up. Save them | 430 | * The bootstrap kernel entry code has set these up. Save them |
| 431 | * for a given CPU, id is physical */ | 431 | * for a given CPU, id is physical */ |
| 432 | void __init | 432 | void __init |
| 433 | smp_store_cpu_info(int id) | 433 | smp_store_cpu_info(int id) |
| 434 | { | 434 | { |
| 435 | struct cpuinfo_x86 *c=&cpu_data[id]; | 435 | struct cpuinfo_x86 *c=&cpu_data[id]; |
| 436 | 436 | ||
| 437 | *c = boot_cpu_data; | 437 | *c = boot_cpu_data; |
| 438 | 438 | ||
| 439 | identify_cpu(c); | 439 | identify_cpu(c); |
| 440 | } | 440 | } |
| 441 | 441 | ||
| 442 | /* set up the trampoline and return the physical address of the code */ | 442 | /* set up the trampoline and return the physical address of the code */ |
| 443 | static __u32 __init | 443 | static __u32 __init |
| 444 | setup_trampoline(void) | 444 | setup_trampoline(void) |
| 445 | { | 445 | { |
| 446 | /* these two are global symbols in trampoline.S */ | 446 | /* these two are global symbols in trampoline.S */ |
| 447 | extern __u8 trampoline_end[]; | 447 | extern __u8 trampoline_end[]; |
| 448 | extern __u8 trampoline_data[]; | 448 | extern __u8 trampoline_data[]; |
| 449 | 449 | ||
| 450 | memcpy((__u8 *)trampoline_base, trampoline_data, | 450 | memcpy((__u8 *)trampoline_base, trampoline_data, |
| 451 | trampoline_end - trampoline_data); | 451 | trampoline_end - trampoline_data); |
| 452 | return virt_to_phys((__u8 *)trampoline_base); | 452 | return virt_to_phys((__u8 *)trampoline_base); |
| 453 | } | 453 | } |
| 454 | 454 | ||
| 455 | /* Routine initially called when a non-boot CPU is brought online */ | 455 | /* Routine initially called when a non-boot CPU is brought online */ |
| 456 | static void __init | 456 | static void __init |
| 457 | start_secondary(void *unused) | 457 | start_secondary(void *unused) |
| 458 | { | 458 | { |
| 459 | __u8 cpuid = hard_smp_processor_id(); | 459 | __u8 cpuid = hard_smp_processor_id(); |
| 460 | /* external functions not defined in the headers */ | 460 | /* external functions not defined in the headers */ |
| 461 | extern void calibrate_delay(void); | 461 | extern void calibrate_delay(void); |
| 462 | 462 | ||
| 463 | cpu_init(); | 463 | cpu_init(); |
| 464 | 464 | ||
| 465 | /* OK, we're in the routine */ | 465 | /* OK, we're in the routine */ |
| 466 | ack_CPI(VIC_CPU_BOOT_CPI); | 466 | ack_CPI(VIC_CPU_BOOT_CPI); |
| 467 | 467 | ||
| 468 | /* setup the 8259 master slave pair belonging to this CPU --- | 468 | /* setup the 8259 master slave pair belonging to this CPU --- |
| 469 | * we won't actually receive any until the boot CPU | 469 | * we won't actually receive any until the boot CPU |
| 470 | * relinquishes it's static routing mask */ | 470 | * relinquishes it's static routing mask */ |
| 471 | vic_setup_pic(); | 471 | vic_setup_pic(); |
| 472 | 472 | ||
| 473 | qic_setup(); | 473 | qic_setup(); |
| 474 | 474 | ||
| 475 | if(is_cpu_quad() && !is_cpu_vic_boot()) { | 475 | if(is_cpu_quad() && !is_cpu_vic_boot()) { |
| 476 | /* clear the boot CPI */ | 476 | /* clear the boot CPI */ |
| 477 | __u8 dummy; | 477 | __u8 dummy; |
| 478 | 478 | ||
| 479 | dummy = voyager_quad_cpi_addr[cpuid]->qic_cpi[VIC_CPU_BOOT_CPI].cpi; | 479 | dummy = voyager_quad_cpi_addr[cpuid]->qic_cpi[VIC_CPU_BOOT_CPI].cpi; |
| 480 | printk("read dummy %d\n", dummy); | 480 | printk("read dummy %d\n", dummy); |
| 481 | } | 481 | } |
| 482 | 482 | ||
| 483 | /* lower the mask to receive CPIs */ | 483 | /* lower the mask to receive CPIs */ |
| 484 | vic_enable_cpi(); | 484 | vic_enable_cpi(); |
| 485 | 485 | ||
| 486 | VDEBUG(("VOYAGER SMP: CPU%d, stack at about %p\n", cpuid, &cpuid)); | 486 | VDEBUG(("VOYAGER SMP: CPU%d, stack at about %p\n", cpuid, &cpuid)); |
| 487 | 487 | ||
| 488 | /* enable interrupts */ | 488 | /* enable interrupts */ |
| 489 | local_irq_enable(); | 489 | local_irq_enable(); |
| 490 | 490 | ||
| 491 | /* get our bogomips */ | 491 | /* get our bogomips */ |
| 492 | calibrate_delay(); | 492 | calibrate_delay(); |
| 493 | 493 | ||
| 494 | /* save our processor parameters */ | 494 | /* save our processor parameters */ |
| 495 | smp_store_cpu_info(cpuid); | 495 | smp_store_cpu_info(cpuid); |
| 496 | 496 | ||
| 497 | /* if we're a quad, we may need to bootstrap other CPUs */ | 497 | /* if we're a quad, we may need to bootstrap other CPUs */ |
| 498 | do_quad_bootstrap(); | 498 | do_quad_bootstrap(); |
| 499 | 499 | ||
| 500 | /* FIXME: this is rather a poor hack to prevent the CPU | 500 | /* FIXME: this is rather a poor hack to prevent the CPU |
| 501 | * activating softirqs while it's supposed to be waiting for | 501 | * activating softirqs while it's supposed to be waiting for |
| 502 | * permission to proceed. Without this, the new per CPU stuff | 502 | * permission to proceed. Without this, the new per CPU stuff |
| 503 | * in the softirqs will fail */ | 503 | * in the softirqs will fail */ |
| 504 | local_irq_disable(); | 504 | local_irq_disable(); |
| 505 | cpu_set(cpuid, cpu_callin_map); | 505 | cpu_set(cpuid, cpu_callin_map); |
| 506 | 506 | ||
| 507 | /* signal that we're done */ | 507 | /* signal that we're done */ |
| 508 | cpu_booted_map = 1; | 508 | cpu_booted_map = 1; |
| 509 | 509 | ||
| 510 | while (!cpu_isset(cpuid, smp_commenced_mask)) | 510 | while (!cpu_isset(cpuid, smp_commenced_mask)) |
| 511 | rep_nop(); | 511 | rep_nop(); |
| 512 | local_irq_enable(); | 512 | local_irq_enable(); |
| 513 | 513 | ||
| 514 | local_flush_tlb(); | 514 | local_flush_tlb(); |
| 515 | 515 | ||
| 516 | cpu_set(cpuid, cpu_online_map); | 516 | cpu_set(cpuid, cpu_online_map); |
| 517 | wmb(); | 517 | wmb(); |
| 518 | cpu_idle(); | 518 | cpu_idle(); |
| 519 | } | 519 | } |
| 520 | 520 | ||
| 521 | 521 | ||
| 522 | /* Routine to kick start the given CPU and wait for it to report ready | 522 | /* Routine to kick start the given CPU and wait for it to report ready |
| 523 | * (or timeout in startup). When this routine returns, the requested | 523 | * (or timeout in startup). When this routine returns, the requested |
| 524 | * CPU is either fully running and configured or known to be dead. | 524 | * CPU is either fully running and configured or known to be dead. |
| 525 | * | 525 | * |
| 526 | * We call this routine sequentially 1 CPU at a time, so no need for | 526 | * We call this routine sequentially 1 CPU at a time, so no need for |
| 527 | * locking */ | 527 | * locking */ |
| 528 | 528 | ||
| 529 | static void __init | 529 | static void __init |
| 530 | do_boot_cpu(__u8 cpu) | 530 | do_boot_cpu(__u8 cpu) |
| 531 | { | 531 | { |
| 532 | struct task_struct *idle; | 532 | struct task_struct *idle; |
| 533 | int timeout; | 533 | int timeout; |
| 534 | unsigned long flags; | 534 | unsigned long flags; |
| 535 | int quad_boot = (1<<cpu) & voyager_quad_processors | 535 | int quad_boot = (1<<cpu) & voyager_quad_processors |
| 536 | & ~( voyager_extended_vic_processors | 536 | & ~( voyager_extended_vic_processors |
| 537 | & voyager_allowed_boot_processors); | 537 | & voyager_allowed_boot_processors); |
| 538 | 538 | ||
| 539 | /* For the 486, we can't use the 4Mb page table trick, so | 539 | /* For the 486, we can't use the 4Mb page table trick, so |
| 540 | * must map a region of memory */ | 540 | * must map a region of memory */ |
| 541 | #ifdef CONFIG_M486 | 541 | #ifdef CONFIG_M486 |
| 542 | int i; | 542 | int i; |
| 543 | unsigned long *page_table_copies = (unsigned long *) | 543 | unsigned long *page_table_copies = (unsigned long *) |
| 544 | __get_free_page(GFP_KERNEL); | 544 | __get_free_page(GFP_KERNEL); |
| 545 | #endif | 545 | #endif |
| 546 | pgd_t orig_swapper_pg_dir0; | 546 | pgd_t orig_swapper_pg_dir0; |
| 547 | 547 | ||
| 548 | /* This is an area in head.S which was used to set up the | 548 | /* This is an area in head.S which was used to set up the |
| 549 | * initial kernel stack. We need to alter this to give the | 549 | * initial kernel stack. We need to alter this to give the |
| 550 | * booting CPU a new stack (taken from its idle process) */ | 550 | * booting CPU a new stack (taken from its idle process) */ |
| 551 | extern struct { | 551 | extern struct { |
| 552 | __u8 *esp; | 552 | __u8 *esp; |
| 553 | unsigned short ss; | 553 | unsigned short ss; |
| 554 | } stack_start; | 554 | } stack_start; |
| 555 | /* This is the format of the CPI IDT gate (in real mode) which | 555 | /* This is the format of the CPI IDT gate (in real mode) which |
| 556 | * we're hijacking to boot the CPU */ | 556 | * we're hijacking to boot the CPU */ |
| 557 | union IDTFormat { | 557 | union IDTFormat { |
| 558 | struct seg { | 558 | struct seg { |
| 559 | __u16 Offset; | 559 | __u16 Offset; |
| 560 | __u16 Segment; | 560 | __u16 Segment; |
| 561 | } idt; | 561 | } idt; |
| 562 | __u32 val; | 562 | __u32 val; |
| 563 | } hijack_source; | 563 | } hijack_source; |
| 564 | 564 | ||
| 565 | __u32 *hijack_vector; | 565 | __u32 *hijack_vector; |
| 566 | __u32 start_phys_address = setup_trampoline(); | 566 | __u32 start_phys_address = setup_trampoline(); |
| 567 | 567 | ||
| 568 | /* There's a clever trick to this: The linux trampoline is | 568 | /* There's a clever trick to this: The linux trampoline is |
| 569 | * compiled to begin at absolute location zero, so make the | 569 | * compiled to begin at absolute location zero, so make the |
| 570 | * address zero but have the data segment selector compensate | 570 | * address zero but have the data segment selector compensate |
| 571 | * for the actual address */ | 571 | * for the actual address */ |
| 572 | hijack_source.idt.Offset = start_phys_address & 0x000F; | 572 | hijack_source.idt.Offset = start_phys_address & 0x000F; |
| 573 | hijack_source.idt.Segment = (start_phys_address >> 4) & 0xFFFF; | 573 | hijack_source.idt.Segment = (start_phys_address >> 4) & 0xFFFF; |
| 574 | 574 | ||
| 575 | cpucount++; | 575 | cpucount++; |
| 576 | idle = fork_idle(cpu); | 576 | idle = fork_idle(cpu); |
| 577 | if(IS_ERR(idle)) | 577 | if(IS_ERR(idle)) |
| 578 | panic("failed fork for CPU%d", cpu); | 578 | panic("failed fork for CPU%d", cpu); |
| 579 | idle->thread.eip = (unsigned long) start_secondary; | 579 | idle->thread.eip = (unsigned long) start_secondary; |
| 580 | /* init_tasks (in sched.c) is indexed logically */ | 580 | /* init_tasks (in sched.c) is indexed logically */ |
| 581 | stack_start.esp = (void *) idle->thread.esp; | 581 | stack_start.esp = (void *) idle->thread.esp; |
| 582 | 582 | ||
| 583 | irq_ctx_init(cpu); | 583 | irq_ctx_init(cpu); |
| 584 | 584 | ||
| 585 | /* Note: Don't modify initial ss override */ | 585 | /* Note: Don't modify initial ss override */ |
| 586 | VDEBUG(("VOYAGER SMP: Booting CPU%d at 0x%lx[%x:%x], stack %p\n", cpu, | 586 | VDEBUG(("VOYAGER SMP: Booting CPU%d at 0x%lx[%x:%x], stack %p\n", cpu, |
| 587 | (unsigned long)hijack_source.val, hijack_source.idt.Segment, | 587 | (unsigned long)hijack_source.val, hijack_source.idt.Segment, |
| 588 | hijack_source.idt.Offset, stack_start.esp)); | 588 | hijack_source.idt.Offset, stack_start.esp)); |
| 589 | /* set the original swapper_pg_dir[0] to map 0 to 4Mb transparently | 589 | /* set the original swapper_pg_dir[0] to map 0 to 4Mb transparently |
| 590 | * (so that the booting CPU can find start_32 */ | 590 | * (so that the booting CPU can find start_32 */ |
| 591 | orig_swapper_pg_dir0 = swapper_pg_dir[0]; | 591 | orig_swapper_pg_dir0 = swapper_pg_dir[0]; |
| 592 | #ifdef CONFIG_M486 | 592 | #ifdef CONFIG_M486 |
| 593 | if(page_table_copies == NULL) | 593 | if(page_table_copies == NULL) |
| 594 | panic("No free memory for 486 page tables\n"); | 594 | panic("No free memory for 486 page tables\n"); |
| 595 | for(i = 0; i < PAGE_SIZE/sizeof(unsigned long); i++) | 595 | for(i = 0; i < PAGE_SIZE/sizeof(unsigned long); i++) |
| 596 | page_table_copies[i] = (i * PAGE_SIZE) | 596 | page_table_copies[i] = (i * PAGE_SIZE) |
| 597 | | _PAGE_RW | _PAGE_USER | _PAGE_PRESENT; | 597 | | _PAGE_RW | _PAGE_USER | _PAGE_PRESENT; |
| 598 | 598 | ||
| 599 | ((unsigned long *)swapper_pg_dir)[0] = | 599 | ((unsigned long *)swapper_pg_dir)[0] = |
| 600 | ((virt_to_phys(page_table_copies)) & PAGE_MASK) | 600 | ((virt_to_phys(page_table_copies)) & PAGE_MASK) |
| 601 | | _PAGE_RW | _PAGE_USER | _PAGE_PRESENT; | 601 | | _PAGE_RW | _PAGE_USER | _PAGE_PRESENT; |
| 602 | #else | 602 | #else |
| 603 | ((unsigned long *)swapper_pg_dir)[0] = | 603 | ((unsigned long *)swapper_pg_dir)[0] = |
| 604 | (virt_to_phys(pg0) & PAGE_MASK) | 604 | (virt_to_phys(pg0) & PAGE_MASK) |
| 605 | | _PAGE_RW | _PAGE_USER | _PAGE_PRESENT; | 605 | | _PAGE_RW | _PAGE_USER | _PAGE_PRESENT; |
| 606 | #endif | 606 | #endif |
| 607 | 607 | ||
| 608 | if(quad_boot) { | 608 | if(quad_boot) { |
| 609 | printk("CPU %d: non extended Quad boot\n", cpu); | 609 | printk("CPU %d: non extended Quad boot\n", cpu); |
| 610 | hijack_vector = (__u32 *)phys_to_virt((VIC_CPU_BOOT_CPI + QIC_DEFAULT_CPI_BASE)*4); | 610 | hijack_vector = (__u32 *)phys_to_virt((VIC_CPU_BOOT_CPI + QIC_DEFAULT_CPI_BASE)*4); |
| 611 | *hijack_vector = hijack_source.val; | 611 | *hijack_vector = hijack_source.val; |
| 612 | } else { | 612 | } else { |
| 613 | printk("CPU%d: extended VIC boot\n", cpu); | 613 | printk("CPU%d: extended VIC boot\n", cpu); |
| 614 | hijack_vector = (__u32 *)phys_to_virt((VIC_CPU_BOOT_CPI + VIC_DEFAULT_CPI_BASE)*4); | 614 | hijack_vector = (__u32 *)phys_to_virt((VIC_CPU_BOOT_CPI + VIC_DEFAULT_CPI_BASE)*4); |
| 615 | *hijack_vector = hijack_source.val; | 615 | *hijack_vector = hijack_source.val; |
| 616 | /* VIC errata, may also receive interrupt at this address */ | 616 | /* VIC errata, may also receive interrupt at this address */ |
| 617 | hijack_vector = (__u32 *)phys_to_virt((VIC_CPU_BOOT_ERRATA_CPI + VIC_DEFAULT_CPI_BASE)*4); | 617 | hijack_vector = (__u32 *)phys_to_virt((VIC_CPU_BOOT_ERRATA_CPI + VIC_DEFAULT_CPI_BASE)*4); |
| 618 | *hijack_vector = hijack_source.val; | 618 | *hijack_vector = hijack_source.val; |
| 619 | } | 619 | } |
| 620 | /* All non-boot CPUs start with interrupts fully masked. Need | 620 | /* All non-boot CPUs start with interrupts fully masked. Need |
| 621 | * to lower the mask of the CPI we're about to send. We do | 621 | * to lower the mask of the CPI we're about to send. We do |
| 622 | * this in the VIC by masquerading as the processor we're | 622 | * this in the VIC by masquerading as the processor we're |
| 623 | * about to boot and lowering its interrupt mask */ | 623 | * about to boot and lowering its interrupt mask */ |
| 624 | local_irq_save(flags); | 624 | local_irq_save(flags); |
| 625 | if(quad_boot) { | 625 | if(quad_boot) { |
| 626 | send_one_QIC_CPI(cpu, VIC_CPU_BOOT_CPI); | 626 | send_one_QIC_CPI(cpu, VIC_CPU_BOOT_CPI); |
| 627 | } else { | 627 | } else { |
| 628 | outb(VIC_CPU_MASQUERADE_ENABLE | cpu, VIC_PROCESSOR_ID); | 628 | outb(VIC_CPU_MASQUERADE_ENABLE | cpu, VIC_PROCESSOR_ID); |
| 629 | /* here we're altering registers belonging to `cpu' */ | 629 | /* here we're altering registers belonging to `cpu' */ |
| 630 | 630 | ||
| 631 | outb(VIC_BOOT_INTERRUPT_MASK, 0x21); | 631 | outb(VIC_BOOT_INTERRUPT_MASK, 0x21); |
| 632 | /* now go back to our original identity */ | 632 | /* now go back to our original identity */ |
| 633 | outb(boot_cpu_id, VIC_PROCESSOR_ID); | 633 | outb(boot_cpu_id, VIC_PROCESSOR_ID); |
| 634 | 634 | ||
| 635 | /* and boot the CPU */ | 635 | /* and boot the CPU */ |
| 636 | 636 | ||
| 637 | send_CPI((1<<cpu), VIC_CPU_BOOT_CPI); | 637 | send_CPI((1<<cpu), VIC_CPU_BOOT_CPI); |
| 638 | } | 638 | } |
| 639 | cpu_booted_map = 0; | 639 | cpu_booted_map = 0; |
| 640 | local_irq_restore(flags); | 640 | local_irq_restore(flags); |
| 641 | 641 | ||
| 642 | /* now wait for it to become ready (or timeout) */ | 642 | /* now wait for it to become ready (or timeout) */ |
| 643 | for(timeout = 0; timeout < 50000; timeout++) { | 643 | for(timeout = 0; timeout < 50000; timeout++) { |
| 644 | if(cpu_booted_map) | 644 | if(cpu_booted_map) |
| 645 | break; | 645 | break; |
| 646 | udelay(100); | 646 | udelay(100); |
| 647 | } | 647 | } |
| 648 | /* reset the page table */ | 648 | /* reset the page table */ |
| 649 | swapper_pg_dir[0] = orig_swapper_pg_dir0; | 649 | swapper_pg_dir[0] = orig_swapper_pg_dir0; |
| 650 | local_flush_tlb(); | 650 | local_flush_tlb(); |
| 651 | #ifdef CONFIG_M486 | 651 | #ifdef CONFIG_M486 |
| 652 | free_page((unsigned long)page_table_copies); | 652 | free_page((unsigned long)page_table_copies); |
| 653 | #endif | 653 | #endif |
| 654 | 654 | ||
| 655 | if (cpu_booted_map) { | 655 | if (cpu_booted_map) { |
| 656 | VDEBUG(("CPU%d: Booted successfully, back in CPU %d\n", | 656 | VDEBUG(("CPU%d: Booted successfully, back in CPU %d\n", |
| 657 | cpu, smp_processor_id())); | 657 | cpu, smp_processor_id())); |
| 658 | 658 | ||
| 659 | printk("CPU%d: ", cpu); | 659 | printk("CPU%d: ", cpu); |
| 660 | print_cpu_info(&cpu_data[cpu]); | 660 | print_cpu_info(&cpu_data[cpu]); |
| 661 | wmb(); | 661 | wmb(); |
| 662 | cpu_set(cpu, cpu_callout_map); | 662 | cpu_set(cpu, cpu_callout_map); |
| 663 | } | 663 | } |
| 664 | else { | 664 | else { |
| 665 | printk("CPU%d FAILED TO BOOT: ", cpu); | 665 | printk("CPU%d FAILED TO BOOT: ", cpu); |
| 666 | if (*((volatile unsigned char *)phys_to_virt(start_phys_address))==0xA5) | 666 | if (*((volatile unsigned char *)phys_to_virt(start_phys_address))==0xA5) |
| 667 | printk("Stuck.\n"); | 667 | printk("Stuck.\n"); |
| 668 | else | 668 | else |
| 669 | printk("Not responding.\n"); | 669 | printk("Not responding.\n"); |
| 670 | 670 | ||
| 671 | cpucount--; | 671 | cpucount--; |
| 672 | } | 672 | } |
| 673 | } | 673 | } |
| 674 | 674 | ||
| 675 | void __init | 675 | void __init |
| 676 | smp_boot_cpus(void) | 676 | smp_boot_cpus(void) |
| 677 | { | 677 | { |
| 678 | int i; | 678 | int i; |
| 679 | 679 | ||
| 680 | /* CAT BUS initialisation must be done after the memory */ | 680 | /* CAT BUS initialisation must be done after the memory */ |
| 681 | /* FIXME: The L4 has a catbus too, it just needs to be | 681 | /* FIXME: The L4 has a catbus too, it just needs to be |
| 682 | * accessed in a totally different way */ | 682 | * accessed in a totally different way */ |
| 683 | if(voyager_level == 5) { | 683 | if(voyager_level == 5) { |
| 684 | voyager_cat_init(); | 684 | voyager_cat_init(); |
| 685 | 685 | ||
| 686 | /* now that the cat has probed the Voyager System Bus, sanity | 686 | /* now that the cat has probed the Voyager System Bus, sanity |
| 687 | * check the cpu map */ | 687 | * check the cpu map */ |
| 688 | if( ((voyager_quad_processors | voyager_extended_vic_processors) | 688 | if( ((voyager_quad_processors | voyager_extended_vic_processors) |
| 689 | & cpus_addr(phys_cpu_present_map)[0]) != cpus_addr(phys_cpu_present_map)[0]) { | 689 | & cpus_addr(phys_cpu_present_map)[0]) != cpus_addr(phys_cpu_present_map)[0]) { |
| 690 | /* should panic */ | 690 | /* should panic */ |
| 691 | printk("\n\n***WARNING*** Sanity check of CPU present map FAILED\n"); | 691 | printk("\n\n***WARNING*** Sanity check of CPU present map FAILED\n"); |
| 692 | } | 692 | } |
| 693 | } else if(voyager_level == 4) | 693 | } else if(voyager_level == 4) |
| 694 | voyager_extended_vic_processors = cpus_addr(phys_cpu_present_map)[0]; | 694 | voyager_extended_vic_processors = cpus_addr(phys_cpu_present_map)[0]; |
| 695 | 695 | ||
| 696 | /* this sets up the idle task to run on the current cpu */ | 696 | /* this sets up the idle task to run on the current cpu */ |
| 697 | voyager_extended_cpus = 1; | 697 | voyager_extended_cpus = 1; |
| 698 | /* Remove the global_irq_holder setting, it triggers a BUG() on | 698 | /* Remove the global_irq_holder setting, it triggers a BUG() on |
| 699 | * schedule at the moment */ | 699 | * schedule at the moment */ |
| 700 | //global_irq_holder = boot_cpu_id; | 700 | //global_irq_holder = boot_cpu_id; |
| 701 | 701 | ||
| 702 | /* FIXME: Need to do something about this but currently only works | 702 | /* FIXME: Need to do something about this but currently only works |
| 703 | * on CPUs with a tsc which none of mine have. | 703 | * on CPUs with a tsc which none of mine have. |
| 704 | smp_tune_scheduling(); | 704 | smp_tune_scheduling(); |
| 705 | */ | 705 | */ |
| 706 | smp_store_cpu_info(boot_cpu_id); | 706 | smp_store_cpu_info(boot_cpu_id); |
| 707 | printk("CPU%d: ", boot_cpu_id); | 707 | printk("CPU%d: ", boot_cpu_id); |
| 708 | print_cpu_info(&cpu_data[boot_cpu_id]); | 708 | print_cpu_info(&cpu_data[boot_cpu_id]); |
| 709 | 709 | ||
| 710 | if(is_cpu_quad()) { | 710 | if(is_cpu_quad()) { |
| 711 | /* booting on a Quad CPU */ | 711 | /* booting on a Quad CPU */ |
| 712 | printk("VOYAGER SMP: Boot CPU is Quad\n"); | 712 | printk("VOYAGER SMP: Boot CPU is Quad\n"); |
| 713 | qic_setup(); | 713 | qic_setup(); |
| 714 | do_quad_bootstrap(); | 714 | do_quad_bootstrap(); |
| 715 | } | 715 | } |
| 716 | 716 | ||
| 717 | /* enable our own CPIs */ | 717 | /* enable our own CPIs */ |
| 718 | vic_enable_cpi(); | 718 | vic_enable_cpi(); |
| 719 | 719 | ||
| 720 | cpu_set(boot_cpu_id, cpu_online_map); | 720 | cpu_set(boot_cpu_id, cpu_online_map); |
| 721 | cpu_set(boot_cpu_id, cpu_callout_map); | 721 | cpu_set(boot_cpu_id, cpu_callout_map); |
| 722 | 722 | ||
| 723 | /* loop over all the extended VIC CPUs and boot them. The | 723 | /* loop over all the extended VIC CPUs and boot them. The |
| 724 | * Quad CPUs must be bootstrapped by their extended VIC cpu */ | 724 | * Quad CPUs must be bootstrapped by their extended VIC cpu */ |
| 725 | for(i = 0; i < NR_CPUS; i++) { | 725 | for(i = 0; i < NR_CPUS; i++) { |
| 726 | if(i == boot_cpu_id || !cpu_isset(i, phys_cpu_present_map)) | 726 | if(i == boot_cpu_id || !cpu_isset(i, phys_cpu_present_map)) |
| 727 | continue; | 727 | continue; |
| 728 | do_boot_cpu(i); | 728 | do_boot_cpu(i); |
| 729 | /* This udelay seems to be needed for the Quad boots | 729 | /* This udelay seems to be needed for the Quad boots |
| 730 | * don't remove unless you know what you're doing */ | 730 | * don't remove unless you know what you're doing */ |
| 731 | udelay(1000); | 731 | udelay(1000); |
| 732 | } | 732 | } |
| 733 | /* we could compute the total bogomips here, but why bother?, | 733 | /* we could compute the total bogomips here, but why bother?, |
| 734 | * Code added from smpboot.c */ | 734 | * Code added from smpboot.c */ |
| 735 | { | 735 | { |
| 736 | unsigned long bogosum = 0; | 736 | unsigned long bogosum = 0; |
| 737 | for (i = 0; i < NR_CPUS; i++) | 737 | for (i = 0; i < NR_CPUS; i++) |
| 738 | if (cpu_isset(i, cpu_online_map)) | 738 | if (cpu_isset(i, cpu_online_map)) |
| 739 | bogosum += cpu_data[i].loops_per_jiffy; | 739 | bogosum += cpu_data[i].loops_per_jiffy; |
| 740 | printk(KERN_INFO "Total of %d processors activated (%lu.%02lu BogoMIPS).\n", | 740 | printk(KERN_INFO "Total of %d processors activated (%lu.%02lu BogoMIPS).\n", |
| 741 | cpucount+1, | 741 | cpucount+1, |
| 742 | bogosum/(500000/HZ), | 742 | bogosum/(500000/HZ), |
| 743 | (bogosum/(5000/HZ))%100); | 743 | (bogosum/(5000/HZ))%100); |
| 744 | } | 744 | } |
| 745 | voyager_extended_cpus = hweight32(voyager_extended_vic_processors); | 745 | voyager_extended_cpus = hweight32(voyager_extended_vic_processors); |
| 746 | printk("VOYAGER: Extended (interrupt handling CPUs): %d, non-extended: %d\n", voyager_extended_cpus, num_booting_cpus() - voyager_extended_cpus); | 746 | printk("VOYAGER: Extended (interrupt handling CPUs): %d, non-extended: %d\n", voyager_extended_cpus, num_booting_cpus() - voyager_extended_cpus); |
| 747 | /* that's it, switch to symmetric mode */ | 747 | /* that's it, switch to symmetric mode */ |
| 748 | outb(0, VIC_PRIORITY_REGISTER); | 748 | outb(0, VIC_PRIORITY_REGISTER); |
| 749 | outb(0, VIC_CLAIM_REGISTER_0); | 749 | outb(0, VIC_CLAIM_REGISTER_0); |
| 750 | outb(0, VIC_CLAIM_REGISTER_1); | 750 | outb(0, VIC_CLAIM_REGISTER_1); |
| 751 | 751 | ||
| 752 | VDEBUG(("VOYAGER SMP: Booted with %d CPUs\n", num_booting_cpus())); | 752 | VDEBUG(("VOYAGER SMP: Booted with %d CPUs\n", num_booting_cpus())); |
| 753 | } | 753 | } |
| 754 | 754 | ||
| 755 | /* Reload the secondary CPUs task structure (this function does not | 755 | /* Reload the secondary CPUs task structure (this function does not |
| 756 | * return ) */ | 756 | * return ) */ |
| 757 | void __init | 757 | void __init |
| 758 | initialize_secondary(void) | 758 | initialize_secondary(void) |
| 759 | { | 759 | { |
| 760 | #if 0 | 760 | #if 0 |
| 761 | // AC kernels only | 761 | // AC kernels only |
| 762 | set_current(hard_get_current()); | 762 | set_current(hard_get_current()); |
| 763 | #endif | 763 | #endif |
| 764 | 764 | ||
| 765 | /* | 765 | /* |
| 766 | * We don't actually need to load the full TSS, | 766 | * We don't actually need to load the full TSS, |
| 767 | * basically just the stack pointer and the eip. | 767 | * basically just the stack pointer and the eip. |
| 768 | */ | 768 | */ |
| 769 | 769 | ||
| 770 | asm volatile( | 770 | asm volatile( |
| 771 | "movl %0,%%esp\n\t" | 771 | "movl %0,%%esp\n\t" |
| 772 | "jmp *%1" | 772 | "jmp *%1" |
| 773 | : | 773 | : |
| 774 | :"r" (current->thread.esp),"r" (current->thread.eip)); | 774 | :"r" (current->thread.esp),"r" (current->thread.eip)); |
| 775 | } | 775 | } |
| 776 | 776 | ||
| 777 | /* handle a Voyager SYS_INT -- If we don't, the base board will | 777 | /* handle a Voyager SYS_INT -- If we don't, the base board will |
| 778 | * panic the system. | 778 | * panic the system. |
| 779 | * | 779 | * |
| 780 | * System interrupts occur because some problem was detected on the | 780 | * System interrupts occur because some problem was detected on the |
| 781 | * various busses. To find out what you have to probe all the | 781 | * various busses. To find out what you have to probe all the |
| 782 | * hardware via the CAT bus. FIXME: At the moment we do nothing. */ | 782 | * hardware via the CAT bus. FIXME: At the moment we do nothing. */ |
| 783 | fastcall void | 783 | fastcall void |
| 784 | smp_vic_sys_interrupt(struct pt_regs *regs) | 784 | smp_vic_sys_interrupt(struct pt_regs *regs) |
| 785 | { | 785 | { |
| 786 | ack_CPI(VIC_SYS_INT); | 786 | ack_CPI(VIC_SYS_INT); |
| 787 | printk("Voyager SYSTEM INTERRUPT\n"); | 787 | printk("Voyager SYSTEM INTERRUPT\n"); |
| 788 | } | 788 | } |
| 789 | 789 | ||
| 790 | /* Handle a voyager CMN_INT; These interrupts occur either because of | 790 | /* Handle a voyager CMN_INT; These interrupts occur either because of |
| 791 | * a system status change or because a single bit memory error | 791 | * a system status change or because a single bit memory error |
| 792 | * occurred. FIXME: At the moment, ignore all this. */ | 792 | * occurred. FIXME: At the moment, ignore all this. */ |
| 793 | fastcall void | 793 | fastcall void |
| 794 | smp_vic_cmn_interrupt(struct pt_regs *regs) | 794 | smp_vic_cmn_interrupt(struct pt_regs *regs) |
| 795 | { | 795 | { |
| 796 | static __u8 in_cmn_int = 0; | 796 | static __u8 in_cmn_int = 0; |
| 797 | static DEFINE_SPINLOCK(cmn_int_lock); | 797 | static DEFINE_SPINLOCK(cmn_int_lock); |
| 798 | 798 | ||
| 799 | /* common ints are broadcast, so make sure we only do this once */ | 799 | /* common ints are broadcast, so make sure we only do this once */ |
| 800 | _raw_spin_lock(&cmn_int_lock); | 800 | _raw_spin_lock(&cmn_int_lock); |
| 801 | if(in_cmn_int) | 801 | if(in_cmn_int) |
| 802 | goto unlock_end; | 802 | goto unlock_end; |
| 803 | 803 | ||
| 804 | in_cmn_int++; | 804 | in_cmn_int++; |
| 805 | _raw_spin_unlock(&cmn_int_lock); | 805 | _raw_spin_unlock(&cmn_int_lock); |
| 806 | 806 | ||
| 807 | VDEBUG(("Voyager COMMON INTERRUPT\n")); | 807 | VDEBUG(("Voyager COMMON INTERRUPT\n")); |
| 808 | 808 | ||
| 809 | if(voyager_level == 5) | 809 | if(voyager_level == 5) |
| 810 | voyager_cat_do_common_interrupt(); | 810 | voyager_cat_do_common_interrupt(); |
| 811 | 811 | ||
| 812 | _raw_spin_lock(&cmn_int_lock); | 812 | _raw_spin_lock(&cmn_int_lock); |
| 813 | in_cmn_int = 0; | 813 | in_cmn_int = 0; |
| 814 | unlock_end: | 814 | unlock_end: |
| 815 | _raw_spin_unlock(&cmn_int_lock); | 815 | _raw_spin_unlock(&cmn_int_lock); |
| 816 | ack_CPI(VIC_CMN_INT); | 816 | ack_CPI(VIC_CMN_INT); |
| 817 | } | 817 | } |
| 818 | 818 | ||
| 819 | /* | 819 | /* |
| 820 | * Reschedule call back. Nothing to do, all the work is done | 820 | * Reschedule call back. Nothing to do, all the work is done |
| 821 | * automatically when we return from the interrupt. */ | 821 | * automatically when we return from the interrupt. */ |
| 822 | static void | 822 | static void |
| 823 | smp_reschedule_interrupt(void) | 823 | smp_reschedule_interrupt(void) |
| 824 | { | 824 | { |
| 825 | /* do nothing */ | 825 | /* do nothing */ |
| 826 | } | 826 | } |
| 827 | 827 | ||
| 828 | static struct mm_struct * flush_mm; | 828 | static struct mm_struct * flush_mm; |
| 829 | static unsigned long flush_va; | 829 | static unsigned long flush_va; |
| 830 | static DEFINE_SPINLOCK(tlbstate_lock); | 830 | static DEFINE_SPINLOCK(tlbstate_lock); |
| 831 | #define FLUSH_ALL 0xffffffff | 831 | #define FLUSH_ALL 0xffffffff |
| 832 | 832 | ||
| 833 | /* | 833 | /* |
| 834 | * We cannot call mmdrop() because we are in interrupt context, | 834 | * We cannot call mmdrop() because we are in interrupt context, |
| 835 | * instead update mm->cpu_vm_mask. | 835 | * instead update mm->cpu_vm_mask. |
| 836 | * | 836 | * |
| 837 | * We need to reload %cr3 since the page tables may be going | 837 | * We need to reload %cr3 since the page tables may be going |
| 838 | * away from under us.. | 838 | * away from under us.. |
| 839 | */ | 839 | */ |
| 840 | static inline void | 840 | static inline void |
| 841 | leave_mm (unsigned long cpu) | 841 | leave_mm (unsigned long cpu) |
| 842 | { | 842 | { |
| 843 | if (per_cpu(cpu_tlbstate, cpu).state == TLBSTATE_OK) | 843 | if (per_cpu(cpu_tlbstate, cpu).state == TLBSTATE_OK) |
| 844 | BUG(); | 844 | BUG(); |
| 845 | cpu_clear(cpu, per_cpu(cpu_tlbstate, cpu).active_mm->cpu_vm_mask); | 845 | cpu_clear(cpu, per_cpu(cpu_tlbstate, cpu).active_mm->cpu_vm_mask); |
| 846 | load_cr3(swapper_pg_dir); | 846 | load_cr3(swapper_pg_dir); |
| 847 | } | 847 | } |
| 848 | 848 | ||
| 849 | 849 | ||
| 850 | /* | 850 | /* |
| 851 | * Invalidate call-back | 851 | * Invalidate call-back |
| 852 | */ | 852 | */ |
| 853 | static void | 853 | static void |
| 854 | smp_invalidate_interrupt(void) | 854 | smp_invalidate_interrupt(void) |
| 855 | { | 855 | { |
| 856 | __u8 cpu = smp_processor_id(); | 856 | __u8 cpu = smp_processor_id(); |
| 857 | 857 | ||
| 858 | if (!test_bit(cpu, &smp_invalidate_needed)) | 858 | if (!test_bit(cpu, &smp_invalidate_needed)) |
| 859 | return; | 859 | return; |
| 860 | /* This will flood messages. Don't uncomment unless you see | 860 | /* This will flood messages. Don't uncomment unless you see |
| 861 | * Problems with cross cpu invalidation | 861 | * Problems with cross cpu invalidation |
| 862 | VDEBUG(("VOYAGER SMP: CPU%d received INVALIDATE_CPI\n", | 862 | VDEBUG(("VOYAGER SMP: CPU%d received INVALIDATE_CPI\n", |
| 863 | smp_processor_id())); | 863 | smp_processor_id())); |
| 864 | */ | 864 | */ |
| 865 | 865 | ||
| 866 | if (flush_mm == per_cpu(cpu_tlbstate, cpu).active_mm) { | 866 | if (flush_mm == per_cpu(cpu_tlbstate, cpu).active_mm) { |
| 867 | if (per_cpu(cpu_tlbstate, cpu).state == TLBSTATE_OK) { | 867 | if (per_cpu(cpu_tlbstate, cpu).state == TLBSTATE_OK) { |
| 868 | if (flush_va == FLUSH_ALL) | 868 | if (flush_va == FLUSH_ALL) |
| 869 | local_flush_tlb(); | 869 | local_flush_tlb(); |
| 870 | else | 870 | else |
| 871 | __flush_tlb_one(flush_va); | 871 | __flush_tlb_one(flush_va); |
| 872 | } else | 872 | } else |
| 873 | leave_mm(cpu); | 873 | leave_mm(cpu); |
| 874 | } | 874 | } |
| 875 | smp_mb__before_clear_bit(); | 875 | smp_mb__before_clear_bit(); |
| 876 | clear_bit(cpu, &smp_invalidate_needed); | 876 | clear_bit(cpu, &smp_invalidate_needed); |
| 877 | smp_mb__after_clear_bit(); | 877 | smp_mb__after_clear_bit(); |
| 878 | } | 878 | } |
| 879 | 879 | ||
| 880 | /* All the new flush operations for 2.4 */ | 880 | /* All the new flush operations for 2.4 */ |
| 881 | 881 | ||
| 882 | 882 | ||
| 883 | /* This routine is called with a physical cpu mask */ | 883 | /* This routine is called with a physical cpu mask */ |
| 884 | static void | 884 | static void |
| 885 | flush_tlb_others (unsigned long cpumask, struct mm_struct *mm, | 885 | flush_tlb_others (unsigned long cpumask, struct mm_struct *mm, |
| 886 | unsigned long va) | 886 | unsigned long va) |
| 887 | { | 887 | { |
| 888 | int stuck = 50000; | 888 | int stuck = 50000; |
| 889 | 889 | ||
| 890 | if (!cpumask) | 890 | if (!cpumask) |
| 891 | BUG(); | 891 | BUG(); |
| 892 | if ((cpumask & cpus_addr(cpu_online_map)[0]) != cpumask) | 892 | if ((cpumask & cpus_addr(cpu_online_map)[0]) != cpumask) |
| 893 | BUG(); | 893 | BUG(); |
| 894 | if (cpumask & (1 << smp_processor_id())) | 894 | if (cpumask & (1 << smp_processor_id())) |
| 895 | BUG(); | 895 | BUG(); |
| 896 | if (!mm) | 896 | if (!mm) |
| 897 | BUG(); | 897 | BUG(); |
| 898 | 898 | ||
| 899 | spin_lock(&tlbstate_lock); | 899 | spin_lock(&tlbstate_lock); |
| 900 | 900 | ||
| 901 | flush_mm = mm; | 901 | flush_mm = mm; |
| 902 | flush_va = va; | 902 | flush_va = va; |
| 903 | atomic_set_mask(cpumask, &smp_invalidate_needed); | 903 | atomic_set_mask(cpumask, &smp_invalidate_needed); |
| 904 | /* | 904 | /* |
| 905 | * We have to send the CPI only to | 905 | * We have to send the CPI only to |
| 906 | * CPUs affected. | 906 | * CPUs affected. |
| 907 | */ | 907 | */ |
| 908 | send_CPI(cpumask, VIC_INVALIDATE_CPI); | 908 | send_CPI(cpumask, VIC_INVALIDATE_CPI); |
| 909 | 909 | ||
| 910 | while (smp_invalidate_needed) { | 910 | while (smp_invalidate_needed) { |
| 911 | mb(); | 911 | mb(); |
| 912 | if(--stuck == 0) { | 912 | if(--stuck == 0) { |
| 913 | printk("***WARNING*** Stuck doing invalidate CPI (CPU%d)\n", smp_processor_id()); | 913 | printk("***WARNING*** Stuck doing invalidate CPI (CPU%d)\n", smp_processor_id()); |
| 914 | break; | 914 | break; |
| 915 | } | 915 | } |
| 916 | } | 916 | } |
| 917 | 917 | ||
| 918 | /* Uncomment only to debug invalidation problems | 918 | /* Uncomment only to debug invalidation problems |
| 919 | VDEBUG(("VOYAGER SMP: Completed invalidate CPI (CPU%d)\n", cpu)); | 919 | VDEBUG(("VOYAGER SMP: Completed invalidate CPI (CPU%d)\n", cpu)); |
| 920 | */ | 920 | */ |
| 921 | 921 | ||
| 922 | flush_mm = NULL; | 922 | flush_mm = NULL; |
| 923 | flush_va = 0; | 923 | flush_va = 0; |
| 924 | spin_unlock(&tlbstate_lock); | 924 | spin_unlock(&tlbstate_lock); |
| 925 | } | 925 | } |
| 926 | 926 | ||
| 927 | void | 927 | void |
| 928 | flush_tlb_current_task(void) | 928 | flush_tlb_current_task(void) |
| 929 | { | 929 | { |
| 930 | struct mm_struct *mm = current->mm; | 930 | struct mm_struct *mm = current->mm; |
| 931 | unsigned long cpu_mask; | 931 | unsigned long cpu_mask; |
| 932 | 932 | ||
| 933 | preempt_disable(); | 933 | preempt_disable(); |
| 934 | 934 | ||
| 935 | cpu_mask = cpus_addr(mm->cpu_vm_mask)[0] & ~(1 << smp_processor_id()); | 935 | cpu_mask = cpus_addr(mm->cpu_vm_mask)[0] & ~(1 << smp_processor_id()); |
| 936 | local_flush_tlb(); | 936 | local_flush_tlb(); |
| 937 | if (cpu_mask) | 937 | if (cpu_mask) |
| 938 | flush_tlb_others(cpu_mask, mm, FLUSH_ALL); | 938 | flush_tlb_others(cpu_mask, mm, FLUSH_ALL); |
| 939 | 939 | ||
| 940 | preempt_enable(); | 940 | preempt_enable(); |
| 941 | } | 941 | } |
| 942 | 942 | ||
| 943 | 943 | ||
| 944 | void | 944 | void |
| 945 | flush_tlb_mm (struct mm_struct * mm) | 945 | flush_tlb_mm (struct mm_struct * mm) |
| 946 | { | 946 | { |
| 947 | unsigned long cpu_mask; | 947 | unsigned long cpu_mask; |
| 948 | 948 | ||
| 949 | preempt_disable(); | 949 | preempt_disable(); |
| 950 | 950 | ||
| 951 | cpu_mask = cpus_addr(mm->cpu_vm_mask)[0] & ~(1 << smp_processor_id()); | 951 | cpu_mask = cpus_addr(mm->cpu_vm_mask)[0] & ~(1 << smp_processor_id()); |
| 952 | 952 | ||
| 953 | if (current->active_mm == mm) { | 953 | if (current->active_mm == mm) { |
| 954 | if (current->mm) | 954 | if (current->mm) |
| 955 | local_flush_tlb(); | 955 | local_flush_tlb(); |
| 956 | else | 956 | else |
| 957 | leave_mm(smp_processor_id()); | 957 | leave_mm(smp_processor_id()); |
| 958 | } | 958 | } |
| 959 | if (cpu_mask) | 959 | if (cpu_mask) |
| 960 | flush_tlb_others(cpu_mask, mm, FLUSH_ALL); | 960 | flush_tlb_others(cpu_mask, mm, FLUSH_ALL); |
| 961 | 961 | ||
| 962 | preempt_enable(); | 962 | preempt_enable(); |
| 963 | } | 963 | } |
| 964 | 964 | ||
| 965 | void flush_tlb_page(struct vm_area_struct * vma, unsigned long va) | 965 | void flush_tlb_page(struct vm_area_struct * vma, unsigned long va) |
| 966 | { | 966 | { |
| 967 | struct mm_struct *mm = vma->vm_mm; | 967 | struct mm_struct *mm = vma->vm_mm; |
| 968 | unsigned long cpu_mask; | 968 | unsigned long cpu_mask; |
| 969 | 969 | ||
| 970 | preempt_disable(); | 970 | preempt_disable(); |
| 971 | 971 | ||
| 972 | cpu_mask = cpus_addr(mm->cpu_vm_mask)[0] & ~(1 << smp_processor_id()); | 972 | cpu_mask = cpus_addr(mm->cpu_vm_mask)[0] & ~(1 << smp_processor_id()); |
| 973 | if (current->active_mm == mm) { | 973 | if (current->active_mm == mm) { |
| 974 | if(current->mm) | 974 | if(current->mm) |
| 975 | __flush_tlb_one(va); | 975 | __flush_tlb_one(va); |
| 976 | else | 976 | else |
| 977 | leave_mm(smp_processor_id()); | 977 | leave_mm(smp_processor_id()); |
| 978 | } | 978 | } |
| 979 | 979 | ||
| 980 | if (cpu_mask) | 980 | if (cpu_mask) |
| 981 | flush_tlb_others(cpu_mask, mm, va); | 981 | flush_tlb_others(cpu_mask, mm, va); |
| 982 | 982 | ||
| 983 | preempt_enable(); | 983 | preempt_enable(); |
| 984 | } | 984 | } |
| 985 | EXPORT_SYMBOL(flush_tlb_page); | 985 | EXPORT_SYMBOL(flush_tlb_page); |
| 986 | 986 | ||
| 987 | /* enable the requested IRQs */ | 987 | /* enable the requested IRQs */ |
| 988 | static void | 988 | static void |
| 989 | smp_enable_irq_interrupt(void) | 989 | smp_enable_irq_interrupt(void) |
| 990 | { | 990 | { |
| 991 | __u8 irq; | 991 | __u8 irq; |
| 992 | __u8 cpu = get_cpu(); | 992 | __u8 cpu = get_cpu(); |
| 993 | 993 | ||
| 994 | VDEBUG(("VOYAGER SMP: CPU%d enabling irq mask 0x%x\n", cpu, | 994 | VDEBUG(("VOYAGER SMP: CPU%d enabling irq mask 0x%x\n", cpu, |
| 995 | vic_irq_enable_mask[cpu])); | 995 | vic_irq_enable_mask[cpu])); |
| 996 | 996 | ||
| 997 | spin_lock(&vic_irq_lock); | 997 | spin_lock(&vic_irq_lock); |
| 998 | for(irq = 0; irq < 16; irq++) { | 998 | for(irq = 0; irq < 16; irq++) { |
| 999 | if(vic_irq_enable_mask[cpu] & (1<<irq)) | 999 | if(vic_irq_enable_mask[cpu] & (1<<irq)) |
| 1000 | enable_local_vic_irq(irq); | 1000 | enable_local_vic_irq(irq); |
| 1001 | } | 1001 | } |
| 1002 | vic_irq_enable_mask[cpu] = 0; | 1002 | vic_irq_enable_mask[cpu] = 0; |
| 1003 | spin_unlock(&vic_irq_lock); | 1003 | spin_unlock(&vic_irq_lock); |
| 1004 | 1004 | ||
| 1005 | put_cpu_no_resched(); | 1005 | put_cpu_no_resched(); |
| 1006 | } | 1006 | } |
| 1007 | 1007 | ||
| 1008 | /* | 1008 | /* |
| 1009 | * CPU halt call-back | 1009 | * CPU halt call-back |
| 1010 | */ | 1010 | */ |
| 1011 | static void | 1011 | static void |
| 1012 | smp_stop_cpu_function(void *dummy) | 1012 | smp_stop_cpu_function(void *dummy) |
| 1013 | { | 1013 | { |
| 1014 | VDEBUG(("VOYAGER SMP: CPU%d is STOPPING\n", smp_processor_id())); | 1014 | VDEBUG(("VOYAGER SMP: CPU%d is STOPPING\n", smp_processor_id())); |
| 1015 | cpu_clear(smp_processor_id(), cpu_online_map); | 1015 | cpu_clear(smp_processor_id(), cpu_online_map); |
| 1016 | local_irq_disable(); | 1016 | local_irq_disable(); |
| 1017 | for(;;) | 1017 | for(;;) |
| 1018 | __asm__("hlt"); | 1018 | halt(); |
| 1019 | } | 1019 | } |
| 1020 | 1020 | ||
| 1021 | static DEFINE_SPINLOCK(call_lock); | 1021 | static DEFINE_SPINLOCK(call_lock); |
| 1022 | 1022 | ||
| 1023 | struct call_data_struct { | 1023 | struct call_data_struct { |
| 1024 | void (*func) (void *info); | 1024 | void (*func) (void *info); |
| 1025 | void *info; | 1025 | void *info; |
| 1026 | volatile unsigned long started; | 1026 | volatile unsigned long started; |
| 1027 | volatile unsigned long finished; | 1027 | volatile unsigned long finished; |
| 1028 | int wait; | 1028 | int wait; |
| 1029 | }; | 1029 | }; |
| 1030 | 1030 | ||
| 1031 | static struct call_data_struct * call_data; | 1031 | static struct call_data_struct * call_data; |
| 1032 | 1032 | ||
| 1033 | /* execute a thread on a new CPU. The function to be called must be | 1033 | /* execute a thread on a new CPU. The function to be called must be |
| 1034 | * previously set up. This is used to schedule a function for | 1034 | * previously set up. This is used to schedule a function for |
| 1035 | * execution on all CPU's - set up the function then broadcast a | 1035 | * execution on all CPU's - set up the function then broadcast a |
| 1036 | * function_interrupt CPI to come here on each CPU */ | 1036 | * function_interrupt CPI to come here on each CPU */ |
| 1037 | static void | 1037 | static void |
| 1038 | smp_call_function_interrupt(void) | 1038 | smp_call_function_interrupt(void) |
| 1039 | { | 1039 | { |
| 1040 | void (*func) (void *info) = call_data->func; | 1040 | void (*func) (void *info) = call_data->func; |
| 1041 | void *info = call_data->info; | 1041 | void *info = call_data->info; |
| 1042 | /* must take copy of wait because call_data may be replaced | 1042 | /* must take copy of wait because call_data may be replaced |
| 1043 | * unless the function is waiting for us to finish */ | 1043 | * unless the function is waiting for us to finish */ |
| 1044 | int wait = call_data->wait; | 1044 | int wait = call_data->wait; |
| 1045 | __u8 cpu = smp_processor_id(); | 1045 | __u8 cpu = smp_processor_id(); |
| 1046 | 1046 | ||
| 1047 | /* | 1047 | /* |
| 1048 | * Notify initiating CPU that I've grabbed the data and am | 1048 | * Notify initiating CPU that I've grabbed the data and am |
| 1049 | * about to execute the function | 1049 | * about to execute the function |
| 1050 | */ | 1050 | */ |
| 1051 | mb(); | 1051 | mb(); |
| 1052 | if(!test_and_clear_bit(cpu, &call_data->started)) { | 1052 | if(!test_and_clear_bit(cpu, &call_data->started)) { |
| 1053 | /* If the bit wasn't set, this could be a replay */ | 1053 | /* If the bit wasn't set, this could be a replay */ |
| 1054 | printk(KERN_WARNING "VOYAGER SMP: CPU %d received call funtion with no call pending\n", cpu); | 1054 | printk(KERN_WARNING "VOYAGER SMP: CPU %d received call funtion with no call pending\n", cpu); |
| 1055 | return; | 1055 | return; |
| 1056 | } | 1056 | } |
| 1057 | /* | 1057 | /* |
| 1058 | * At this point the info structure may be out of scope unless wait==1 | 1058 | * At this point the info structure may be out of scope unless wait==1 |
| 1059 | */ | 1059 | */ |
| 1060 | irq_enter(); | 1060 | irq_enter(); |
| 1061 | (*func)(info); | 1061 | (*func)(info); |
| 1062 | irq_exit(); | 1062 | irq_exit(); |
| 1063 | if (wait) { | 1063 | if (wait) { |
| 1064 | mb(); | 1064 | mb(); |
| 1065 | clear_bit(cpu, &call_data->finished); | 1065 | clear_bit(cpu, &call_data->finished); |
| 1066 | } | 1066 | } |
| 1067 | } | 1067 | } |
| 1068 | 1068 | ||
| 1069 | /* Call this function on all CPUs using the function_interrupt above | 1069 | /* Call this function on all CPUs using the function_interrupt above |
| 1070 | <func> The function to run. This must be fast and non-blocking. | 1070 | <func> The function to run. This must be fast and non-blocking. |
| 1071 | <info> An arbitrary pointer to pass to the function. | 1071 | <info> An arbitrary pointer to pass to the function. |
| 1072 | <retry> If true, keep retrying until ready. | 1072 | <retry> If true, keep retrying until ready. |
| 1073 | <wait> If true, wait until function has completed on other CPUs. | 1073 | <wait> If true, wait until function has completed on other CPUs. |
| 1074 | [RETURNS] 0 on success, else a negative status code. Does not return until | 1074 | [RETURNS] 0 on success, else a negative status code. Does not return until |
| 1075 | remote CPUs are nearly ready to execute <<func>> or are or have executed. | 1075 | remote CPUs are nearly ready to execute <<func>> or are or have executed. |
| 1076 | */ | 1076 | */ |
| 1077 | int | 1077 | int |
| 1078 | smp_call_function (void (*func) (void *info), void *info, int retry, | 1078 | smp_call_function (void (*func) (void *info), void *info, int retry, |
| 1079 | int wait) | 1079 | int wait) |
| 1080 | { | 1080 | { |
| 1081 | struct call_data_struct data; | 1081 | struct call_data_struct data; |
| 1082 | __u32 mask = cpus_addr(cpu_online_map)[0]; | 1082 | __u32 mask = cpus_addr(cpu_online_map)[0]; |
| 1083 | 1083 | ||
| 1084 | mask &= ~(1<<smp_processor_id()); | 1084 | mask &= ~(1<<smp_processor_id()); |
| 1085 | 1085 | ||
| 1086 | if (!mask) | 1086 | if (!mask) |
| 1087 | return 0; | 1087 | return 0; |
| 1088 | 1088 | ||
| 1089 | /* Can deadlock when called with interrupts disabled */ | 1089 | /* Can deadlock when called with interrupts disabled */ |
| 1090 | WARN_ON(irqs_disabled()); | 1090 | WARN_ON(irqs_disabled()); |
| 1091 | 1091 | ||
| 1092 | data.func = func; | 1092 | data.func = func; |
| 1093 | data.info = info; | 1093 | data.info = info; |
| 1094 | data.started = mask; | 1094 | data.started = mask; |
| 1095 | data.wait = wait; | 1095 | data.wait = wait; |
| 1096 | if (wait) | 1096 | if (wait) |
| 1097 | data.finished = mask; | 1097 | data.finished = mask; |
| 1098 | 1098 | ||
| 1099 | spin_lock(&call_lock); | 1099 | spin_lock(&call_lock); |
| 1100 | call_data = &data; | 1100 | call_data = &data; |
| 1101 | wmb(); | 1101 | wmb(); |
| 1102 | /* Send a message to all other CPUs and wait for them to respond */ | 1102 | /* Send a message to all other CPUs and wait for them to respond */ |
| 1103 | send_CPI_allbutself(VIC_CALL_FUNCTION_CPI); | 1103 | send_CPI_allbutself(VIC_CALL_FUNCTION_CPI); |
| 1104 | 1104 | ||
| 1105 | /* Wait for response */ | 1105 | /* Wait for response */ |
| 1106 | while (data.started) | 1106 | while (data.started) |
| 1107 | barrier(); | 1107 | barrier(); |
| 1108 | 1108 | ||
| 1109 | if (wait) | 1109 | if (wait) |
| 1110 | while (data.finished) | 1110 | while (data.finished) |
| 1111 | barrier(); | 1111 | barrier(); |
| 1112 | 1112 | ||
| 1113 | spin_unlock(&call_lock); | 1113 | spin_unlock(&call_lock); |
| 1114 | 1114 | ||
| 1115 | return 0; | 1115 | return 0; |
| 1116 | } | 1116 | } |
| 1117 | EXPORT_SYMBOL(smp_call_function); | 1117 | EXPORT_SYMBOL(smp_call_function); |
| 1118 | 1118 | ||
| 1119 | /* Sorry about the name. In an APIC based system, the APICs | 1119 | /* Sorry about the name. In an APIC based system, the APICs |
| 1120 | * themselves are programmed to send a timer interrupt. This is used | 1120 | * themselves are programmed to send a timer interrupt. This is used |
| 1121 | * by linux to reschedule the processor. Voyager doesn't have this, | 1121 | * by linux to reschedule the processor. Voyager doesn't have this, |
| 1122 | * so we use the system clock to interrupt one processor, which in | 1122 | * so we use the system clock to interrupt one processor, which in |
| 1123 | * turn, broadcasts a timer CPI to all the others --- we receive that | 1123 | * turn, broadcasts a timer CPI to all the others --- we receive that |
| 1124 | * CPI here. We don't use this actually for counting so losing | 1124 | * CPI here. We don't use this actually for counting so losing |
| 1125 | * ticks doesn't matter | 1125 | * ticks doesn't matter |
| 1126 | * | 1126 | * |
| 1127 | * FIXME: For those CPU's which actually have a local APIC, we could | 1127 | * FIXME: For those CPU's which actually have a local APIC, we could |
| 1128 | * try to use it to trigger this interrupt instead of having to | 1128 | * try to use it to trigger this interrupt instead of having to |
| 1129 | * broadcast the timer tick. Unfortunately, all my pentium DYADs have | 1129 | * broadcast the timer tick. Unfortunately, all my pentium DYADs have |
| 1130 | * no local APIC, so I can't do this | 1130 | * no local APIC, so I can't do this |
| 1131 | * | 1131 | * |
| 1132 | * This function is currently a placeholder and is unused in the code */ | 1132 | * This function is currently a placeholder and is unused in the code */ |
| 1133 | fastcall void | 1133 | fastcall void |
| 1134 | smp_apic_timer_interrupt(struct pt_regs *regs) | 1134 | smp_apic_timer_interrupt(struct pt_regs *regs) |
| 1135 | { | 1135 | { |
| 1136 | wrapper_smp_local_timer_interrupt(regs); | 1136 | wrapper_smp_local_timer_interrupt(regs); |
| 1137 | } | 1137 | } |
| 1138 | 1138 | ||
| 1139 | /* All of the QUAD interrupt GATES */ | 1139 | /* All of the QUAD interrupt GATES */ |
| 1140 | fastcall void | 1140 | fastcall void |
| 1141 | smp_qic_timer_interrupt(struct pt_regs *regs) | 1141 | smp_qic_timer_interrupt(struct pt_regs *regs) |
| 1142 | { | 1142 | { |
| 1143 | ack_QIC_CPI(QIC_TIMER_CPI); | 1143 | ack_QIC_CPI(QIC_TIMER_CPI); |
| 1144 | wrapper_smp_local_timer_interrupt(regs); | 1144 | wrapper_smp_local_timer_interrupt(regs); |
| 1145 | } | 1145 | } |
| 1146 | 1146 | ||
| 1147 | fastcall void | 1147 | fastcall void |
| 1148 | smp_qic_invalidate_interrupt(struct pt_regs *regs) | 1148 | smp_qic_invalidate_interrupt(struct pt_regs *regs) |
| 1149 | { | 1149 | { |
| 1150 | ack_QIC_CPI(QIC_INVALIDATE_CPI); | 1150 | ack_QIC_CPI(QIC_INVALIDATE_CPI); |
| 1151 | smp_invalidate_interrupt(); | 1151 | smp_invalidate_interrupt(); |
| 1152 | } | 1152 | } |
| 1153 | 1153 | ||
| 1154 | fastcall void | 1154 | fastcall void |
| 1155 | smp_qic_reschedule_interrupt(struct pt_regs *regs) | 1155 | smp_qic_reschedule_interrupt(struct pt_regs *regs) |
| 1156 | { | 1156 | { |
| 1157 | ack_QIC_CPI(QIC_RESCHEDULE_CPI); | 1157 | ack_QIC_CPI(QIC_RESCHEDULE_CPI); |
| 1158 | smp_reschedule_interrupt(); | 1158 | smp_reschedule_interrupt(); |
| 1159 | } | 1159 | } |
| 1160 | 1160 | ||
| 1161 | fastcall void | 1161 | fastcall void |
| 1162 | smp_qic_enable_irq_interrupt(struct pt_regs *regs) | 1162 | smp_qic_enable_irq_interrupt(struct pt_regs *regs) |
| 1163 | { | 1163 | { |
| 1164 | ack_QIC_CPI(QIC_ENABLE_IRQ_CPI); | 1164 | ack_QIC_CPI(QIC_ENABLE_IRQ_CPI); |
| 1165 | smp_enable_irq_interrupt(); | 1165 | smp_enable_irq_interrupt(); |
| 1166 | } | 1166 | } |
| 1167 | 1167 | ||
| 1168 | fastcall void | 1168 | fastcall void |
| 1169 | smp_qic_call_function_interrupt(struct pt_regs *regs) | 1169 | smp_qic_call_function_interrupt(struct pt_regs *regs) |
| 1170 | { | 1170 | { |
| 1171 | ack_QIC_CPI(QIC_CALL_FUNCTION_CPI); | 1171 | ack_QIC_CPI(QIC_CALL_FUNCTION_CPI); |
| 1172 | smp_call_function_interrupt(); | 1172 | smp_call_function_interrupt(); |
| 1173 | } | 1173 | } |
| 1174 | 1174 | ||
| 1175 | fastcall void | 1175 | fastcall void |
| 1176 | smp_vic_cpi_interrupt(struct pt_regs *regs) | 1176 | smp_vic_cpi_interrupt(struct pt_regs *regs) |
| 1177 | { | 1177 | { |
| 1178 | __u8 cpu = smp_processor_id(); | 1178 | __u8 cpu = smp_processor_id(); |
| 1179 | 1179 | ||
| 1180 | if(is_cpu_quad()) | 1180 | if(is_cpu_quad()) |
| 1181 | ack_QIC_CPI(VIC_CPI_LEVEL0); | 1181 | ack_QIC_CPI(VIC_CPI_LEVEL0); |
| 1182 | else | 1182 | else |
| 1183 | ack_VIC_CPI(VIC_CPI_LEVEL0); | 1183 | ack_VIC_CPI(VIC_CPI_LEVEL0); |
| 1184 | 1184 | ||
| 1185 | if(test_and_clear_bit(VIC_TIMER_CPI, &vic_cpi_mailbox[cpu])) | 1185 | if(test_and_clear_bit(VIC_TIMER_CPI, &vic_cpi_mailbox[cpu])) |
| 1186 | wrapper_smp_local_timer_interrupt(regs); | 1186 | wrapper_smp_local_timer_interrupt(regs); |
| 1187 | if(test_and_clear_bit(VIC_INVALIDATE_CPI, &vic_cpi_mailbox[cpu])) | 1187 | if(test_and_clear_bit(VIC_INVALIDATE_CPI, &vic_cpi_mailbox[cpu])) |
| 1188 | smp_invalidate_interrupt(); | 1188 | smp_invalidate_interrupt(); |
| 1189 | if(test_and_clear_bit(VIC_RESCHEDULE_CPI, &vic_cpi_mailbox[cpu])) | 1189 | if(test_and_clear_bit(VIC_RESCHEDULE_CPI, &vic_cpi_mailbox[cpu])) |
| 1190 | smp_reschedule_interrupt(); | 1190 | smp_reschedule_interrupt(); |
| 1191 | if(test_and_clear_bit(VIC_ENABLE_IRQ_CPI, &vic_cpi_mailbox[cpu])) | 1191 | if(test_and_clear_bit(VIC_ENABLE_IRQ_CPI, &vic_cpi_mailbox[cpu])) |
| 1192 | smp_enable_irq_interrupt(); | 1192 | smp_enable_irq_interrupt(); |
| 1193 | if(test_and_clear_bit(VIC_CALL_FUNCTION_CPI, &vic_cpi_mailbox[cpu])) | 1193 | if(test_and_clear_bit(VIC_CALL_FUNCTION_CPI, &vic_cpi_mailbox[cpu])) |
| 1194 | smp_call_function_interrupt(); | 1194 | smp_call_function_interrupt(); |
| 1195 | } | 1195 | } |
| 1196 | 1196 | ||
| 1197 | static void | 1197 | static void |
| 1198 | do_flush_tlb_all(void* info) | 1198 | do_flush_tlb_all(void* info) |
| 1199 | { | 1199 | { |
| 1200 | unsigned long cpu = smp_processor_id(); | 1200 | unsigned long cpu = smp_processor_id(); |
| 1201 | 1201 | ||
| 1202 | __flush_tlb_all(); | 1202 | __flush_tlb_all(); |
| 1203 | if (per_cpu(cpu_tlbstate, cpu).state == TLBSTATE_LAZY) | 1203 | if (per_cpu(cpu_tlbstate, cpu).state == TLBSTATE_LAZY) |
| 1204 | leave_mm(cpu); | 1204 | leave_mm(cpu); |
| 1205 | } | 1205 | } |
| 1206 | 1206 | ||
| 1207 | 1207 | ||
| 1208 | /* flush the TLB of every active CPU in the system */ | 1208 | /* flush the TLB of every active CPU in the system */ |
| 1209 | void | 1209 | void |
| 1210 | flush_tlb_all(void) | 1210 | flush_tlb_all(void) |
| 1211 | { | 1211 | { |
| 1212 | on_each_cpu(do_flush_tlb_all, 0, 1, 1); | 1212 | on_each_cpu(do_flush_tlb_all, 0, 1, 1); |
| 1213 | } | 1213 | } |
| 1214 | 1214 | ||
| 1215 | /* used to set up the trampoline for other CPUs when the memory manager | 1215 | /* used to set up the trampoline for other CPUs when the memory manager |
| 1216 | * is sorted out */ | 1216 | * is sorted out */ |
| 1217 | void __init | 1217 | void __init |
| 1218 | smp_alloc_memory(void) | 1218 | smp_alloc_memory(void) |
| 1219 | { | 1219 | { |
| 1220 | trampoline_base = (__u32)alloc_bootmem_low_pages(PAGE_SIZE); | 1220 | trampoline_base = (__u32)alloc_bootmem_low_pages(PAGE_SIZE); |
| 1221 | if(__pa(trampoline_base) >= 0x93000) | 1221 | if(__pa(trampoline_base) >= 0x93000) |
| 1222 | BUG(); | 1222 | BUG(); |
| 1223 | } | 1223 | } |
| 1224 | 1224 | ||
| 1225 | /* send a reschedule CPI to one CPU by physical CPU number*/ | 1225 | /* send a reschedule CPI to one CPU by physical CPU number*/ |
| 1226 | void | 1226 | void |
| 1227 | smp_send_reschedule(int cpu) | 1227 | smp_send_reschedule(int cpu) |
| 1228 | { | 1228 | { |
| 1229 | send_one_CPI(cpu, VIC_RESCHEDULE_CPI); | 1229 | send_one_CPI(cpu, VIC_RESCHEDULE_CPI); |
| 1230 | } | 1230 | } |
| 1231 | 1231 | ||
| 1232 | 1232 | ||
| 1233 | int | 1233 | int |
| 1234 | hard_smp_processor_id(void) | 1234 | hard_smp_processor_id(void) |
| 1235 | { | 1235 | { |
| 1236 | __u8 i; | 1236 | __u8 i; |
| 1237 | __u8 cpumask = inb(VIC_PROC_WHO_AM_I); | 1237 | __u8 cpumask = inb(VIC_PROC_WHO_AM_I); |
| 1238 | if((cpumask & QUAD_IDENTIFIER) == QUAD_IDENTIFIER) | 1238 | if((cpumask & QUAD_IDENTIFIER) == QUAD_IDENTIFIER) |
| 1239 | return cpumask & 0x1F; | 1239 | return cpumask & 0x1F; |
| 1240 | 1240 | ||
| 1241 | for(i = 0; i < 8; i++) { | 1241 | for(i = 0; i < 8; i++) { |
| 1242 | if(cpumask & (1<<i)) | 1242 | if(cpumask & (1<<i)) |
| 1243 | return i; | 1243 | return i; |
| 1244 | } | 1244 | } |
| 1245 | printk("** WARNING ** Illegal cpuid returned by VIC: %d", cpumask); | 1245 | printk("** WARNING ** Illegal cpuid returned by VIC: %d", cpumask); |
| 1246 | return 0; | 1246 | return 0; |
| 1247 | } | 1247 | } |
| 1248 | 1248 | ||
| 1249 | /* broadcast a halt to all other CPUs */ | 1249 | /* broadcast a halt to all other CPUs */ |
| 1250 | void | 1250 | void |
| 1251 | smp_send_stop(void) | 1251 | smp_send_stop(void) |
| 1252 | { | 1252 | { |
| 1253 | smp_call_function(smp_stop_cpu_function, NULL, 1, 1); | 1253 | smp_call_function(smp_stop_cpu_function, NULL, 1, 1); |
| 1254 | } | 1254 | } |
| 1255 | 1255 | ||
| 1256 | /* this function is triggered in time.c when a clock tick fires | 1256 | /* this function is triggered in time.c when a clock tick fires |
| 1257 | * we need to re-broadcast the tick to all CPUs */ | 1257 | * we need to re-broadcast the tick to all CPUs */ |
| 1258 | void | 1258 | void |
| 1259 | smp_vic_timer_interrupt(struct pt_regs *regs) | 1259 | smp_vic_timer_interrupt(struct pt_regs *regs) |
| 1260 | { | 1260 | { |
| 1261 | send_CPI_allbutself(VIC_TIMER_CPI); | 1261 | send_CPI_allbutself(VIC_TIMER_CPI); |
| 1262 | smp_local_timer_interrupt(regs); | 1262 | smp_local_timer_interrupt(regs); |
| 1263 | } | 1263 | } |
| 1264 | 1264 | ||
| 1265 | /* local (per CPU) timer interrupt. It does both profiling and | 1265 | /* local (per CPU) timer interrupt. It does both profiling and |
| 1266 | * process statistics/rescheduling. | 1266 | * process statistics/rescheduling. |
| 1267 | * | 1267 | * |
| 1268 | * We do profiling in every local tick, statistics/rescheduling | 1268 | * We do profiling in every local tick, statistics/rescheduling |
| 1269 | * happen only every 'profiling multiplier' ticks. The default | 1269 | * happen only every 'profiling multiplier' ticks. The default |
| 1270 | * multiplier is 1 and it can be changed by writing the new multiplier | 1270 | * multiplier is 1 and it can be changed by writing the new multiplier |
| 1271 | * value into /proc/profile. | 1271 | * value into /proc/profile. |
| 1272 | */ | 1272 | */ |
| 1273 | void | 1273 | void |
| 1274 | smp_local_timer_interrupt(struct pt_regs * regs) | 1274 | smp_local_timer_interrupt(struct pt_regs * regs) |
| 1275 | { | 1275 | { |
| 1276 | int cpu = smp_processor_id(); | 1276 | int cpu = smp_processor_id(); |
| 1277 | long weight; | 1277 | long weight; |
| 1278 | 1278 | ||
| 1279 | profile_tick(CPU_PROFILING, regs); | 1279 | profile_tick(CPU_PROFILING, regs); |
| 1280 | if (--per_cpu(prof_counter, cpu) <= 0) { | 1280 | if (--per_cpu(prof_counter, cpu) <= 0) { |
| 1281 | /* | 1281 | /* |
| 1282 | * The multiplier may have changed since the last time we got | 1282 | * The multiplier may have changed since the last time we got |
| 1283 | * to this point as a result of the user writing to | 1283 | * to this point as a result of the user writing to |
| 1284 | * /proc/profile. In this case we need to adjust the APIC | 1284 | * /proc/profile. In this case we need to adjust the APIC |
| 1285 | * timer accordingly. | 1285 | * timer accordingly. |
| 1286 | * | 1286 | * |
| 1287 | * Interrupts are already masked off at this point. | 1287 | * Interrupts are already masked off at this point. |
| 1288 | */ | 1288 | */ |
| 1289 | per_cpu(prof_counter,cpu) = per_cpu(prof_multiplier, cpu); | 1289 | per_cpu(prof_counter,cpu) = per_cpu(prof_multiplier, cpu); |
| 1290 | if (per_cpu(prof_counter, cpu) != | 1290 | if (per_cpu(prof_counter, cpu) != |
| 1291 | per_cpu(prof_old_multiplier, cpu)) { | 1291 | per_cpu(prof_old_multiplier, cpu)) { |
| 1292 | /* FIXME: need to update the vic timer tick here */ | 1292 | /* FIXME: need to update the vic timer tick here */ |
| 1293 | per_cpu(prof_old_multiplier, cpu) = | 1293 | per_cpu(prof_old_multiplier, cpu) = |
| 1294 | per_cpu(prof_counter, cpu); | 1294 | per_cpu(prof_counter, cpu); |
| 1295 | } | 1295 | } |
| 1296 | 1296 | ||
| 1297 | update_process_times(user_mode_vm(regs)); | 1297 | update_process_times(user_mode_vm(regs)); |
| 1298 | } | 1298 | } |
| 1299 | 1299 | ||
| 1300 | if( ((1<<cpu) & voyager_extended_vic_processors) == 0) | 1300 | if( ((1<<cpu) & voyager_extended_vic_processors) == 0) |
| 1301 | /* only extended VIC processors participate in | 1301 | /* only extended VIC processors participate in |
| 1302 | * interrupt distribution */ | 1302 | * interrupt distribution */ |
| 1303 | return; | 1303 | return; |
| 1304 | 1304 | ||
| 1305 | /* | 1305 | /* |
| 1306 | * We take the 'long' return path, and there every subsystem | 1306 | * We take the 'long' return path, and there every subsystem |
| 1307 | * grabs the apropriate locks (kernel lock/ irq lock). | 1307 | * grabs the apropriate locks (kernel lock/ irq lock). |
| 1308 | * | 1308 | * |
| 1309 | * we might want to decouple profiling from the 'long path', | 1309 | * we might want to decouple profiling from the 'long path', |
| 1310 | * and do the profiling totally in assembly. | 1310 | * and do the profiling totally in assembly. |
| 1311 | * | 1311 | * |
| 1312 | * Currently this isn't too much of an issue (performance wise), | 1312 | * Currently this isn't too much of an issue (performance wise), |
| 1313 | * we can take more than 100K local irqs per second on a 100 MHz P5. | 1313 | * we can take more than 100K local irqs per second on a 100 MHz P5. |
| 1314 | */ | 1314 | */ |
| 1315 | 1315 | ||
| 1316 | if((++vic_tick[cpu] & 0x7) != 0) | 1316 | if((++vic_tick[cpu] & 0x7) != 0) |
| 1317 | return; | 1317 | return; |
| 1318 | /* get here every 16 ticks (about every 1/6 of a second) */ | 1318 | /* get here every 16 ticks (about every 1/6 of a second) */ |
| 1319 | 1319 | ||
| 1320 | /* Change our priority to give someone else a chance at getting | 1320 | /* Change our priority to give someone else a chance at getting |
| 1321 | * the IRQ. The algorithm goes like this: | 1321 | * the IRQ. The algorithm goes like this: |
| 1322 | * | 1322 | * |
| 1323 | * In the VIC, the dynamically routed interrupt is always | 1323 | * In the VIC, the dynamically routed interrupt is always |
| 1324 | * handled by the lowest priority eligible (i.e. receiving | 1324 | * handled by the lowest priority eligible (i.e. receiving |
| 1325 | * interrupts) CPU. If >1 eligible CPUs are equal lowest, the | 1325 | * interrupts) CPU. If >1 eligible CPUs are equal lowest, the |
| 1326 | * lowest processor number gets it. | 1326 | * lowest processor number gets it. |
| 1327 | * | 1327 | * |
| 1328 | * The priority of a CPU is controlled by a special per-CPU | 1328 | * The priority of a CPU is controlled by a special per-CPU |
| 1329 | * VIC priority register which is 3 bits wide 0 being lowest | 1329 | * VIC priority register which is 3 bits wide 0 being lowest |
| 1330 | * and 7 highest priority.. | 1330 | * and 7 highest priority.. |
| 1331 | * | 1331 | * |
| 1332 | * Therefore we subtract the average number of interrupts from | 1332 | * Therefore we subtract the average number of interrupts from |
| 1333 | * the number we've fielded. If this number is negative, we | 1333 | * the number we've fielded. If this number is negative, we |
| 1334 | * lower the activity count and if it is positive, we raise | 1334 | * lower the activity count and if it is positive, we raise |
| 1335 | * it. | 1335 | * it. |
| 1336 | * | 1336 | * |
| 1337 | * I'm afraid this still leads to odd looking interrupt counts: | 1337 | * I'm afraid this still leads to odd looking interrupt counts: |
| 1338 | * the totals are all roughly equal, but the individual ones | 1338 | * the totals are all roughly equal, but the individual ones |
| 1339 | * look rather skewed. | 1339 | * look rather skewed. |
| 1340 | * | 1340 | * |
| 1341 | * FIXME: This algorithm is total crap when mixed with SMP | 1341 | * FIXME: This algorithm is total crap when mixed with SMP |
| 1342 | * affinity code since we now try to even up the interrupt | 1342 | * affinity code since we now try to even up the interrupt |
| 1343 | * counts when an affinity binding is keeping them on a | 1343 | * counts when an affinity binding is keeping them on a |
| 1344 | * particular CPU*/ | 1344 | * particular CPU*/ |
| 1345 | weight = (vic_intr_count[cpu]*voyager_extended_cpus | 1345 | weight = (vic_intr_count[cpu]*voyager_extended_cpus |
| 1346 | - vic_intr_total) >> 4; | 1346 | - vic_intr_total) >> 4; |
| 1347 | weight += 4; | 1347 | weight += 4; |
| 1348 | if(weight > 7) | 1348 | if(weight > 7) |
| 1349 | weight = 7; | 1349 | weight = 7; |
| 1350 | if(weight < 0) | 1350 | if(weight < 0) |
| 1351 | weight = 0; | 1351 | weight = 0; |
| 1352 | 1352 | ||
| 1353 | outb((__u8)weight, VIC_PRIORITY_REGISTER); | 1353 | outb((__u8)weight, VIC_PRIORITY_REGISTER); |
| 1354 | 1354 | ||
| 1355 | #ifdef VOYAGER_DEBUG | 1355 | #ifdef VOYAGER_DEBUG |
| 1356 | if((vic_tick[cpu] & 0xFFF) == 0) { | 1356 | if((vic_tick[cpu] & 0xFFF) == 0) { |
| 1357 | /* print this message roughly every 25 secs */ | 1357 | /* print this message roughly every 25 secs */ |
| 1358 | printk("VOYAGER SMP: vic_tick[%d] = %lu, weight = %ld\n", | 1358 | printk("VOYAGER SMP: vic_tick[%d] = %lu, weight = %ld\n", |
| 1359 | cpu, vic_tick[cpu], weight); | 1359 | cpu, vic_tick[cpu], weight); |
| 1360 | } | 1360 | } |
| 1361 | #endif | 1361 | #endif |
| 1362 | } | 1362 | } |
| 1363 | 1363 | ||
| 1364 | /* setup the profiling timer */ | 1364 | /* setup the profiling timer */ |
| 1365 | int | 1365 | int |
| 1366 | setup_profiling_timer(unsigned int multiplier) | 1366 | setup_profiling_timer(unsigned int multiplier) |
| 1367 | { | 1367 | { |
| 1368 | int i; | 1368 | int i; |
| 1369 | 1369 | ||
| 1370 | if ( (!multiplier)) | 1370 | if ( (!multiplier)) |
| 1371 | return -EINVAL; | 1371 | return -EINVAL; |
| 1372 | 1372 | ||
| 1373 | /* | 1373 | /* |
| 1374 | * Set the new multiplier for each CPU. CPUs don't start using the | 1374 | * Set the new multiplier for each CPU. CPUs don't start using the |
| 1375 | * new values until the next timer interrupt in which they do process | 1375 | * new values until the next timer interrupt in which they do process |
| 1376 | * accounting. | 1376 | * accounting. |
| 1377 | */ | 1377 | */ |
| 1378 | for (i = 0; i < NR_CPUS; ++i) | 1378 | for (i = 0; i < NR_CPUS; ++i) |
| 1379 | per_cpu(prof_multiplier, i) = multiplier; | 1379 | per_cpu(prof_multiplier, i) = multiplier; |
| 1380 | 1380 | ||
| 1381 | return 0; | 1381 | return 0; |
| 1382 | } | 1382 | } |
| 1383 | 1383 | ||
| 1384 | 1384 | ||
| 1385 | /* The CPIs are handled in the per cpu 8259s, so they must be | 1385 | /* The CPIs are handled in the per cpu 8259s, so they must be |
| 1386 | * enabled to be received: FIX: enabling the CPIs in the early | 1386 | * enabled to be received: FIX: enabling the CPIs in the early |
| 1387 | * boot sequence interferes with bug checking; enable them later | 1387 | * boot sequence interferes with bug checking; enable them later |
| 1388 | * on in smp_init */ | 1388 | * on in smp_init */ |
| 1389 | #define VIC_SET_GATE(cpi, vector) \ | 1389 | #define VIC_SET_GATE(cpi, vector) \ |
| 1390 | set_intr_gate((cpi) + VIC_DEFAULT_CPI_BASE, (vector)) | 1390 | set_intr_gate((cpi) + VIC_DEFAULT_CPI_BASE, (vector)) |
| 1391 | #define QIC_SET_GATE(cpi, vector) \ | 1391 | #define QIC_SET_GATE(cpi, vector) \ |
| 1392 | set_intr_gate((cpi) + QIC_DEFAULT_CPI_BASE, (vector)) | 1392 | set_intr_gate((cpi) + QIC_DEFAULT_CPI_BASE, (vector)) |
| 1393 | 1393 | ||
| 1394 | void __init | 1394 | void __init |
| 1395 | smp_intr_init(void) | 1395 | smp_intr_init(void) |
| 1396 | { | 1396 | { |
| 1397 | int i; | 1397 | int i; |
| 1398 | 1398 | ||
| 1399 | /* initialize the per cpu irq mask to all disabled */ | 1399 | /* initialize the per cpu irq mask to all disabled */ |
| 1400 | for(i = 0; i < NR_CPUS; i++) | 1400 | for(i = 0; i < NR_CPUS; i++) |
| 1401 | vic_irq_mask[i] = 0xFFFF; | 1401 | vic_irq_mask[i] = 0xFFFF; |
| 1402 | 1402 | ||
| 1403 | VIC_SET_GATE(VIC_CPI_LEVEL0, vic_cpi_interrupt); | 1403 | VIC_SET_GATE(VIC_CPI_LEVEL0, vic_cpi_interrupt); |
| 1404 | 1404 | ||
| 1405 | VIC_SET_GATE(VIC_SYS_INT, vic_sys_interrupt); | 1405 | VIC_SET_GATE(VIC_SYS_INT, vic_sys_interrupt); |
| 1406 | VIC_SET_GATE(VIC_CMN_INT, vic_cmn_interrupt); | 1406 | VIC_SET_GATE(VIC_CMN_INT, vic_cmn_interrupt); |
| 1407 | 1407 | ||
| 1408 | QIC_SET_GATE(QIC_TIMER_CPI, qic_timer_interrupt); | 1408 | QIC_SET_GATE(QIC_TIMER_CPI, qic_timer_interrupt); |
| 1409 | QIC_SET_GATE(QIC_INVALIDATE_CPI, qic_invalidate_interrupt); | 1409 | QIC_SET_GATE(QIC_INVALIDATE_CPI, qic_invalidate_interrupt); |
| 1410 | QIC_SET_GATE(QIC_RESCHEDULE_CPI, qic_reschedule_interrupt); | 1410 | QIC_SET_GATE(QIC_RESCHEDULE_CPI, qic_reschedule_interrupt); |
| 1411 | QIC_SET_GATE(QIC_ENABLE_IRQ_CPI, qic_enable_irq_interrupt); | 1411 | QIC_SET_GATE(QIC_ENABLE_IRQ_CPI, qic_enable_irq_interrupt); |
| 1412 | QIC_SET_GATE(QIC_CALL_FUNCTION_CPI, qic_call_function_interrupt); | 1412 | QIC_SET_GATE(QIC_CALL_FUNCTION_CPI, qic_call_function_interrupt); |
| 1413 | 1413 | ||
| 1414 | 1414 | ||
| 1415 | /* now put the VIC descriptor into the first 48 IRQs | 1415 | /* now put the VIC descriptor into the first 48 IRQs |
| 1416 | * | 1416 | * |
| 1417 | * This is for later: first 16 correspond to PC IRQs; next 16 | 1417 | * This is for later: first 16 correspond to PC IRQs; next 16 |
| 1418 | * are Primary MC IRQs and final 16 are Secondary MC IRQs */ | 1418 | * are Primary MC IRQs and final 16 are Secondary MC IRQs */ |
| 1419 | for(i = 0; i < 48; i++) | 1419 | for(i = 0; i < 48; i++) |
| 1420 | irq_desc[i].handler = &vic_irq_type; | 1420 | irq_desc[i].handler = &vic_irq_type; |
| 1421 | } | 1421 | } |
| 1422 | 1422 | ||
| 1423 | /* send a CPI at level cpi to a set of cpus in cpuset (set 1 bit per | 1423 | /* send a CPI at level cpi to a set of cpus in cpuset (set 1 bit per |
| 1424 | * processor to receive CPI */ | 1424 | * processor to receive CPI */ |
| 1425 | static void | 1425 | static void |
| 1426 | send_CPI(__u32 cpuset, __u8 cpi) | 1426 | send_CPI(__u32 cpuset, __u8 cpi) |
| 1427 | { | 1427 | { |
| 1428 | int cpu; | 1428 | int cpu; |
| 1429 | __u32 quad_cpuset = (cpuset & voyager_quad_processors); | 1429 | __u32 quad_cpuset = (cpuset & voyager_quad_processors); |
| 1430 | 1430 | ||
| 1431 | if(cpi < VIC_START_FAKE_CPI) { | 1431 | if(cpi < VIC_START_FAKE_CPI) { |
| 1432 | /* fake CPI are only used for booting, so send to the | 1432 | /* fake CPI are only used for booting, so send to the |
| 1433 | * extended quads as well---Quads must be VIC booted */ | 1433 | * extended quads as well---Quads must be VIC booted */ |
| 1434 | outb((__u8)(cpuset), VIC_CPI_Registers[cpi]); | 1434 | outb((__u8)(cpuset), VIC_CPI_Registers[cpi]); |
| 1435 | return; | 1435 | return; |
| 1436 | } | 1436 | } |
| 1437 | if(quad_cpuset) | 1437 | if(quad_cpuset) |
| 1438 | send_QIC_CPI(quad_cpuset, cpi); | 1438 | send_QIC_CPI(quad_cpuset, cpi); |
| 1439 | cpuset &= ~quad_cpuset; | 1439 | cpuset &= ~quad_cpuset; |
| 1440 | cpuset &= 0xff; /* only first 8 CPUs vaild for VIC CPI */ | 1440 | cpuset &= 0xff; /* only first 8 CPUs vaild for VIC CPI */ |
| 1441 | if(cpuset == 0) | 1441 | if(cpuset == 0) |
| 1442 | return; | 1442 | return; |
| 1443 | for_each_online_cpu(cpu) { | 1443 | for_each_online_cpu(cpu) { |
| 1444 | if(cpuset & (1<<cpu)) | 1444 | if(cpuset & (1<<cpu)) |
| 1445 | set_bit(cpi, &vic_cpi_mailbox[cpu]); | 1445 | set_bit(cpi, &vic_cpi_mailbox[cpu]); |
| 1446 | } | 1446 | } |
| 1447 | if(cpuset) | 1447 | if(cpuset) |
| 1448 | outb((__u8)cpuset, VIC_CPI_Registers[VIC_CPI_LEVEL0]); | 1448 | outb((__u8)cpuset, VIC_CPI_Registers[VIC_CPI_LEVEL0]); |
| 1449 | } | 1449 | } |
| 1450 | 1450 | ||
| 1451 | /* Acknowledge receipt of CPI in the QIC, clear in QIC hardware and | 1451 | /* Acknowledge receipt of CPI in the QIC, clear in QIC hardware and |
| 1452 | * set the cache line to shared by reading it. | 1452 | * set the cache line to shared by reading it. |
| 1453 | * | 1453 | * |
| 1454 | * DON'T make this inline otherwise the cache line read will be | 1454 | * DON'T make this inline otherwise the cache line read will be |
| 1455 | * optimised away | 1455 | * optimised away |
| 1456 | * */ | 1456 | * */ |
| 1457 | static int | 1457 | static int |
| 1458 | ack_QIC_CPI(__u8 cpi) { | 1458 | ack_QIC_CPI(__u8 cpi) { |
| 1459 | __u8 cpu = hard_smp_processor_id(); | 1459 | __u8 cpu = hard_smp_processor_id(); |
| 1460 | 1460 | ||
| 1461 | cpi &= 7; | 1461 | cpi &= 7; |
| 1462 | 1462 | ||
| 1463 | outb(1<<cpi, QIC_INTERRUPT_CLEAR1); | 1463 | outb(1<<cpi, QIC_INTERRUPT_CLEAR1); |
| 1464 | return voyager_quad_cpi_addr[cpu]->qic_cpi[cpi].cpi; | 1464 | return voyager_quad_cpi_addr[cpu]->qic_cpi[cpi].cpi; |
| 1465 | } | 1465 | } |
| 1466 | 1466 | ||
| 1467 | static void | 1467 | static void |
| 1468 | ack_special_QIC_CPI(__u8 cpi) | 1468 | ack_special_QIC_CPI(__u8 cpi) |
| 1469 | { | 1469 | { |
| 1470 | switch(cpi) { | 1470 | switch(cpi) { |
| 1471 | case VIC_CMN_INT: | 1471 | case VIC_CMN_INT: |
| 1472 | outb(QIC_CMN_INT, QIC_INTERRUPT_CLEAR0); | 1472 | outb(QIC_CMN_INT, QIC_INTERRUPT_CLEAR0); |
| 1473 | break; | 1473 | break; |
| 1474 | case VIC_SYS_INT: | 1474 | case VIC_SYS_INT: |
| 1475 | outb(QIC_SYS_INT, QIC_INTERRUPT_CLEAR0); | 1475 | outb(QIC_SYS_INT, QIC_INTERRUPT_CLEAR0); |
| 1476 | break; | 1476 | break; |
| 1477 | } | 1477 | } |
| 1478 | /* also clear at the VIC, just in case (nop for non-extended proc) */ | 1478 | /* also clear at the VIC, just in case (nop for non-extended proc) */ |
| 1479 | ack_VIC_CPI(cpi); | 1479 | ack_VIC_CPI(cpi); |
| 1480 | } | 1480 | } |
| 1481 | 1481 | ||
| 1482 | /* Acknowledge receipt of CPI in the VIC (essentially an EOI) */ | 1482 | /* Acknowledge receipt of CPI in the VIC (essentially an EOI) */ |
| 1483 | static void | 1483 | static void |
| 1484 | ack_VIC_CPI(__u8 cpi) | 1484 | ack_VIC_CPI(__u8 cpi) |
| 1485 | { | 1485 | { |
| 1486 | #ifdef VOYAGER_DEBUG | 1486 | #ifdef VOYAGER_DEBUG |
| 1487 | unsigned long flags; | 1487 | unsigned long flags; |
| 1488 | __u16 isr; | 1488 | __u16 isr; |
| 1489 | __u8 cpu = smp_processor_id(); | 1489 | __u8 cpu = smp_processor_id(); |
| 1490 | 1490 | ||
| 1491 | local_irq_save(flags); | 1491 | local_irq_save(flags); |
| 1492 | isr = vic_read_isr(); | 1492 | isr = vic_read_isr(); |
| 1493 | if((isr & (1<<(cpi &7))) == 0) { | 1493 | if((isr & (1<<(cpi &7))) == 0) { |
| 1494 | printk("VOYAGER SMP: CPU%d lost CPI%d\n", cpu, cpi); | 1494 | printk("VOYAGER SMP: CPU%d lost CPI%d\n", cpu, cpi); |
| 1495 | } | 1495 | } |
| 1496 | #endif | 1496 | #endif |
| 1497 | /* send specific EOI; the two system interrupts have | 1497 | /* send specific EOI; the two system interrupts have |
| 1498 | * bit 4 set for a separate vector but behave as the | 1498 | * bit 4 set for a separate vector but behave as the |
| 1499 | * corresponding 3 bit intr */ | 1499 | * corresponding 3 bit intr */ |
| 1500 | outb_p(0x60|(cpi & 7),0x20); | 1500 | outb_p(0x60|(cpi & 7),0x20); |
| 1501 | 1501 | ||
| 1502 | #ifdef VOYAGER_DEBUG | 1502 | #ifdef VOYAGER_DEBUG |
| 1503 | if((vic_read_isr() & (1<<(cpi &7))) != 0) { | 1503 | if((vic_read_isr() & (1<<(cpi &7))) != 0) { |
| 1504 | printk("VOYAGER SMP: CPU%d still asserting CPI%d\n", cpu, cpi); | 1504 | printk("VOYAGER SMP: CPU%d still asserting CPI%d\n", cpu, cpi); |
| 1505 | } | 1505 | } |
| 1506 | local_irq_restore(flags); | 1506 | local_irq_restore(flags); |
| 1507 | #endif | 1507 | #endif |
| 1508 | } | 1508 | } |
| 1509 | 1509 | ||
| 1510 | /* cribbed with thanks from irq.c */ | 1510 | /* cribbed with thanks from irq.c */ |
| 1511 | #define __byte(x,y) (((unsigned char *)&(y))[x]) | 1511 | #define __byte(x,y) (((unsigned char *)&(y))[x]) |
| 1512 | #define cached_21(cpu) (__byte(0,vic_irq_mask[cpu])) | 1512 | #define cached_21(cpu) (__byte(0,vic_irq_mask[cpu])) |
| 1513 | #define cached_A1(cpu) (__byte(1,vic_irq_mask[cpu])) | 1513 | #define cached_A1(cpu) (__byte(1,vic_irq_mask[cpu])) |
| 1514 | 1514 | ||
| 1515 | static unsigned int | 1515 | static unsigned int |
| 1516 | startup_vic_irq(unsigned int irq) | 1516 | startup_vic_irq(unsigned int irq) |
| 1517 | { | 1517 | { |
| 1518 | enable_vic_irq(irq); | 1518 | enable_vic_irq(irq); |
| 1519 | 1519 | ||
| 1520 | return 0; | 1520 | return 0; |
| 1521 | } | 1521 | } |
| 1522 | 1522 | ||
| 1523 | /* The enable and disable routines. This is where we run into | 1523 | /* The enable and disable routines. This is where we run into |
| 1524 | * conflicting architectural philosophy. Fundamentally, the voyager | 1524 | * conflicting architectural philosophy. Fundamentally, the voyager |
| 1525 | * architecture does not expect to have to disable interrupts globally | 1525 | * architecture does not expect to have to disable interrupts globally |
| 1526 | * (the IRQ controllers belong to each CPU). The processor masquerade | 1526 | * (the IRQ controllers belong to each CPU). The processor masquerade |
| 1527 | * which is used to start the system shouldn't be used in a running OS | 1527 | * which is used to start the system shouldn't be used in a running OS |
| 1528 | * since it will cause great confusion if two separate CPUs drive to | 1528 | * since it will cause great confusion if two separate CPUs drive to |
| 1529 | * the same IRQ controller (I know, I've tried it). | 1529 | * the same IRQ controller (I know, I've tried it). |
| 1530 | * | 1530 | * |
| 1531 | * The solution is a variant on the NCR lazy SPL design: | 1531 | * The solution is a variant on the NCR lazy SPL design: |
| 1532 | * | 1532 | * |
| 1533 | * 1) To disable an interrupt, do nothing (other than set the | 1533 | * 1) To disable an interrupt, do nothing (other than set the |
| 1534 | * IRQ_DISABLED flag). This dares the interrupt actually to arrive. | 1534 | * IRQ_DISABLED flag). This dares the interrupt actually to arrive. |
| 1535 | * | 1535 | * |
| 1536 | * 2) If the interrupt dares to come in, raise the local mask against | 1536 | * 2) If the interrupt dares to come in, raise the local mask against |
| 1537 | * it (this will result in all the CPU masks being raised | 1537 | * it (this will result in all the CPU masks being raised |
| 1538 | * eventually). | 1538 | * eventually). |
| 1539 | * | 1539 | * |
| 1540 | * 3) To enable the interrupt, lower the mask on the local CPU and | 1540 | * 3) To enable the interrupt, lower the mask on the local CPU and |
| 1541 | * broadcast an Interrupt enable CPI which causes all other CPUs to | 1541 | * broadcast an Interrupt enable CPI which causes all other CPUs to |
| 1542 | * adjust their masks accordingly. */ | 1542 | * adjust their masks accordingly. */ |
| 1543 | 1543 | ||
| 1544 | static void | 1544 | static void |
| 1545 | enable_vic_irq(unsigned int irq) | 1545 | enable_vic_irq(unsigned int irq) |
| 1546 | { | 1546 | { |
| 1547 | /* linux doesn't to processor-irq affinity, so enable on | 1547 | /* linux doesn't to processor-irq affinity, so enable on |
| 1548 | * all CPUs we know about */ | 1548 | * all CPUs we know about */ |
| 1549 | int cpu = smp_processor_id(), real_cpu; | 1549 | int cpu = smp_processor_id(), real_cpu; |
| 1550 | __u16 mask = (1<<irq); | 1550 | __u16 mask = (1<<irq); |
| 1551 | __u32 processorList = 0; | 1551 | __u32 processorList = 0; |
| 1552 | unsigned long flags; | 1552 | unsigned long flags; |
| 1553 | 1553 | ||
| 1554 | VDEBUG(("VOYAGER: enable_vic_irq(%d) CPU%d affinity 0x%lx\n", | 1554 | VDEBUG(("VOYAGER: enable_vic_irq(%d) CPU%d affinity 0x%lx\n", |
| 1555 | irq, cpu, cpu_irq_affinity[cpu])); | 1555 | irq, cpu, cpu_irq_affinity[cpu])); |
| 1556 | spin_lock_irqsave(&vic_irq_lock, flags); | 1556 | spin_lock_irqsave(&vic_irq_lock, flags); |
| 1557 | for_each_online_cpu(real_cpu) { | 1557 | for_each_online_cpu(real_cpu) { |
| 1558 | if(!(voyager_extended_vic_processors & (1<<real_cpu))) | 1558 | if(!(voyager_extended_vic_processors & (1<<real_cpu))) |
| 1559 | continue; | 1559 | continue; |
| 1560 | if(!(cpu_irq_affinity[real_cpu] & mask)) { | 1560 | if(!(cpu_irq_affinity[real_cpu] & mask)) { |
| 1561 | /* irq has no affinity for this CPU, ignore */ | 1561 | /* irq has no affinity for this CPU, ignore */ |
| 1562 | continue; | 1562 | continue; |
| 1563 | } | 1563 | } |
| 1564 | if(real_cpu == cpu) { | 1564 | if(real_cpu == cpu) { |
| 1565 | enable_local_vic_irq(irq); | 1565 | enable_local_vic_irq(irq); |
| 1566 | } | 1566 | } |
| 1567 | else if(vic_irq_mask[real_cpu] & mask) { | 1567 | else if(vic_irq_mask[real_cpu] & mask) { |
| 1568 | vic_irq_enable_mask[real_cpu] |= mask; | 1568 | vic_irq_enable_mask[real_cpu] |= mask; |
| 1569 | processorList |= (1<<real_cpu); | 1569 | processorList |= (1<<real_cpu); |
| 1570 | } | 1570 | } |
| 1571 | } | 1571 | } |
| 1572 | spin_unlock_irqrestore(&vic_irq_lock, flags); | 1572 | spin_unlock_irqrestore(&vic_irq_lock, flags); |
| 1573 | if(processorList) | 1573 | if(processorList) |
| 1574 | send_CPI(processorList, VIC_ENABLE_IRQ_CPI); | 1574 | send_CPI(processorList, VIC_ENABLE_IRQ_CPI); |
| 1575 | } | 1575 | } |
| 1576 | 1576 | ||
| 1577 | static void | 1577 | static void |
| 1578 | disable_vic_irq(unsigned int irq) | 1578 | disable_vic_irq(unsigned int irq) |
| 1579 | { | 1579 | { |
| 1580 | /* lazy disable, do nothing */ | 1580 | /* lazy disable, do nothing */ |
| 1581 | } | 1581 | } |
| 1582 | 1582 | ||
| 1583 | static void | 1583 | static void |
| 1584 | enable_local_vic_irq(unsigned int irq) | 1584 | enable_local_vic_irq(unsigned int irq) |
| 1585 | { | 1585 | { |
| 1586 | __u8 cpu = smp_processor_id(); | 1586 | __u8 cpu = smp_processor_id(); |
| 1587 | __u16 mask = ~(1 << irq); | 1587 | __u16 mask = ~(1 << irq); |
| 1588 | __u16 old_mask = vic_irq_mask[cpu]; | 1588 | __u16 old_mask = vic_irq_mask[cpu]; |
| 1589 | 1589 | ||
| 1590 | vic_irq_mask[cpu] &= mask; | 1590 | vic_irq_mask[cpu] &= mask; |
| 1591 | if(vic_irq_mask[cpu] == old_mask) | 1591 | if(vic_irq_mask[cpu] == old_mask) |
| 1592 | return; | 1592 | return; |
| 1593 | 1593 | ||
| 1594 | VDEBUG(("VOYAGER DEBUG: Enabling irq %d in hardware on CPU %d\n", | 1594 | VDEBUG(("VOYAGER DEBUG: Enabling irq %d in hardware on CPU %d\n", |
| 1595 | irq, cpu)); | 1595 | irq, cpu)); |
| 1596 | 1596 | ||
| 1597 | if (irq & 8) { | 1597 | if (irq & 8) { |
| 1598 | outb_p(cached_A1(cpu),0xA1); | 1598 | outb_p(cached_A1(cpu),0xA1); |
| 1599 | (void)inb_p(0xA1); | 1599 | (void)inb_p(0xA1); |
| 1600 | } | 1600 | } |
| 1601 | else { | 1601 | else { |
| 1602 | outb_p(cached_21(cpu),0x21); | 1602 | outb_p(cached_21(cpu),0x21); |
| 1603 | (void)inb_p(0x21); | 1603 | (void)inb_p(0x21); |
| 1604 | } | 1604 | } |
| 1605 | } | 1605 | } |
| 1606 | 1606 | ||
| 1607 | static void | 1607 | static void |
| 1608 | disable_local_vic_irq(unsigned int irq) | 1608 | disable_local_vic_irq(unsigned int irq) |
| 1609 | { | 1609 | { |
| 1610 | __u8 cpu = smp_processor_id(); | 1610 | __u8 cpu = smp_processor_id(); |
| 1611 | __u16 mask = (1 << irq); | 1611 | __u16 mask = (1 << irq); |
| 1612 | __u16 old_mask = vic_irq_mask[cpu]; | 1612 | __u16 old_mask = vic_irq_mask[cpu]; |
| 1613 | 1613 | ||
| 1614 | if(irq == 7) | 1614 | if(irq == 7) |
| 1615 | return; | 1615 | return; |
| 1616 | 1616 | ||
| 1617 | vic_irq_mask[cpu] |= mask; | 1617 | vic_irq_mask[cpu] |= mask; |
| 1618 | if(old_mask == vic_irq_mask[cpu]) | 1618 | if(old_mask == vic_irq_mask[cpu]) |
| 1619 | return; | 1619 | return; |
| 1620 | 1620 | ||
| 1621 | VDEBUG(("VOYAGER DEBUG: Disabling irq %d in hardware on CPU %d\n", | 1621 | VDEBUG(("VOYAGER DEBUG: Disabling irq %d in hardware on CPU %d\n", |
| 1622 | irq, cpu)); | 1622 | irq, cpu)); |
| 1623 | 1623 | ||
| 1624 | if (irq & 8) { | 1624 | if (irq & 8) { |
| 1625 | outb_p(cached_A1(cpu),0xA1); | 1625 | outb_p(cached_A1(cpu),0xA1); |
| 1626 | (void)inb_p(0xA1); | 1626 | (void)inb_p(0xA1); |
| 1627 | } | 1627 | } |
| 1628 | else { | 1628 | else { |
| 1629 | outb_p(cached_21(cpu),0x21); | 1629 | outb_p(cached_21(cpu),0x21); |
| 1630 | (void)inb_p(0x21); | 1630 | (void)inb_p(0x21); |
| 1631 | } | 1631 | } |
| 1632 | } | 1632 | } |
| 1633 | 1633 | ||
| 1634 | /* The VIC is level triggered, so the ack can only be issued after the | 1634 | /* The VIC is level triggered, so the ack can only be issued after the |
| 1635 | * interrupt completes. However, we do Voyager lazy interrupt | 1635 | * interrupt completes. However, we do Voyager lazy interrupt |
| 1636 | * handling here: It is an extremely expensive operation to mask an | 1636 | * handling here: It is an extremely expensive operation to mask an |
| 1637 | * interrupt in the vic, so we merely set a flag (IRQ_DISABLED). If | 1637 | * interrupt in the vic, so we merely set a flag (IRQ_DISABLED). If |
| 1638 | * this interrupt actually comes in, then we mask and ack here to push | 1638 | * this interrupt actually comes in, then we mask and ack here to push |
| 1639 | * the interrupt off to another CPU */ | 1639 | * the interrupt off to another CPU */ |
| 1640 | static void | 1640 | static void |
| 1641 | before_handle_vic_irq(unsigned int irq) | 1641 | before_handle_vic_irq(unsigned int irq) |
| 1642 | { | 1642 | { |
| 1643 | irq_desc_t *desc = irq_desc + irq; | 1643 | irq_desc_t *desc = irq_desc + irq; |
| 1644 | __u8 cpu = smp_processor_id(); | 1644 | __u8 cpu = smp_processor_id(); |
| 1645 | 1645 | ||
| 1646 | _raw_spin_lock(&vic_irq_lock); | 1646 | _raw_spin_lock(&vic_irq_lock); |
| 1647 | vic_intr_total++; | 1647 | vic_intr_total++; |
| 1648 | vic_intr_count[cpu]++; | 1648 | vic_intr_count[cpu]++; |
| 1649 | 1649 | ||
| 1650 | if(!(cpu_irq_affinity[cpu] & (1<<irq))) { | 1650 | if(!(cpu_irq_affinity[cpu] & (1<<irq))) { |
| 1651 | /* The irq is not in our affinity mask, push it off | 1651 | /* The irq is not in our affinity mask, push it off |
| 1652 | * onto another CPU */ | 1652 | * onto another CPU */ |
| 1653 | VDEBUG(("VOYAGER DEBUG: affinity triggered disable of irq %d on cpu %d\n", | 1653 | VDEBUG(("VOYAGER DEBUG: affinity triggered disable of irq %d on cpu %d\n", |
| 1654 | irq, cpu)); | 1654 | irq, cpu)); |
| 1655 | disable_local_vic_irq(irq); | 1655 | disable_local_vic_irq(irq); |
| 1656 | /* set IRQ_INPROGRESS to prevent the handler in irq.c from | 1656 | /* set IRQ_INPROGRESS to prevent the handler in irq.c from |
| 1657 | * actually calling the interrupt routine */ | 1657 | * actually calling the interrupt routine */ |
| 1658 | desc->status |= IRQ_REPLAY | IRQ_INPROGRESS; | 1658 | desc->status |= IRQ_REPLAY | IRQ_INPROGRESS; |
| 1659 | } else if(desc->status & IRQ_DISABLED) { | 1659 | } else if(desc->status & IRQ_DISABLED) { |
| 1660 | /* Damn, the interrupt actually arrived, do the lazy | 1660 | /* Damn, the interrupt actually arrived, do the lazy |
| 1661 | * disable thing. The interrupt routine in irq.c will | 1661 | * disable thing. The interrupt routine in irq.c will |
| 1662 | * not handle a IRQ_DISABLED interrupt, so nothing more | 1662 | * not handle a IRQ_DISABLED interrupt, so nothing more |
| 1663 | * need be done here */ | 1663 | * need be done here */ |
| 1664 | VDEBUG(("VOYAGER DEBUG: lazy disable of irq %d on CPU %d\n", | 1664 | VDEBUG(("VOYAGER DEBUG: lazy disable of irq %d on CPU %d\n", |
| 1665 | irq, cpu)); | 1665 | irq, cpu)); |
| 1666 | disable_local_vic_irq(irq); | 1666 | disable_local_vic_irq(irq); |
| 1667 | desc->status |= IRQ_REPLAY; | 1667 | desc->status |= IRQ_REPLAY; |
| 1668 | } else { | 1668 | } else { |
| 1669 | desc->status &= ~IRQ_REPLAY; | 1669 | desc->status &= ~IRQ_REPLAY; |
| 1670 | } | 1670 | } |
| 1671 | 1671 | ||
| 1672 | _raw_spin_unlock(&vic_irq_lock); | 1672 | _raw_spin_unlock(&vic_irq_lock); |
| 1673 | } | 1673 | } |
| 1674 | 1674 | ||
| 1675 | /* Finish the VIC interrupt: basically mask */ | 1675 | /* Finish the VIC interrupt: basically mask */ |
| 1676 | static void | 1676 | static void |
| 1677 | after_handle_vic_irq(unsigned int irq) | 1677 | after_handle_vic_irq(unsigned int irq) |
| 1678 | { | 1678 | { |
| 1679 | irq_desc_t *desc = irq_desc + irq; | 1679 | irq_desc_t *desc = irq_desc + irq; |
| 1680 | 1680 | ||
| 1681 | _raw_spin_lock(&vic_irq_lock); | 1681 | _raw_spin_lock(&vic_irq_lock); |
| 1682 | { | 1682 | { |
| 1683 | unsigned int status = desc->status & ~IRQ_INPROGRESS; | 1683 | unsigned int status = desc->status & ~IRQ_INPROGRESS; |
| 1684 | #ifdef VOYAGER_DEBUG | 1684 | #ifdef VOYAGER_DEBUG |
| 1685 | __u16 isr; | 1685 | __u16 isr; |
| 1686 | #endif | 1686 | #endif |
| 1687 | 1687 | ||
| 1688 | desc->status = status; | 1688 | desc->status = status; |
| 1689 | if ((status & IRQ_DISABLED)) | 1689 | if ((status & IRQ_DISABLED)) |
| 1690 | disable_local_vic_irq(irq); | 1690 | disable_local_vic_irq(irq); |
| 1691 | #ifdef VOYAGER_DEBUG | 1691 | #ifdef VOYAGER_DEBUG |
| 1692 | /* DEBUG: before we ack, check what's in progress */ | 1692 | /* DEBUG: before we ack, check what's in progress */ |
| 1693 | isr = vic_read_isr(); | 1693 | isr = vic_read_isr(); |
| 1694 | if((isr & (1<<irq) && !(status & IRQ_REPLAY)) == 0) { | 1694 | if((isr & (1<<irq) && !(status & IRQ_REPLAY)) == 0) { |
| 1695 | int i; | 1695 | int i; |
| 1696 | __u8 cpu = smp_processor_id(); | 1696 | __u8 cpu = smp_processor_id(); |
| 1697 | __u8 real_cpu; | 1697 | __u8 real_cpu; |
| 1698 | int mask; /* Um... initialize me??? --RR */ | 1698 | int mask; /* Um... initialize me??? --RR */ |
| 1699 | 1699 | ||
| 1700 | printk("VOYAGER SMP: CPU%d lost interrupt %d\n", | 1700 | printk("VOYAGER SMP: CPU%d lost interrupt %d\n", |
| 1701 | cpu, irq); | 1701 | cpu, irq); |
| 1702 | for_each_cpu(real_cpu, mask) { | 1702 | for_each_cpu(real_cpu, mask) { |
| 1703 | 1703 | ||
| 1704 | outb(VIC_CPU_MASQUERADE_ENABLE | real_cpu, | 1704 | outb(VIC_CPU_MASQUERADE_ENABLE | real_cpu, |
| 1705 | VIC_PROCESSOR_ID); | 1705 | VIC_PROCESSOR_ID); |
| 1706 | isr = vic_read_isr(); | 1706 | isr = vic_read_isr(); |
| 1707 | if(isr & (1<<irq)) { | 1707 | if(isr & (1<<irq)) { |
| 1708 | printk("VOYAGER SMP: CPU%d ack irq %d\n", | 1708 | printk("VOYAGER SMP: CPU%d ack irq %d\n", |
| 1709 | real_cpu, irq); | 1709 | real_cpu, irq); |
| 1710 | ack_vic_irq(irq); | 1710 | ack_vic_irq(irq); |
| 1711 | } | 1711 | } |
| 1712 | outb(cpu, VIC_PROCESSOR_ID); | 1712 | outb(cpu, VIC_PROCESSOR_ID); |
| 1713 | } | 1713 | } |
| 1714 | } | 1714 | } |
| 1715 | #endif /* VOYAGER_DEBUG */ | 1715 | #endif /* VOYAGER_DEBUG */ |
| 1716 | /* as soon as we ack, the interrupt is eligible for | 1716 | /* as soon as we ack, the interrupt is eligible for |
| 1717 | * receipt by another CPU so everything must be in | 1717 | * receipt by another CPU so everything must be in |
| 1718 | * order here */ | 1718 | * order here */ |
| 1719 | ack_vic_irq(irq); | 1719 | ack_vic_irq(irq); |
| 1720 | if(status & IRQ_REPLAY) { | 1720 | if(status & IRQ_REPLAY) { |
| 1721 | /* replay is set if we disable the interrupt | 1721 | /* replay is set if we disable the interrupt |
| 1722 | * in the before_handle_vic_irq() routine, so | 1722 | * in the before_handle_vic_irq() routine, so |
| 1723 | * clear the in progress bit here to allow the | 1723 | * clear the in progress bit here to allow the |
| 1724 | * next CPU to handle this correctly */ | 1724 | * next CPU to handle this correctly */ |
| 1725 | desc->status &= ~(IRQ_REPLAY | IRQ_INPROGRESS); | 1725 | desc->status &= ~(IRQ_REPLAY | IRQ_INPROGRESS); |
| 1726 | } | 1726 | } |
| 1727 | #ifdef VOYAGER_DEBUG | 1727 | #ifdef VOYAGER_DEBUG |
| 1728 | isr = vic_read_isr(); | 1728 | isr = vic_read_isr(); |
| 1729 | if((isr & (1<<irq)) != 0) | 1729 | if((isr & (1<<irq)) != 0) |
| 1730 | printk("VOYAGER SMP: after_handle_vic_irq() after ack irq=%d, isr=0x%x\n", | 1730 | printk("VOYAGER SMP: after_handle_vic_irq() after ack irq=%d, isr=0x%x\n", |
| 1731 | irq, isr); | 1731 | irq, isr); |
| 1732 | #endif /* VOYAGER_DEBUG */ | 1732 | #endif /* VOYAGER_DEBUG */ |
| 1733 | } | 1733 | } |
| 1734 | _raw_spin_unlock(&vic_irq_lock); | 1734 | _raw_spin_unlock(&vic_irq_lock); |
| 1735 | 1735 | ||
| 1736 | /* All code after this point is out of the main path - the IRQ | 1736 | /* All code after this point is out of the main path - the IRQ |
| 1737 | * may be intercepted by another CPU if reasserted */ | 1737 | * may be intercepted by another CPU if reasserted */ |
| 1738 | } | 1738 | } |
| 1739 | 1739 | ||
| 1740 | 1740 | ||
| 1741 | /* Linux processor - interrupt affinity manipulations. | 1741 | /* Linux processor - interrupt affinity manipulations. |
| 1742 | * | 1742 | * |
| 1743 | * For each processor, we maintain a 32 bit irq affinity mask. | 1743 | * For each processor, we maintain a 32 bit irq affinity mask. |
| 1744 | * Initially it is set to all 1's so every processor accepts every | 1744 | * Initially it is set to all 1's so every processor accepts every |
| 1745 | * interrupt. In this call, we change the processor's affinity mask: | 1745 | * interrupt. In this call, we change the processor's affinity mask: |
| 1746 | * | 1746 | * |
| 1747 | * Change from enable to disable: | 1747 | * Change from enable to disable: |
| 1748 | * | 1748 | * |
| 1749 | * If the interrupt ever comes in to the processor, we will disable it | 1749 | * If the interrupt ever comes in to the processor, we will disable it |
| 1750 | * and ack it to push it off to another CPU, so just accept the mask here. | 1750 | * and ack it to push it off to another CPU, so just accept the mask here. |
| 1751 | * | 1751 | * |
| 1752 | * Change from disable to enable: | 1752 | * Change from disable to enable: |
| 1753 | * | 1753 | * |
| 1754 | * change the mask and then do an interrupt enable CPI to re-enable on | 1754 | * change the mask and then do an interrupt enable CPI to re-enable on |
| 1755 | * the selected processors */ | 1755 | * the selected processors */ |
| 1756 | 1756 | ||
| 1757 | void | 1757 | void |
| 1758 | set_vic_irq_affinity(unsigned int irq, cpumask_t mask) | 1758 | set_vic_irq_affinity(unsigned int irq, cpumask_t mask) |
| 1759 | { | 1759 | { |
| 1760 | /* Only extended processors handle interrupts */ | 1760 | /* Only extended processors handle interrupts */ |
| 1761 | unsigned long real_mask; | 1761 | unsigned long real_mask; |
| 1762 | unsigned long irq_mask = 1 << irq; | 1762 | unsigned long irq_mask = 1 << irq; |
| 1763 | int cpu; | 1763 | int cpu; |
| 1764 | 1764 | ||
| 1765 | real_mask = cpus_addr(mask)[0] & voyager_extended_vic_processors; | 1765 | real_mask = cpus_addr(mask)[0] & voyager_extended_vic_processors; |
| 1766 | 1766 | ||
| 1767 | if(cpus_addr(mask)[0] == 0) | 1767 | if(cpus_addr(mask)[0] == 0) |
| 1768 | /* can't have no cpu's to accept the interrupt -- extremely | 1768 | /* can't have no cpu's to accept the interrupt -- extremely |
| 1769 | * bad things will happen */ | 1769 | * bad things will happen */ |
| 1770 | return; | 1770 | return; |
| 1771 | 1771 | ||
| 1772 | if(irq == 0) | 1772 | if(irq == 0) |
| 1773 | /* can't change the affinity of the timer IRQ. This | 1773 | /* can't change the affinity of the timer IRQ. This |
| 1774 | * is due to the constraint in the voyager | 1774 | * is due to the constraint in the voyager |
| 1775 | * architecture that the CPI also comes in on and IRQ | 1775 | * architecture that the CPI also comes in on and IRQ |
| 1776 | * line and we have chosen IRQ0 for this. If you | 1776 | * line and we have chosen IRQ0 for this. If you |
| 1777 | * raise the mask on this interrupt, the processor | 1777 | * raise the mask on this interrupt, the processor |
| 1778 | * will no-longer be able to accept VIC CPIs */ | 1778 | * will no-longer be able to accept VIC CPIs */ |
| 1779 | return; | 1779 | return; |
| 1780 | 1780 | ||
| 1781 | if(irq >= 32) | 1781 | if(irq >= 32) |
| 1782 | /* You can only have 32 interrupts in a voyager system | 1782 | /* You can only have 32 interrupts in a voyager system |
| 1783 | * (and 32 only if you have a secondary microchannel | 1783 | * (and 32 only if you have a secondary microchannel |
| 1784 | * bus) */ | 1784 | * bus) */ |
| 1785 | return; | 1785 | return; |
| 1786 | 1786 | ||
| 1787 | for_each_online_cpu(cpu) { | 1787 | for_each_online_cpu(cpu) { |
| 1788 | unsigned long cpu_mask = 1 << cpu; | 1788 | unsigned long cpu_mask = 1 << cpu; |
| 1789 | 1789 | ||
| 1790 | if(cpu_mask & real_mask) { | 1790 | if(cpu_mask & real_mask) { |
| 1791 | /* enable the interrupt for this cpu */ | 1791 | /* enable the interrupt for this cpu */ |
| 1792 | cpu_irq_affinity[cpu] |= irq_mask; | 1792 | cpu_irq_affinity[cpu] |= irq_mask; |
| 1793 | } else { | 1793 | } else { |
| 1794 | /* disable the interrupt for this cpu */ | 1794 | /* disable the interrupt for this cpu */ |
| 1795 | cpu_irq_affinity[cpu] &= ~irq_mask; | 1795 | cpu_irq_affinity[cpu] &= ~irq_mask; |
| 1796 | } | 1796 | } |
| 1797 | } | 1797 | } |
| 1798 | /* this is magic, we now have the correct affinity maps, so | 1798 | /* this is magic, we now have the correct affinity maps, so |
| 1799 | * enable the interrupt. This will send an enable CPI to | 1799 | * enable the interrupt. This will send an enable CPI to |
| 1800 | * those cpu's who need to enable it in their local masks, | 1800 | * those cpu's who need to enable it in their local masks, |
| 1801 | * causing them to correct for the new affinity . If the | 1801 | * causing them to correct for the new affinity . If the |
| 1802 | * interrupt is currently globally disabled, it will simply be | 1802 | * interrupt is currently globally disabled, it will simply be |
| 1803 | * disabled again as it comes in (voyager lazy disable). If | 1803 | * disabled again as it comes in (voyager lazy disable). If |
| 1804 | * the affinity map is tightened to disable the interrupt on a | 1804 | * the affinity map is tightened to disable the interrupt on a |
| 1805 | * cpu, it will be pushed off when it comes in */ | 1805 | * cpu, it will be pushed off when it comes in */ |
| 1806 | enable_vic_irq(irq); | 1806 | enable_vic_irq(irq); |
| 1807 | } | 1807 | } |
| 1808 | 1808 | ||
| 1809 | static void | 1809 | static void |
| 1810 | ack_vic_irq(unsigned int irq) | 1810 | ack_vic_irq(unsigned int irq) |
| 1811 | { | 1811 | { |
| 1812 | if (irq & 8) { | 1812 | if (irq & 8) { |
| 1813 | outb(0x62,0x20); /* Specific EOI to cascade */ | 1813 | outb(0x62,0x20); /* Specific EOI to cascade */ |
| 1814 | outb(0x60|(irq & 7),0xA0); | 1814 | outb(0x60|(irq & 7),0xA0); |
| 1815 | } else { | 1815 | } else { |
| 1816 | outb(0x60 | (irq & 7),0x20); | 1816 | outb(0x60 | (irq & 7),0x20); |
| 1817 | } | 1817 | } |
| 1818 | } | 1818 | } |
| 1819 | 1819 | ||
| 1820 | /* enable the CPIs. In the VIC, the CPIs are delivered by the 8259 | 1820 | /* enable the CPIs. In the VIC, the CPIs are delivered by the 8259 |
| 1821 | * but are not vectored by it. This means that the 8259 mask must be | 1821 | * but are not vectored by it. This means that the 8259 mask must be |
| 1822 | * lowered to receive them */ | 1822 | * lowered to receive them */ |
| 1823 | static __init void | 1823 | static __init void |
| 1824 | vic_enable_cpi(void) | 1824 | vic_enable_cpi(void) |
| 1825 | { | 1825 | { |
| 1826 | __u8 cpu = smp_processor_id(); | 1826 | __u8 cpu = smp_processor_id(); |
| 1827 | 1827 | ||
| 1828 | /* just take a copy of the current mask (nop for boot cpu) */ | 1828 | /* just take a copy of the current mask (nop for boot cpu) */ |
| 1829 | vic_irq_mask[cpu] = vic_irq_mask[boot_cpu_id]; | 1829 | vic_irq_mask[cpu] = vic_irq_mask[boot_cpu_id]; |
| 1830 | 1830 | ||
| 1831 | enable_local_vic_irq(VIC_CPI_LEVEL0); | 1831 | enable_local_vic_irq(VIC_CPI_LEVEL0); |
| 1832 | enable_local_vic_irq(VIC_CPI_LEVEL1); | 1832 | enable_local_vic_irq(VIC_CPI_LEVEL1); |
| 1833 | /* for sys int and cmn int */ | 1833 | /* for sys int and cmn int */ |
| 1834 | enable_local_vic_irq(7); | 1834 | enable_local_vic_irq(7); |
| 1835 | 1835 | ||
| 1836 | if(is_cpu_quad()) { | 1836 | if(is_cpu_quad()) { |
| 1837 | outb(QIC_DEFAULT_MASK0, QIC_MASK_REGISTER0); | 1837 | outb(QIC_DEFAULT_MASK0, QIC_MASK_REGISTER0); |
| 1838 | outb(QIC_CPI_ENABLE, QIC_MASK_REGISTER1); | 1838 | outb(QIC_CPI_ENABLE, QIC_MASK_REGISTER1); |
| 1839 | VDEBUG(("VOYAGER SMP: QIC ENABLE CPI: CPU%d: MASK 0x%x\n", | 1839 | VDEBUG(("VOYAGER SMP: QIC ENABLE CPI: CPU%d: MASK 0x%x\n", |
| 1840 | cpu, QIC_CPI_ENABLE)); | 1840 | cpu, QIC_CPI_ENABLE)); |
| 1841 | } | 1841 | } |
| 1842 | 1842 | ||
| 1843 | VDEBUG(("VOYAGER SMP: ENABLE CPI: CPU%d: MASK 0x%x\n", | 1843 | VDEBUG(("VOYAGER SMP: ENABLE CPI: CPU%d: MASK 0x%x\n", |
| 1844 | cpu, vic_irq_mask[cpu])); | 1844 | cpu, vic_irq_mask[cpu])); |
| 1845 | } | 1845 | } |
| 1846 | 1846 | ||
| 1847 | void | 1847 | void |
| 1848 | voyager_smp_dump() | 1848 | voyager_smp_dump() |
| 1849 | { | 1849 | { |
| 1850 | int old_cpu = smp_processor_id(), cpu; | 1850 | int old_cpu = smp_processor_id(), cpu; |
| 1851 | 1851 | ||
| 1852 | /* dump the interrupt masks of each processor */ | 1852 | /* dump the interrupt masks of each processor */ |
| 1853 | for_each_online_cpu(cpu) { | 1853 | for_each_online_cpu(cpu) { |
| 1854 | __u16 imr, isr, irr; | 1854 | __u16 imr, isr, irr; |
| 1855 | unsigned long flags; | 1855 | unsigned long flags; |
| 1856 | 1856 | ||
| 1857 | local_irq_save(flags); | 1857 | local_irq_save(flags); |
| 1858 | outb(VIC_CPU_MASQUERADE_ENABLE | cpu, VIC_PROCESSOR_ID); | 1858 | outb(VIC_CPU_MASQUERADE_ENABLE | cpu, VIC_PROCESSOR_ID); |
| 1859 | imr = (inb(0xa1) << 8) | inb(0x21); | 1859 | imr = (inb(0xa1) << 8) | inb(0x21); |
| 1860 | outb(0x0a, 0xa0); | 1860 | outb(0x0a, 0xa0); |
| 1861 | irr = inb(0xa0) << 8; | 1861 | irr = inb(0xa0) << 8; |
| 1862 | outb(0x0a, 0x20); | 1862 | outb(0x0a, 0x20); |
| 1863 | irr |= inb(0x20); | 1863 | irr |= inb(0x20); |
| 1864 | outb(0x0b, 0xa0); | 1864 | outb(0x0b, 0xa0); |
| 1865 | isr = inb(0xa0) << 8; | 1865 | isr = inb(0xa0) << 8; |
| 1866 | outb(0x0b, 0x20); | 1866 | outb(0x0b, 0x20); |
| 1867 | isr |= inb(0x20); | 1867 | isr |= inb(0x20); |
| 1868 | outb(old_cpu, VIC_PROCESSOR_ID); | 1868 | outb(old_cpu, VIC_PROCESSOR_ID); |
| 1869 | local_irq_restore(flags); | 1869 | local_irq_restore(flags); |
| 1870 | printk("\tCPU%d: mask=0x%x, IMR=0x%x, IRR=0x%x, ISR=0x%x\n", | 1870 | printk("\tCPU%d: mask=0x%x, IMR=0x%x, IRR=0x%x, ISR=0x%x\n", |
| 1871 | cpu, vic_irq_mask[cpu], imr, irr, isr); | 1871 | cpu, vic_irq_mask[cpu], imr, irr, isr); |
| 1872 | #if 0 | 1872 | #if 0 |
| 1873 | /* These lines are put in to try to unstick an un ack'd irq */ | 1873 | /* These lines are put in to try to unstick an un ack'd irq */ |
| 1874 | if(isr != 0) { | 1874 | if(isr != 0) { |
| 1875 | int irq; | 1875 | int irq; |
| 1876 | for(irq=0; irq<16; irq++) { | 1876 | for(irq=0; irq<16; irq++) { |
| 1877 | if(isr & (1<<irq)) { | 1877 | if(isr & (1<<irq)) { |
| 1878 | printk("\tCPU%d: ack irq %d\n", | 1878 | printk("\tCPU%d: ack irq %d\n", |
| 1879 | cpu, irq); | 1879 | cpu, irq); |
| 1880 | local_irq_save(flags); | 1880 | local_irq_save(flags); |
| 1881 | outb(VIC_CPU_MASQUERADE_ENABLE | cpu, | 1881 | outb(VIC_CPU_MASQUERADE_ENABLE | cpu, |
| 1882 | VIC_PROCESSOR_ID); | 1882 | VIC_PROCESSOR_ID); |
| 1883 | ack_vic_irq(irq); | 1883 | ack_vic_irq(irq); |
| 1884 | outb(old_cpu, VIC_PROCESSOR_ID); | 1884 | outb(old_cpu, VIC_PROCESSOR_ID); |
| 1885 | local_irq_restore(flags); | 1885 | local_irq_restore(flags); |
| 1886 | } | 1886 | } |
| 1887 | } | 1887 | } |
| 1888 | } | 1888 | } |
| 1889 | #endif | 1889 | #endif |
| 1890 | } | 1890 | } |
| 1891 | } | 1891 | } |
| 1892 | 1892 | ||
| 1893 | void | 1893 | void |
| 1894 | smp_voyager_power_off(void *dummy) | 1894 | smp_voyager_power_off(void *dummy) |
| 1895 | { | 1895 | { |
| 1896 | if(smp_processor_id() == boot_cpu_id) | 1896 | if(smp_processor_id() == boot_cpu_id) |
| 1897 | voyager_power_off(); | 1897 | voyager_power_off(); |
| 1898 | else | 1898 | else |
| 1899 | smp_stop_cpu_function(NULL); | 1899 | smp_stop_cpu_function(NULL); |
| 1900 | } | 1900 | } |
| 1901 | 1901 | ||
| 1902 | void __init | 1902 | void __init |
| 1903 | smp_prepare_cpus(unsigned int max_cpus) | 1903 | smp_prepare_cpus(unsigned int max_cpus) |
| 1904 | { | 1904 | { |
| 1905 | /* FIXME: ignore max_cpus for now */ | 1905 | /* FIXME: ignore max_cpus for now */ |
| 1906 | smp_boot_cpus(); | 1906 | smp_boot_cpus(); |
| 1907 | } | 1907 | } |
| 1908 | 1908 | ||
| 1909 | void __devinit smp_prepare_boot_cpu(void) | 1909 | void __devinit smp_prepare_boot_cpu(void) |
| 1910 | { | 1910 | { |
| 1911 | cpu_set(smp_processor_id(), cpu_online_map); | 1911 | cpu_set(smp_processor_id(), cpu_online_map); |
| 1912 | cpu_set(smp_processor_id(), cpu_callout_map); | 1912 | cpu_set(smp_processor_id(), cpu_callout_map); |
| 1913 | } | 1913 | } |
| 1914 | 1914 | ||
| 1915 | int __devinit | 1915 | int __devinit |
| 1916 | __cpu_up(unsigned int cpu) | 1916 | __cpu_up(unsigned int cpu) |
| 1917 | { | 1917 | { |
| 1918 | /* This only works at boot for x86. See "rewrite" above. */ | 1918 | /* This only works at boot for x86. See "rewrite" above. */ |
| 1919 | if (cpu_isset(cpu, smp_commenced_mask)) | 1919 | if (cpu_isset(cpu, smp_commenced_mask)) |
| 1920 | return -ENOSYS; | 1920 | return -ENOSYS; |
| 1921 | 1921 | ||
| 1922 | /* In case one didn't come up */ | 1922 | /* In case one didn't come up */ |
| 1923 | if (!cpu_isset(cpu, cpu_callin_map)) | 1923 | if (!cpu_isset(cpu, cpu_callin_map)) |
| 1924 | return -EIO; | 1924 | return -EIO; |
| 1925 | /* Unleash the CPU! */ | 1925 | /* Unleash the CPU! */ |
| 1926 | cpu_set(cpu, smp_commenced_mask); | 1926 | cpu_set(cpu, smp_commenced_mask); |
| 1927 | while (!cpu_isset(cpu, cpu_online_map)) | 1927 | while (!cpu_isset(cpu, cpu_online_map)) |
| 1928 | mb(); | 1928 | mb(); |
| 1929 | return 0; | 1929 | return 0; |
| 1930 | } | 1930 | } |
| 1931 | 1931 | ||
| 1932 | void __init | 1932 | void __init |
| 1933 | smp_cpus_done(unsigned int max_cpus) | 1933 | smp_cpus_done(unsigned int max_cpus) |
| 1934 | { | 1934 | { |
| 1935 | zap_low_mappings(); | 1935 | zap_low_mappings(); |
| 1936 | } | 1936 | } |
| 1937 | 1937 |
include/asm-i386/msr.h
| 1 | #ifndef __ASM_MSR_H | 1 | #ifndef __ASM_MSR_H |
| 2 | #define __ASM_MSR_H | 2 | #define __ASM_MSR_H |
| 3 | 3 | ||
| 4 | /* | 4 | /* |
| 5 | * Access to machine-specific registers (available on 586 and better only) | 5 | * Access to machine-specific registers (available on 586 and better only) |
| 6 | * Note: the rd* operations modify the parameters directly (without using | 6 | * Note: the rd* operations modify the parameters directly (without using |
| 7 | * pointer indirection), this allows gcc to optimize better | 7 | * pointer indirection), this allows gcc to optimize better |
| 8 | */ | 8 | */ |
| 9 | 9 | ||
| 10 | #define rdmsr(msr,val1,val2) \ | 10 | #define rdmsr(msr,val1,val2) \ |
| 11 | __asm__ __volatile__("rdmsr" \ | 11 | __asm__ __volatile__("rdmsr" \ |
| 12 | : "=a" (val1), "=d" (val2) \ | 12 | : "=a" (val1), "=d" (val2) \ |
| 13 | : "c" (msr)) | 13 | : "c" (msr)) |
| 14 | 14 | ||
| 15 | #define wrmsr(msr,val1,val2) \ | 15 | #define wrmsr(msr,val1,val2) \ |
| 16 | __asm__ __volatile__("wrmsr" \ | 16 | __asm__ __volatile__("wrmsr" \ |
| 17 | : /* no outputs */ \ | 17 | : /* no outputs */ \ |
| 18 | : "c" (msr), "a" (val1), "d" (val2)) | 18 | : "c" (msr), "a" (val1), "d" (val2)) |
| 19 | 19 | ||
| 20 | #define rdmsrl(msr,val) do { \ | 20 | #define rdmsrl(msr,val) do { \ |
| 21 | unsigned long l__,h__; \ | 21 | unsigned long l__,h__; \ |
| 22 | rdmsr (msr, l__, h__); \ | 22 | rdmsr (msr, l__, h__); \ |
| 23 | val = l__; \ | 23 | val = l__; \ |
| 24 | val |= ((u64)h__<<32); \ | 24 | val |= ((u64)h__<<32); \ |
| 25 | } while(0) | 25 | } while(0) |
| 26 | 26 | ||
| 27 | static inline void wrmsrl (unsigned long msr, unsigned long long val) | 27 | static inline void wrmsrl (unsigned long msr, unsigned long long val) |
| 28 | { | 28 | { |
| 29 | unsigned long lo, hi; | 29 | unsigned long lo, hi; |
| 30 | lo = (unsigned long) val; | 30 | lo = (unsigned long) val; |
| 31 | hi = val >> 32; | 31 | hi = val >> 32; |
| 32 | wrmsr (msr, lo, hi); | 32 | wrmsr (msr, lo, hi); |
| 33 | } | 33 | } |
| 34 | 34 | ||
| 35 | /* wrmsr with exception handling */ | 35 | /* wrmsr with exception handling */ |
| 36 | #define wrmsr_safe(msr,a,b) ({ int ret__; \ | 36 | #define wrmsr_safe(msr,a,b) ({ int ret__; \ |
| 37 | asm volatile("2: wrmsr ; xorl %0,%0\n" \ | 37 | asm volatile("2: wrmsr ; xorl %0,%0\n" \ |
| 38 | "1:\n\t" \ | 38 | "1:\n\t" \ |
| 39 | ".section .fixup,\"ax\"\n\t" \ | 39 | ".section .fixup,\"ax\"\n\t" \ |
| 40 | "3: movl %4,%0 ; jmp 1b\n\t" \ | 40 | "3: movl %4,%0 ; jmp 1b\n\t" \ |
| 41 | ".previous\n\t" \ | 41 | ".previous\n\t" \ |
| 42 | ".section __ex_table,\"a\"\n" \ | 42 | ".section __ex_table,\"a\"\n" \ |
| 43 | " .align 4\n\t" \ | 43 | " .align 4\n\t" \ |
| 44 | " .long 2b,3b\n\t" \ | 44 | " .long 2b,3b\n\t" \ |
| 45 | ".previous" \ | 45 | ".previous" \ |
| 46 | : "=a" (ret__) \ | 46 | : "=a" (ret__) \ |
| 47 | : "c" (msr), "0" (a), "d" (b), "i" (-EFAULT));\ | 47 | : "c" (msr), "0" (a), "d" (b), "i" (-EFAULT));\ |
| 48 | ret__; }) | 48 | ret__; }) |
| 49 | 49 | ||
| 50 | /* rdmsr with exception handling */ | ||
| 51 | #define rdmsr_safe(msr,a,b) ({ int ret__; \ | ||
| 52 | asm volatile("2: rdmsr ; xorl %0,%0\n" \ | ||
| 53 | "1:\n\t" \ | ||
| 54 | ".section .fixup,\"ax\"\n\t" \ | ||
| 55 | "3: movl %4,%0 ; jmp 1b\n\t" \ | ||
| 56 | ".previous\n\t" \ | ||
| 57 | ".section __ex_table,\"a\"\n" \ | ||
| 58 | " .align 4\n\t" \ | ||
| 59 | " .long 2b,3b\n\t" \ | ||
| 60 | ".previous" \ | ||
| 61 | : "=r" (ret__), "=a" (*(a)), "=d" (*(b)) \ | ||
| 62 | : "c" (msr), "i" (-EFAULT));\ | ||
| 63 | ret__; }) | ||
| 64 | |||
| 50 | #define rdtsc(low,high) \ | 65 | #define rdtsc(low,high) \ |
| 51 | __asm__ __volatile__("rdtsc" : "=a" (low), "=d" (high)) | 66 | __asm__ __volatile__("rdtsc" : "=a" (low), "=d" (high)) |
| 52 | 67 | ||
| 53 | #define rdtscl(low) \ | 68 | #define rdtscl(low) \ |
| 54 | __asm__ __volatile__("rdtsc" : "=a" (low) : : "edx") | 69 | __asm__ __volatile__("rdtsc" : "=a" (low) : : "edx") |
| 55 | 70 | ||
| 56 | #define rdtscll(val) \ | 71 | #define rdtscll(val) \ |
| 57 | __asm__ __volatile__("rdtsc" : "=A" (val)) | 72 | __asm__ __volatile__("rdtsc" : "=A" (val)) |
| 58 | 73 | ||
| 59 | #define write_tsc(val1,val2) wrmsr(0x10, val1, val2) | 74 | #define write_tsc(val1,val2) wrmsr(0x10, val1, val2) |
| 60 | 75 | ||
| 61 | #define rdpmc(counter,low,high) \ | 76 | #define rdpmc(counter,low,high) \ |
| 62 | __asm__ __volatile__("rdpmc" \ | 77 | __asm__ __volatile__("rdpmc" \ |
| 63 | : "=a" (low), "=d" (high) \ | 78 | : "=a" (low), "=d" (high) \ |
| 64 | : "c" (counter)) | 79 | : "c" (counter)) |
| 65 | 80 | ||
| 66 | /* symbolic names for some interesting MSRs */ | 81 | /* symbolic names for some interesting MSRs */ |
| 67 | /* Intel defined MSRs. */ | 82 | /* Intel defined MSRs. */ |
| 68 | #define MSR_IA32_P5_MC_ADDR 0 | 83 | #define MSR_IA32_P5_MC_ADDR 0 |
| 69 | #define MSR_IA32_P5_MC_TYPE 1 | 84 | #define MSR_IA32_P5_MC_TYPE 1 |
| 70 | #define MSR_IA32_PLATFORM_ID 0x17 | 85 | #define MSR_IA32_PLATFORM_ID 0x17 |
| 71 | #define MSR_IA32_EBL_CR_POWERON 0x2a | 86 | #define MSR_IA32_EBL_CR_POWERON 0x2a |
| 72 | 87 | ||
| 73 | #define MSR_IA32_APICBASE 0x1b | 88 | #define MSR_IA32_APICBASE 0x1b |
| 74 | #define MSR_IA32_APICBASE_BSP (1<<8) | 89 | #define MSR_IA32_APICBASE_BSP (1<<8) |
| 75 | #define MSR_IA32_APICBASE_ENABLE (1<<11) | 90 | #define MSR_IA32_APICBASE_ENABLE (1<<11) |
| 76 | #define MSR_IA32_APICBASE_BASE (0xfffff<<12) | 91 | #define MSR_IA32_APICBASE_BASE (0xfffff<<12) |
| 77 | 92 | ||
| 78 | #define MSR_IA32_UCODE_WRITE 0x79 | 93 | #define MSR_IA32_UCODE_WRITE 0x79 |
| 79 | #define MSR_IA32_UCODE_REV 0x8b | 94 | #define MSR_IA32_UCODE_REV 0x8b |
| 80 | 95 | ||
| 81 | #define MSR_P6_PERFCTR0 0xc1 | 96 | #define MSR_P6_PERFCTR0 0xc1 |
| 82 | #define MSR_P6_PERFCTR1 0xc2 | 97 | #define MSR_P6_PERFCTR1 0xc2 |
| 83 | 98 | ||
| 84 | #define MSR_IA32_BBL_CR_CTL 0x119 | 99 | #define MSR_IA32_BBL_CR_CTL 0x119 |
| 85 | 100 | ||
| 86 | #define MSR_IA32_SYSENTER_CS 0x174 | 101 | #define MSR_IA32_SYSENTER_CS 0x174 |
| 87 | #define MSR_IA32_SYSENTER_ESP 0x175 | 102 | #define MSR_IA32_SYSENTER_ESP 0x175 |
| 88 | #define MSR_IA32_SYSENTER_EIP 0x176 | 103 | #define MSR_IA32_SYSENTER_EIP 0x176 |
| 89 | 104 | ||
| 90 | #define MSR_IA32_MCG_CAP 0x179 | 105 | #define MSR_IA32_MCG_CAP 0x179 |
| 91 | #define MSR_IA32_MCG_STATUS 0x17a | 106 | #define MSR_IA32_MCG_STATUS 0x17a |
| 92 | #define MSR_IA32_MCG_CTL 0x17b | 107 | #define MSR_IA32_MCG_CTL 0x17b |
| 93 | 108 | ||
| 94 | /* P4/Xeon+ specific */ | 109 | /* P4/Xeon+ specific */ |
| 95 | #define MSR_IA32_MCG_EAX 0x180 | 110 | #define MSR_IA32_MCG_EAX 0x180 |
| 96 | #define MSR_IA32_MCG_EBX 0x181 | 111 | #define MSR_IA32_MCG_EBX 0x181 |
| 97 | #define MSR_IA32_MCG_ECX 0x182 | 112 | #define MSR_IA32_MCG_ECX 0x182 |
| 98 | #define MSR_IA32_MCG_EDX 0x183 | 113 | #define MSR_IA32_MCG_EDX 0x183 |
| 99 | #define MSR_IA32_MCG_ESI 0x184 | 114 | #define MSR_IA32_MCG_ESI 0x184 |
| 100 | #define MSR_IA32_MCG_EDI 0x185 | 115 | #define MSR_IA32_MCG_EDI 0x185 |
| 101 | #define MSR_IA32_MCG_EBP 0x186 | 116 | #define MSR_IA32_MCG_EBP 0x186 |
| 102 | #define MSR_IA32_MCG_ESP 0x187 | 117 | #define MSR_IA32_MCG_ESP 0x187 |
| 103 | #define MSR_IA32_MCG_EFLAGS 0x188 | 118 | #define MSR_IA32_MCG_EFLAGS 0x188 |
| 104 | #define MSR_IA32_MCG_EIP 0x189 | 119 | #define MSR_IA32_MCG_EIP 0x189 |
| 105 | #define MSR_IA32_MCG_RESERVED 0x18A | 120 | #define MSR_IA32_MCG_RESERVED 0x18A |
| 106 | 121 | ||
| 107 | #define MSR_P6_EVNTSEL0 0x186 | 122 | #define MSR_P6_EVNTSEL0 0x186 |
| 108 | #define MSR_P6_EVNTSEL1 0x187 | 123 | #define MSR_P6_EVNTSEL1 0x187 |
| 109 | 124 | ||
| 110 | #define MSR_IA32_PERF_STATUS 0x198 | 125 | #define MSR_IA32_PERF_STATUS 0x198 |
| 111 | #define MSR_IA32_PERF_CTL 0x199 | 126 | #define MSR_IA32_PERF_CTL 0x199 |
| 112 | 127 | ||
| 113 | #define MSR_IA32_THERM_CONTROL 0x19a | 128 | #define MSR_IA32_THERM_CONTROL 0x19a |
| 114 | #define MSR_IA32_THERM_INTERRUPT 0x19b | 129 | #define MSR_IA32_THERM_INTERRUPT 0x19b |
| 115 | #define MSR_IA32_THERM_STATUS 0x19c | 130 | #define MSR_IA32_THERM_STATUS 0x19c |
| 116 | #define MSR_IA32_MISC_ENABLE 0x1a0 | 131 | #define MSR_IA32_MISC_ENABLE 0x1a0 |
| 117 | 132 | ||
| 118 | #define MSR_IA32_DEBUGCTLMSR 0x1d9 | 133 | #define MSR_IA32_DEBUGCTLMSR 0x1d9 |
| 119 | #define MSR_IA32_LASTBRANCHFROMIP 0x1db | 134 | #define MSR_IA32_LASTBRANCHFROMIP 0x1db |
| 120 | #define MSR_IA32_LASTBRANCHTOIP 0x1dc | 135 | #define MSR_IA32_LASTBRANCHTOIP 0x1dc |
| 121 | #define MSR_IA32_LASTINTFROMIP 0x1dd | 136 | #define MSR_IA32_LASTINTFROMIP 0x1dd |
| 122 | #define MSR_IA32_LASTINTTOIP 0x1de | 137 | #define MSR_IA32_LASTINTTOIP 0x1de |
| 123 | 138 | ||
| 124 | #define MSR_IA32_MC0_CTL 0x400 | 139 | #define MSR_IA32_MC0_CTL 0x400 |
| 125 | #define MSR_IA32_MC0_STATUS 0x401 | 140 | #define MSR_IA32_MC0_STATUS 0x401 |
| 126 | #define MSR_IA32_MC0_ADDR 0x402 | 141 | #define MSR_IA32_MC0_ADDR 0x402 |
| 127 | #define MSR_IA32_MC0_MISC 0x403 | 142 | #define MSR_IA32_MC0_MISC 0x403 |
| 128 | 143 | ||
| 129 | /* Pentium IV performance counter MSRs */ | 144 | /* Pentium IV performance counter MSRs */ |
| 130 | #define MSR_P4_BPU_PERFCTR0 0x300 | 145 | #define MSR_P4_BPU_PERFCTR0 0x300 |
| 131 | #define MSR_P4_BPU_PERFCTR1 0x301 | 146 | #define MSR_P4_BPU_PERFCTR1 0x301 |
| 132 | #define MSR_P4_BPU_PERFCTR2 0x302 | 147 | #define MSR_P4_BPU_PERFCTR2 0x302 |
| 133 | #define MSR_P4_BPU_PERFCTR3 0x303 | 148 | #define MSR_P4_BPU_PERFCTR3 0x303 |
| 134 | #define MSR_P4_MS_PERFCTR0 0x304 | 149 | #define MSR_P4_MS_PERFCTR0 0x304 |
| 135 | #define MSR_P4_MS_PERFCTR1 0x305 | 150 | #define MSR_P4_MS_PERFCTR1 0x305 |
| 136 | #define MSR_P4_MS_PERFCTR2 0x306 | 151 | #define MSR_P4_MS_PERFCTR2 0x306 |
| 137 | #define MSR_P4_MS_PERFCTR3 0x307 | 152 | #define MSR_P4_MS_PERFCTR3 0x307 |
| 138 | #define MSR_P4_FLAME_PERFCTR0 0x308 | 153 | #define MSR_P4_FLAME_PERFCTR0 0x308 |
| 139 | #define MSR_P4_FLAME_PERFCTR1 0x309 | 154 | #define MSR_P4_FLAME_PERFCTR1 0x309 |
| 140 | #define MSR_P4_FLAME_PERFCTR2 0x30a | 155 | #define MSR_P4_FLAME_PERFCTR2 0x30a |
| 141 | #define MSR_P4_FLAME_PERFCTR3 0x30b | 156 | #define MSR_P4_FLAME_PERFCTR3 0x30b |
| 142 | #define MSR_P4_IQ_PERFCTR0 0x30c | 157 | #define MSR_P4_IQ_PERFCTR0 0x30c |
| 143 | #define MSR_P4_IQ_PERFCTR1 0x30d | 158 | #define MSR_P4_IQ_PERFCTR1 0x30d |
| 144 | #define MSR_P4_IQ_PERFCTR2 0x30e | 159 | #define MSR_P4_IQ_PERFCTR2 0x30e |
| 145 | #define MSR_P4_IQ_PERFCTR3 0x30f | 160 | #define MSR_P4_IQ_PERFCTR3 0x30f |
| 146 | #define MSR_P4_IQ_PERFCTR4 0x310 | 161 | #define MSR_P4_IQ_PERFCTR4 0x310 |
| 147 | #define MSR_P4_IQ_PERFCTR5 0x311 | 162 | #define MSR_P4_IQ_PERFCTR5 0x311 |
| 148 | #define MSR_P4_BPU_CCCR0 0x360 | 163 | #define MSR_P4_BPU_CCCR0 0x360 |
| 149 | #define MSR_P4_BPU_CCCR1 0x361 | 164 | #define MSR_P4_BPU_CCCR1 0x361 |
| 150 | #define MSR_P4_BPU_CCCR2 0x362 | 165 | #define MSR_P4_BPU_CCCR2 0x362 |
| 151 | #define MSR_P4_BPU_CCCR3 0x363 | 166 | #define MSR_P4_BPU_CCCR3 0x363 |
| 152 | #define MSR_P4_MS_CCCR0 0x364 | 167 | #define MSR_P4_MS_CCCR0 0x364 |
| 153 | #define MSR_P4_MS_CCCR1 0x365 | 168 | #define MSR_P4_MS_CCCR1 0x365 |
| 154 | #define MSR_P4_MS_CCCR2 0x366 | 169 | #define MSR_P4_MS_CCCR2 0x366 |
| 155 | #define MSR_P4_MS_CCCR3 0x367 | 170 | #define MSR_P4_MS_CCCR3 0x367 |
| 156 | #define MSR_P4_FLAME_CCCR0 0x368 | 171 | #define MSR_P4_FLAME_CCCR0 0x368 |
| 157 | #define MSR_P4_FLAME_CCCR1 0x369 | 172 | #define MSR_P4_FLAME_CCCR1 0x369 |
| 158 | #define MSR_P4_FLAME_CCCR2 0x36a | 173 | #define MSR_P4_FLAME_CCCR2 0x36a |
| 159 | #define MSR_P4_FLAME_CCCR3 0x36b | 174 | #define MSR_P4_FLAME_CCCR3 0x36b |
| 160 | #define MSR_P4_IQ_CCCR0 0x36c | 175 | #define MSR_P4_IQ_CCCR0 0x36c |
| 161 | #define MSR_P4_IQ_CCCR1 0x36d | 176 | #define MSR_P4_IQ_CCCR1 0x36d |
| 162 | #define MSR_P4_IQ_CCCR2 0x36e | 177 | #define MSR_P4_IQ_CCCR2 0x36e |
| 163 | #define MSR_P4_IQ_CCCR3 0x36f | 178 | #define MSR_P4_IQ_CCCR3 0x36f |
| 164 | #define MSR_P4_IQ_CCCR4 0x370 | 179 | #define MSR_P4_IQ_CCCR4 0x370 |
| 165 | #define MSR_P4_IQ_CCCR5 0x371 | 180 | #define MSR_P4_IQ_CCCR5 0x371 |
| 166 | #define MSR_P4_ALF_ESCR0 0x3ca | 181 | #define MSR_P4_ALF_ESCR0 0x3ca |
| 167 | #define MSR_P4_ALF_ESCR1 0x3cb | 182 | #define MSR_P4_ALF_ESCR1 0x3cb |
| 168 | #define MSR_P4_BPU_ESCR0 0x3b2 | 183 | #define MSR_P4_BPU_ESCR0 0x3b2 |
| 169 | #define MSR_P4_BPU_ESCR1 0x3b3 | 184 | #define MSR_P4_BPU_ESCR1 0x3b3 |
| 170 | #define MSR_P4_BSU_ESCR0 0x3a0 | 185 | #define MSR_P4_BSU_ESCR0 0x3a0 |
| 171 | #define MSR_P4_BSU_ESCR1 0x3a1 | 186 | #define MSR_P4_BSU_ESCR1 0x3a1 |
| 172 | #define MSR_P4_CRU_ESCR0 0x3b8 | 187 | #define MSR_P4_CRU_ESCR0 0x3b8 |
| 173 | #define MSR_P4_CRU_ESCR1 0x3b9 | 188 | #define MSR_P4_CRU_ESCR1 0x3b9 |
| 174 | #define MSR_P4_CRU_ESCR2 0x3cc | 189 | #define MSR_P4_CRU_ESCR2 0x3cc |
| 175 | #define MSR_P4_CRU_ESCR3 0x3cd | 190 | #define MSR_P4_CRU_ESCR3 0x3cd |
| 176 | #define MSR_P4_CRU_ESCR4 0x3e0 | 191 | #define MSR_P4_CRU_ESCR4 0x3e0 |
| 177 | #define MSR_P4_CRU_ESCR5 0x3e1 | 192 | #define MSR_P4_CRU_ESCR5 0x3e1 |
| 178 | #define MSR_P4_DAC_ESCR0 0x3a8 | 193 | #define MSR_P4_DAC_ESCR0 0x3a8 |
| 179 | #define MSR_P4_DAC_ESCR1 0x3a9 | 194 | #define MSR_P4_DAC_ESCR1 0x3a9 |
| 180 | #define MSR_P4_FIRM_ESCR0 0x3a4 | 195 | #define MSR_P4_FIRM_ESCR0 0x3a4 |
| 181 | #define MSR_P4_FIRM_ESCR1 0x3a5 | 196 | #define MSR_P4_FIRM_ESCR1 0x3a5 |
| 182 | #define MSR_P4_FLAME_ESCR0 0x3a6 | 197 | #define MSR_P4_FLAME_ESCR0 0x3a6 |
| 183 | #define MSR_P4_FLAME_ESCR1 0x3a7 | 198 | #define MSR_P4_FLAME_ESCR1 0x3a7 |
| 184 | #define MSR_P4_FSB_ESCR0 0x3a2 | 199 | #define MSR_P4_FSB_ESCR0 0x3a2 |
| 185 | #define MSR_P4_FSB_ESCR1 0x3a3 | 200 | #define MSR_P4_FSB_ESCR1 0x3a3 |
| 186 | #define MSR_P4_IQ_ESCR0 0x3ba | 201 | #define MSR_P4_IQ_ESCR0 0x3ba |
| 187 | #define MSR_P4_IQ_ESCR1 0x3bb | 202 | #define MSR_P4_IQ_ESCR1 0x3bb |
| 188 | #define MSR_P4_IS_ESCR0 0x3b4 | 203 | #define MSR_P4_IS_ESCR0 0x3b4 |
| 189 | #define MSR_P4_IS_ESCR1 0x3b5 | 204 | #define MSR_P4_IS_ESCR1 0x3b5 |
| 190 | #define MSR_P4_ITLB_ESCR0 0x3b6 | 205 | #define MSR_P4_ITLB_ESCR0 0x3b6 |
| 191 | #define MSR_P4_ITLB_ESCR1 0x3b7 | 206 | #define MSR_P4_ITLB_ESCR1 0x3b7 |
| 192 | #define MSR_P4_IX_ESCR0 0x3c8 | 207 | #define MSR_P4_IX_ESCR0 0x3c8 |
| 193 | #define MSR_P4_IX_ESCR1 0x3c9 | 208 | #define MSR_P4_IX_ESCR1 0x3c9 |
| 194 | #define MSR_P4_MOB_ESCR0 0x3aa | 209 | #define MSR_P4_MOB_ESCR0 0x3aa |
| 195 | #define MSR_P4_MOB_ESCR1 0x3ab | 210 | #define MSR_P4_MOB_ESCR1 0x3ab |
| 196 | #define MSR_P4_MS_ESCR0 0x3c0 | 211 | #define MSR_P4_MS_ESCR0 0x3c0 |
| 197 | #define MSR_P4_MS_ESCR1 0x3c1 | 212 | #define MSR_P4_MS_ESCR1 0x3c1 |
| 198 | #define MSR_P4_PMH_ESCR0 0x3ac | 213 | #define MSR_P4_PMH_ESCR0 0x3ac |
| 199 | #define MSR_P4_PMH_ESCR1 0x3ad | 214 | #define MSR_P4_PMH_ESCR1 0x3ad |
| 200 | #define MSR_P4_RAT_ESCR0 0x3bc | 215 | #define MSR_P4_RAT_ESCR0 0x3bc |
| 201 | #define MSR_P4_RAT_ESCR1 0x3bd | 216 | #define MSR_P4_RAT_ESCR1 0x3bd |
| 202 | #define MSR_P4_SAAT_ESCR0 0x3ae | 217 | #define MSR_P4_SAAT_ESCR0 0x3ae |
| 203 | #define MSR_P4_SAAT_ESCR1 0x3af | 218 | #define MSR_P4_SAAT_ESCR1 0x3af |
| 204 | #define MSR_P4_SSU_ESCR0 0x3be | 219 | #define MSR_P4_SSU_ESCR0 0x3be |
| 205 | #define MSR_P4_SSU_ESCR1 0x3bf /* guess: not defined in manual */ | 220 | #define MSR_P4_SSU_ESCR1 0x3bf /* guess: not defined in manual */ |
| 206 | #define MSR_P4_TBPU_ESCR0 0x3c2 | 221 | #define MSR_P4_TBPU_ESCR0 0x3c2 |
| 207 | #define MSR_P4_TBPU_ESCR1 0x3c3 | 222 | #define MSR_P4_TBPU_ESCR1 0x3c3 |
| 208 | #define MSR_P4_TC_ESCR0 0x3c4 | 223 | #define MSR_P4_TC_ESCR0 0x3c4 |
| 209 | #define MSR_P4_TC_ESCR1 0x3c5 | 224 | #define MSR_P4_TC_ESCR1 0x3c5 |
| 210 | #define MSR_P4_U2L_ESCR0 0x3b0 | 225 | #define MSR_P4_U2L_ESCR0 0x3b0 |
| 211 | #define MSR_P4_U2L_ESCR1 0x3b1 | 226 | #define MSR_P4_U2L_ESCR1 0x3b1 |
| 212 | 227 | ||
| 213 | /* AMD Defined MSRs */ | 228 | /* AMD Defined MSRs */ |
| 214 | #define MSR_K6_EFER 0xC0000080 | 229 | #define MSR_K6_EFER 0xC0000080 |
| 215 | #define MSR_K6_STAR 0xC0000081 | 230 | #define MSR_K6_STAR 0xC0000081 |
| 216 | #define MSR_K6_WHCR 0xC0000082 | 231 | #define MSR_K6_WHCR 0xC0000082 |
| 217 | #define MSR_K6_UWCCR 0xC0000085 | 232 | #define MSR_K6_UWCCR 0xC0000085 |
| 218 | #define MSR_K6_EPMR 0xC0000086 | 233 | #define MSR_K6_EPMR 0xC0000086 |
| 219 | #define MSR_K6_PSOR 0xC0000087 | 234 | #define MSR_K6_PSOR 0xC0000087 |
| 220 | #define MSR_K6_PFIR 0xC0000088 | 235 | #define MSR_K6_PFIR 0xC0000088 |
| 221 | 236 | ||
| 222 | #define MSR_K7_EVNTSEL0 0xC0010000 | 237 | #define MSR_K7_EVNTSEL0 0xC0010000 |
| 223 | #define MSR_K7_EVNTSEL1 0xC0010001 | 238 | #define MSR_K7_EVNTSEL1 0xC0010001 |
| 224 | #define MSR_K7_EVNTSEL2 0xC0010002 | 239 | #define MSR_K7_EVNTSEL2 0xC0010002 |
| 225 | #define MSR_K7_EVNTSEL3 0xC0010003 | 240 | #define MSR_K7_EVNTSEL3 0xC0010003 |
| 226 | #define MSR_K7_PERFCTR0 0xC0010004 | 241 | #define MSR_K7_PERFCTR0 0xC0010004 |
| 227 | #define MSR_K7_PERFCTR1 0xC0010005 | 242 | #define MSR_K7_PERFCTR1 0xC0010005 |
| 228 | #define MSR_K7_PERFCTR2 0xC0010006 | 243 | #define MSR_K7_PERFCTR2 0xC0010006 |
| 229 | #define MSR_K7_PERFCTR3 0xC0010007 | 244 | #define MSR_K7_PERFCTR3 0xC0010007 |
| 230 | #define MSR_K7_HWCR 0xC0010015 | 245 | #define MSR_K7_HWCR 0xC0010015 |
| 231 | #define MSR_K7_CLK_CTL 0xC001001b | 246 | #define MSR_K7_CLK_CTL 0xC001001b |
| 232 | #define MSR_K7_FID_VID_CTL 0xC0010041 | 247 | #define MSR_K7_FID_VID_CTL 0xC0010041 |
| 233 | #define MSR_K7_FID_VID_STATUS 0xC0010042 | 248 | #define MSR_K7_FID_VID_STATUS 0xC0010042 |
| 234 | 249 | ||
| 235 | /* extended feature register */ | 250 | /* extended feature register */ |
| 236 | #define MSR_EFER 0xc0000080 | 251 | #define MSR_EFER 0xc0000080 |
| 237 | 252 | ||
| 238 | /* EFER bits: */ | 253 | /* EFER bits: */ |
| 239 | 254 | ||
| 240 | /* Execute Disable enable */ | 255 | /* Execute Disable enable */ |
| 241 | #define _EFER_NX 11 | 256 | #define _EFER_NX 11 |
| 242 | #define EFER_NX (1<<_EFER_NX) | 257 | #define EFER_NX (1<<_EFER_NX) |
| 243 | 258 | ||
| 244 | /* Centaur-Hauls/IDT defined MSRs. */ | 259 | /* Centaur-Hauls/IDT defined MSRs. */ |
| 245 | #define MSR_IDT_FCR1 0x107 | 260 | #define MSR_IDT_FCR1 0x107 |
| 246 | #define MSR_IDT_FCR2 0x108 | 261 | #define MSR_IDT_FCR2 0x108 |
| 247 | #define MSR_IDT_FCR3 0x109 | 262 | #define MSR_IDT_FCR3 0x109 |
| 248 | #define MSR_IDT_FCR4 0x10a | 263 | #define MSR_IDT_FCR4 0x10a |
| 249 | 264 | ||
| 250 | #define MSR_IDT_MCR0 0x110 | 265 | #define MSR_IDT_MCR0 0x110 |
| 251 | #define MSR_IDT_MCR1 0x111 | 266 | #define MSR_IDT_MCR1 0x111 |
| 252 | #define MSR_IDT_MCR2 0x112 | 267 | #define MSR_IDT_MCR2 0x112 |
| 253 | #define MSR_IDT_MCR3 0x113 | 268 | #define MSR_IDT_MCR3 0x113 |
| 254 | #define MSR_IDT_MCR4 0x114 | 269 | #define MSR_IDT_MCR4 0x114 |
| 255 | #define MSR_IDT_MCR5 0x115 | 270 | #define MSR_IDT_MCR5 0x115 |
| 256 | #define MSR_IDT_MCR6 0x116 | 271 | #define MSR_IDT_MCR6 0x116 |
| 257 | #define MSR_IDT_MCR7 0x117 | 272 | #define MSR_IDT_MCR7 0x117 |
| 258 | #define MSR_IDT_MCR_CTRL 0x120 | 273 | #define MSR_IDT_MCR_CTRL 0x120 |
| 259 | 274 | ||
| 260 | /* VIA Cyrix defined MSRs*/ | 275 | /* VIA Cyrix defined MSRs*/ |
| 261 | #define MSR_VIA_FCR 0x1107 | 276 | #define MSR_VIA_FCR 0x1107 |
| 262 | #define MSR_VIA_LONGHAUL 0x110a | 277 | #define MSR_VIA_LONGHAUL 0x110a |
| 263 | #define MSR_VIA_RNG 0x110b | 278 | #define MSR_VIA_RNG 0x110b |
| 264 | #define MSR_VIA_BCR2 0x1147 | 279 | #define MSR_VIA_BCR2 0x1147 |
| 265 | 280 | ||
| 266 | /* Transmeta defined MSRs */ | 281 | /* Transmeta defined MSRs */ |
| 267 | #define MSR_TMTA_LONGRUN_CTRL 0x80868010 | 282 | #define MSR_TMTA_LONGRUN_CTRL 0x80868010 |
| 268 | #define MSR_TMTA_LONGRUN_FLAGS 0x80868011 | 283 | #define MSR_TMTA_LONGRUN_FLAGS 0x80868011 |
| 269 | #define MSR_TMTA_LRTI_READOUT 0x80868018 | 284 | #define MSR_TMTA_LRTI_READOUT 0x80868018 |
| 270 | #define MSR_TMTA_LRTI_VOLT_MHZ 0x8086801a | 285 | #define MSR_TMTA_LRTI_VOLT_MHZ 0x8086801a |
| 271 | 286 | ||
| 272 | #endif /* __ASM_MSR_H */ | 287 | #endif /* __ASM_MSR_H */ |
| 273 | 288 |