Upstream | cc2ee17 | 1970-01-12 13:46:40 +0000 | [diff] [blame^] | 1 | /** |
| 2 | * @file op_apic.c |
| 3 | * |
| 4 | * APIC setup etc. routines |
| 5 | * |
| 6 | * @remark Copyright 2002 OProfile authors |
| 7 | * @remark Read the file COPYING |
| 8 | * |
| 9 | * @author John Levon |
| 10 | * @author Philippe Elie |
| 11 | * @author Dave Jones |
| 12 | * @author Graydon Hoare |
| 13 | */ |
| 14 | |
| 15 | #include <linux/mm.h> |
| 16 | #include <linux/init.h> |
| 17 | #include <linux/config.h> |
| 18 | #include <asm/io.h> |
| 19 | |
| 20 | #include "oprofile.h" |
| 21 | #include "op_msr.h" |
| 22 | #include "op_apic.h" |
| 23 | |
| 24 | /* used to save/restore original kernel nmi */ |
| 25 | static struct gate_struct kernel_nmi; |
| 26 | static ulong lvtpc_masked; |
| 27 | |
| 28 | /* this masking code is unsafe and nasty but might deal with the small |
| 29 | * race when installing the NMI entry into the IDT. |
| 30 | */ |
| 31 | static void mask_lvtpc(void * e) |
| 32 | { |
| 33 | u32 v = apic_read(APIC_LVTPC); |
| 34 | lvtpc_masked = v & APIC_LVT_MASKED; |
| 35 | apic_write(APIC_LVTPC, v | APIC_LVT_MASKED); |
| 36 | } |
| 37 | |
| 38 | static void unmask_lvtpc(void * e) |
| 39 | { |
| 40 | if (!lvtpc_masked) |
| 41 | apic_write(APIC_LVTPC, apic_read(APIC_LVTPC) & ~APIC_LVT_MASKED); |
| 42 | } |
| 43 | |
| 44 | |
| 45 | void install_nmi(void) |
| 46 | { |
| 47 | struct _descr descr; |
| 48 | |
| 49 | /* NMI handler is at idt_table[IDT_VECTOR_NUMBER] */ |
| 50 | /* see Intel Vol.3 Figure 5-2, interrupt gate */ |
| 51 | |
| 52 | smp_call_function(mask_lvtpc, NULL, 0, 1); |
| 53 | mask_lvtpc(NULL); |
| 54 | |
| 55 | store_idt(descr); |
| 56 | kernel_nmi = descr.base[NMI_VECTOR_NUM]; |
| 57 | SET_NMI_GATE; |
| 58 | |
| 59 | smp_call_function(unmask_lvtpc, NULL, 0, 1); |
| 60 | unmask_lvtpc(NULL); |
| 61 | } |
| 62 | |
| 63 | void restore_nmi(void) |
| 64 | { |
| 65 | struct _descr descr; |
| 66 | |
| 67 | smp_call_function(mask_lvtpc, NULL, 0, 1); |
| 68 | mask_lvtpc(NULL); |
| 69 | |
| 70 | store_idt(descr); |
| 71 | descr.base[NMI_VECTOR_NUM] = kernel_nmi; |
| 72 | |
| 73 | smp_call_function(unmask_lvtpc, NULL, 0, 1); |
| 74 | unmask_lvtpc(NULL); |
| 75 | } |
| 76 | |
| 77 | |
| 78 | /* ---------------- APIC setup ------------------ */ |
| 79 | static uint saved_lvtpc[NR_CPUS]; |
| 80 | |
| 81 | void __init lvtpc_apic_setup(void * dummy) |
| 82 | { |
| 83 | uint val; |
| 84 | |
| 85 | /* set up LVTPC as we need it */ |
| 86 | /* IA32 V3, Figure 7.8 */ |
| 87 | val = apic_read(APIC_LVTPC); |
| 88 | saved_lvtpc[op_cpu_id()] = val; |
| 89 | /* allow PC overflow interrupts */ |
| 90 | val &= ~APIC_LVT_MASKED; |
| 91 | /* set delivery to NMI */ |
| 92 | val = SET_APIC_DELIVERY_MODE(val, APIC_MODE_NMI); |
| 93 | apic_write(APIC_LVTPC, val); |
| 94 | } |
| 95 | |
| 96 | /* not safe to mark as __exit since used from __init code */ |
| 97 | void lvtpc_apic_restore(void * dummy) |
| 98 | { |
| 99 | /* restoring APIC_LVTPC can trigger an apic error because the delivery |
| 100 | * mode and vector nr combination can be illegal. That's by design: on |
| 101 | * power on apic lvt contain a zero vector nr which are legal only for |
| 102 | * NMI delivrey mode. So inhibit apic err before restoring lvtpc |
| 103 | */ |
| 104 | uint v = apic_read(APIC_LVTERR); |
| 105 | apic_write(APIC_LVTERR, v | APIC_LVT_MASKED); |
| 106 | apic_write(APIC_LVTPC, saved_lvtpc[op_cpu_id()]); |
| 107 | apic_write(APIC_LVTERR, v); |
| 108 | } |
| 109 | |
| 110 | static int __init enable_apic(void) |
| 111 | { |
| 112 | uint msr_low, msr_high; |
| 113 | uint val; |
| 114 | |
| 115 | /* enable local APIC via MSR. Forgetting this is a fun way to |
| 116 | * lock the box. But we have to hope this is allowed if the APIC |
| 117 | * has already been enabled. |
| 118 | * |
| 119 | * IA32 V3, 7.4.2 */ |
| 120 | rdmsr(MSR_IA32_APICBASE, msr_low, msr_high); |
| 121 | if ((msr_low & (1 << 11)) == 0) |
| 122 | wrmsr(MSR_IA32_APICBASE, msr_low | (1<<11), msr_high); |
| 123 | |
| 124 | /* even if the apic is up we must check for a good APIC */ |
| 125 | |
| 126 | /* IA32 V3, 7.4.15 */ |
| 127 | val = apic_read(APIC_LVR); |
| 128 | if (!APIC_INTEGRATED(GET_APIC_VERSION(val))) |
| 129 | goto not_local_apic; |
| 130 | |
| 131 | /* LVT0,LVT1,LVTT,LVTPC */ |
| 132 | if (GET_APIC_MAXLVT(apic_read(APIC_LVR)) < 4) |
| 133 | goto not_local_apic; |
| 134 | |
| 135 | /* IA32 V3, 7.4.14.1 */ |
| 136 | val = apic_read(APIC_SPIV); |
| 137 | if (!(val & APIC_SPIV_APIC_ENABLED)) |
| 138 | apic_write(APIC_SPIV, val | APIC_SPIV_APIC_ENABLED); |
| 139 | |
| 140 | return !!(val & APIC_SPIV_APIC_ENABLED); |
| 141 | |
| 142 | not_local_apic: |
| 143 | /* disable the apic only if it was disabled */ |
| 144 | if ((msr_low & (1 << 11)) == 0) |
| 145 | wrmsr(MSR_IA32_APICBASE, msr_low & ~(1<<11), msr_high); |
| 146 | |
| 147 | printk(KERN_ERR "oprofile: no suitable local APIC. Falling back to RTC mode.\n"); |
| 148 | return -ENODEV; |
| 149 | } |
| 150 | |
| 151 | static void __init do_apic_setup(void) |
| 152 | { |
| 153 | uint val; |
| 154 | |
| 155 | local_irq_disable(); |
| 156 | |
| 157 | val = APIC_LVT_LEVEL_TRIGGER; |
| 158 | val = SET_APIC_DELIVERY_MODE(val, APIC_MODE_EXINT); |
| 159 | apic_write(APIC_LVT0, val); |
| 160 | |
| 161 | /* edge triggered, IA 7.4.11 */ |
| 162 | val = SET_APIC_DELIVERY_MODE(0, APIC_MODE_NMI); |
| 163 | apic_write(APIC_LVT1, val); |
| 164 | |
| 165 | /* clear error register */ |
| 166 | /* IA32 V3, 7.4.17 */ |
| 167 | /* PHE must be cleared after unmasking by a back-to-back write, |
| 168 | * but it is probably ok because we mask only, the ESR is not |
| 169 | * updated is this a real problem ? */ |
| 170 | apic_write(APIC_ESR, 0); |
| 171 | |
| 172 | /* mask error interrupt */ |
| 173 | /* IA32 V3, Figure 7.8 */ |
| 174 | val = apic_read(APIC_LVTERR); |
| 175 | val |= APIC_LVT_MASKED; |
| 176 | apic_write(APIC_LVTERR, val); |
| 177 | |
| 178 | /* setup timer vector */ |
| 179 | /* IA32 V3, 7.4.8 */ |
| 180 | apic_write(APIC_LVTT, APIC_SEND_PENDING | 0x31); |
| 181 | |
| 182 | /* Divide configuration register */ |
| 183 | /* PHE the apic clock is based on the FSB. This should only |
| 184 | * changed with a calibration method. */ |
| 185 | val = APIC_TDR_DIV_1; |
| 186 | apic_write(APIC_TDCR, val); |
| 187 | |
| 188 | local_irq_enable(); |
| 189 | } |
| 190 | |
| 191 | /* does the CPU have a local APIC ? */ |
| 192 | static int __init check_cpu_ok(void) |
| 193 | { |
| 194 | if (sysctl.cpu_type != CPU_PPRO && |
| 195 | sysctl.cpu_type != CPU_PII && |
| 196 | sysctl.cpu_type != CPU_PIII && |
| 197 | sysctl.cpu_type != CPU_ATHLON && |
| 198 | sysctl.cpu_type != CPU_HAMMER && |
| 199 | sysctl.cpu_type != CPU_P4 && |
| 200 | sysctl.cpu_type != CPU_P4_HT2) |
| 201 | return 0; |
| 202 | |
| 203 | return 1; |
| 204 | } |
| 205 | |
| 206 | int __init apic_setup(void) |
| 207 | { |
| 208 | u32 val; |
| 209 | |
| 210 | if (!check_cpu_ok()) |
| 211 | goto nodev; |
| 212 | |
| 213 | fixmap_setup(); |
| 214 | |
| 215 | switch (enable_apic()) { |
| 216 | case 0: |
| 217 | do_apic_setup(); |
| 218 | val = apic_read(APIC_ESR); |
| 219 | printk(KERN_INFO "oprofile: enabled local APIC. Err code %.08x\n", val); |
| 220 | break; |
| 221 | case 1: |
| 222 | printk(KERN_INFO "oprofile: APIC was already enabled\n"); |
| 223 | break; |
| 224 | default: |
| 225 | goto nodev; |
| 226 | } |
| 227 | |
| 228 | lvtpc_apic_setup(NULL); |
| 229 | return 0; |
| 230 | nodev: |
| 231 | printk(KERN_WARNING "Your CPU does not have a local APIC, e.g. " |
| 232 | "mobile P6. Falling back to RTC mode.\n"); |
| 233 | return -ENODEV; |
| 234 | } |
| 235 | |
| 236 | void apic_restore(void) |
| 237 | { |
| 238 | fixmap_restore(); |
| 239 | } |