static int __init enable_apic(void) { uint msr_low, msr_high; uint val; /* enable local APIC via MSR. Forgetting this is a fun way to * lock the box. But we have to hope this is allowed if the APIC * has already been enabled. * * IA32 V3, 7.4.2 */ rdmsr(MSR_IA32_APICBASE, msr_low, msr_high); if ((msr_low & (1 << 11)) == 0) wrmsr(MSR_IA32_APICBASE, msr_low | (1<<11), msr_high); /* even if the apic is up we must check for a good APIC */ /* IA32 V3, 7.4.15 */ val = apic_read(APIC_LVR); if (!APIC_INTEGRATED(GET_APIC_VERSION(val))) goto not_local_apic; /* LVT0,LVT1,LVTT,LVTPC */ if (GET_APIC_MAXLVT(apic_read(APIC_LVR)) < 4) goto not_local_apic; /* IA32 V3, 7.4.14.1 */ val = apic_read(APIC_SPIV); if (!(val & APIC_SPIV_APIC_ENABLED)) apic_write(APIC_SPIV, val | APIC_SPIV_APIC_ENABLED); return !!(val & APIC_SPIV_APIC_ENABLED); not_local_apic: /* disable the apic only if it was disabled */ if ((msr_low & (1 << 11)) == 0) wrmsr(MSR_IA32_APICBASE, msr_low & ~(1<<11), msr_high); printk(KERN_ERR "oprofile: no suitable local APIC. Falling back to RTC mode.\n"); return -ENODEV; }
static int __init calibrate_APIC_clock(void) { unsigned apic, apic_start; unsigned long tsc, tsc_start; int result; /* * Put whatever arbitrary (but long enough) timeout * value into the APIC clock, we just want to get the * counter running for calibration. */ __setup_APIC_LVTT(4000000000); apic_start = apic_read(APIC_TMCCT); #ifdef CONFIG_X86_PM_TIMER if (apic_calibrate_pmtmr && pmtmr_ioport) { pmtimer_wait(5000); /* 5ms wait */ apic = apic_read(APIC_TMCCT); result = (apic_start - apic) * 1000L / 5; } else #endif { rdtscll(tsc_start); do { apic = apic_read(APIC_TMCCT); rdtscll(tsc); } while ((tsc - tsc_start) < TICK_COUNT && (apic_start - apic) < TICK_COUNT); result = (apic_start - apic) * 1000L * tsc_khz / (tsc - tsc_start); } printk("result %d\n", result); printk(KERN_INFO "Detected %d.%03d MHz APIC timer.\n", result / 1000 / 1000, result / 1000 % 1000); return result * APIC_DIVISOR / HZ; }
static void apic_pm_resume(void *data) { unsigned int l, h; unsigned long flags; __save_flags(flags); __cli(); /* * Make sure the APICBASE points to the right address * * FIXME! This will be wrong if we ever support suspend on * SMP! We'll need to do this as part of the CPU restore! */ rdmsr(MSR_IA32_APICBASE, l, h); l &= ~MSR_IA32_APICBASE_BASE; l |= MSR_IA32_APICBASE_ENABLE | mp_lapic_addr; wrmsr(MSR_IA32_APICBASE, l, h); apic_write(APIC_LVTERR, ERROR_APIC_VECTOR | APIC_LVT_MASKED); apic_write(APIC_ID, apic_pm_state.apic_id); apic_write(APIC_DFR, apic_pm_state.apic_dfr); apic_write(APIC_LDR, apic_pm_state.apic_ldr); apic_write(APIC_TASKPRI, apic_pm_state.apic_taskpri); apic_write(APIC_SPIV, apic_pm_state.apic_spiv); apic_write(APIC_LVT0, apic_pm_state.apic_lvt0); apic_write(APIC_LVT1, apic_pm_state.apic_lvt1); apic_write(APIC_LVTPC, apic_pm_state.apic_lvtpc); apic_write(APIC_LVTT, apic_pm_state.apic_lvtt); apic_write(APIC_TDCR, apic_pm_state.apic_tdcr); apic_write(APIC_TMICT, apic_pm_state.apic_tmict); apic_write(APIC_ESR, 0); apic_read(APIC_ESR); apic_write(APIC_LVTERR, apic_pm_state.apic_lvterr); apic_write(APIC_ESR, 0); apic_read(APIC_ESR); __restore_flags(flags); if (apic_pm_state.perfctr_pmdev) pm_send(apic_pm_state.perfctr_pmdev, PM_RESUME, data); }
static int p4_check_ctrs(unsigned int const cpu, struct op_msrs const * const msrs, struct pt_regs * const regs) { unsigned long ctr, low, high, stag, real; int i; unsigned long eip = profile_pc(regs); int is_kernel = !user_mode(regs); stag = get_stagger(); for (i = 0; i < num_counters; ++i) { if (!reset_value[i]) continue; /* * there is some eccentricity in the hardware which * requires that we perform 2 extra corrections: * * - check both the CCCR:OVF flag for overflow and the * counter high bit for un-flagged overflows. * * - write the counter back twice to ensure it gets * updated properly. * * the former seems to be related to extra NMIs happening * during the current NMI; the latter is reported as errata * N15 in intel doc 249199-029, pentium 4 specification * update, though their suggested work-around does not * appear to solve the problem. */ real = VIRT_CTR(stag, i); CCCR_READ(low, high, real); CTR_READ(ctr, high, real); if (CCCR_OVF_P(low) || CTR_OVERFLOW_P(ctr)) { oprofile_add_sample(eip, is_kernel, i, cpu); CTR_WRITE(reset_value[i], real); CCCR_CLEAR_OVF(low); CCCR_WRITE(low, high, real); CTR_WRITE(reset_value[i], real); } } /* P4 quirk: you have to re-unmask the apic vector */ apic_write(APIC_LVTPC, apic_read(APIC_LVTPC) & ~APIC_LVT_MASKED); /* See op_model_ppro.c */ return 1; }
void __init init_apic_mappings(void) { unsigned long apic_phys; /* * If no local APIC can be found then set up a fake all * zeroes page to simulate the local APIC and another * one for the IO-APIC. */ if (!smp_found_config && detect_init_APIC()) { apic_phys = (unsigned long) alloc_bootmem_pages(PAGE_SIZE); apic_phys = __pa(apic_phys); } else apic_phys = mp_lapic_addr; set_fixmap_nocache(FIX_APIC_BASE, apic_phys); Dprintk("mapped APIC to %08lx (%08lx)\n", APIC_BASE, apic_phys); /* * Fetch the APIC ID of the BSP in case we have a * default configuration (or the MP table is broken). */ if (boot_cpu_id == -1U) boot_cpu_id = GET_APIC_ID(apic_read(APIC_ID)); #ifdef CONFIG_X86_IO_APIC { unsigned long ioapic_phys, idx = FIX_IO_APIC_BASE_0; int i; for (i = 0; i < nr_ioapics; i++) { if (smp_found_config) { ioapic_phys = mp_ioapics[i].mpc_apicaddr; if (!ioapic_phys) { printk(KERN_ERR "WARNING: bogus zero IO-APIC address found in MPTABLE, disabling IO-APIC support\n"); smp_found_config = 0; skip_ioapic_setup = 1; goto fake_ioapic_page; } } else { fake_ioapic_page: ioapic_phys = (unsigned long) alloc_bootmem_pages(PAGE_SIZE); ioapic_phys = __pa(ioapic_phys); } set_fixmap_nocache(idx, ioapic_phys); Dprintk("mapped IOAPIC to %08lx (%08lx)\n", __fix_to_virt(idx), ioapic_phys); idx++; } } #endif }
static void nmi_cpu_setup(void) { int cpu = smp_processor_id(); struct op_msrs *msrs = &per_cpu(cpu_msrs, cpu); nmi_cpu_save_registers(msrs); raw_spin_lock(&oprofilefs_lock); model->setup_ctrs(model, msrs); nmi_cpu_setup_mux(cpu, msrs); raw_spin_unlock(&oprofilefs_lock); per_cpu(saved_lvtpc, cpu) = apic_read(APIC_LVTPC); apic_write(APIC_LVTPC, APIC_DM_NMI); }
static __init void cobalt_init(void) { /* * On normal SMP PC this is used only with SMP, but we have to * use it and set it up here to start the Cobalt clock */ set_fixmap(FIX_APIC_BASE, APIC_DEFAULT_PHYS_BASE); setup_local_APIC(); printk(KERN_INFO "Local APIC Version %#lx, ID %#lx\n", apic_read(APIC_LVR), apic_read(APIC_ID)); set_fixmap(FIX_CO_CPU, CO_CPU_PHYS); set_fixmap(FIX_CO_APIC, CO_APIC_PHYS); printk(KERN_INFO "Cobalt Revision %#lx, APIC ID %#lx\n", co_cpu_read(CO_CPU_REV), co_apic_read(CO_APIC_ID)); /* Enable Cobalt APIC being careful to NOT change the ID! */ co_apic_write(CO_APIC_ID, co_apic_read(CO_APIC_ID) | CO_APIC_ENABLE); printk(KERN_INFO "Cobalt APIC enabled: ID reg %#lx\n", co_apic_read(CO_APIC_ID)); }
int arch_smp_set_apic_timer(bigtime_t relative_timeout, int type) { unsigned int config; unsigned int ticks; if(apic == NULL) return -1; if(relative_timeout < MIN_TIMEOUT) relative_timeout = MIN_TIMEOUT; // calculation should be ok, since it's going to be 64-bit ticks = ((relative_timeout * apic_timer_tics_per_sec) / 1000000); int_disable_interrupts(); config = apic_read(APIC_LVTT) | APIC_LVTT_M; // mask the timer apic_write(APIC_LVTT, config); apic_write(APIC_ICRT, 0); // zero out the timer config = apic_read(APIC_LVTT) & ~APIC_LVTT_M; // unmask the timer if(type == HW_TIMER_ONESHOT) config &= ~APIC_LVTT_TM; // clear the periodic bit else config |= APIC_LVTT_TM; // periodic apic_write(APIC_LVTT, config); dprintf("arch_smp_set_apic_timer: config 0x%x, timeout %Ld, tics/sec %d, tics %d\n", config, relative_timeout, apic_timer_tics_per_sec, ticks); apic_write(APIC_ICRT, ticks); // start it up int_restore_interrupts(); return 0; }
void lapic_stop_timer(void) { uint32_t lvt; /* Set the initial count to 0 */ apic_write(APIC_TMICT, 0); /* Disable the local APIC timer */ lvt = apic_read(APIC_LVTT); lvt |= APIC_LVT_MASKED; apic_write(APIC_LVTT, lvt); }
void APIC_error_interrupt(void) // called from "error_apic" { unsigned long v, v1; v = apic_read(APIC_ESR); apic_write(APIC_ESR, 0); v1 = apic_read(APIC_ESR); ack_APIC_irq(); /* Here is what the APIC error bits mean: 0: Send CS error 1: Receive CS error 2: Send accept error 3: Receive accept error 4: Reserved 5: Send illegal vector 6: Received illegal vector 7: Illegal register address */ printf("APIC error: %02lx(%02lx): \"", v, v1); if (v1 & 0x01) printf("Send CS error"); if (v1 & 0x02) printf("Receive CS error"); if (v1 & 0x04) printf("Send accept error"); if (v1 & 0x08) printf("Receive accept error"); if (v1 & 0x10) printf("Reserved"); if (v1 & 0x20) printf("Send illegal vector"); if (v1 & 0x40) printf("Received illegal vector"); if (v1 & 0x80) printf("Illegal register addres"); printf("\" on CPU%d\n", get_processor_id()); sys_panic("APIC error on CPU%d\n", get_processor_id()); }
/* * Set up the logical destination ID. * * Intel recommends to set DFR, LDR and TPR before enabling * an APIC. See e.g. "AP-388 82489DX User's Manual" (Intel * document number 292116). So here it goes... */ static void flat_init_apic_ldr(void) { unsigned long val; unsigned long num, id; num = smp_processor_id(); id = 1UL << num; x86_cpu_to_log_apicid[num] = id; apic_write_around(APIC_DFR, APIC_DFR_FLAT); val = apic_read(APIC_LDR) & ~APIC_LDR_MASK; val |= SET_APIC_LOGICAL_ID(id); apic_write_around(APIC_LDR, val); }
void disconnect_bsp_APIC(int virt_wire_setup) { /* Go back to Virtual Wire compatibility mode */ unsigned long value; /* For the spurious interrupt use vector F, and enable it */ value = apic_read(APIC_SPIV); value &= ~APIC_VECTOR_MASK; value |= APIC_SPIV_APIC_ENABLED; value |= 0xf; apic_write(APIC_SPIV, value); if (!virt_wire_setup) { /* * For LVT0 make it edge triggered, active high, * external and enabled */ value = apic_read(APIC_LVT0); value &= ~(APIC_MODE_MASK | APIC_SEND_PENDING | APIC_INPUT_POLARITY | APIC_LVT_REMOTE_IRR | APIC_LVT_LEVEL_TRIGGER | APIC_LVT_MASKED); value |= APIC_LVT_REMOTE_IRR | APIC_SEND_PENDING; value = SET_APIC_DELIVERY_MODE(value, APIC_MODE_EXTINT); apic_write(APIC_LVT0, value); } else { /* Disable LVT0 */ apic_write(APIC_LVT0, APIC_LVT_MASKED); } /* For LVT1 make it edge triggered, active high, nmi and enabled */ value = apic_read(APIC_LVT1); value &= ~(APIC_MODE_MASK | APIC_SEND_PENDING | APIC_INPUT_POLARITY | APIC_LVT_REMOTE_IRR | APIC_LVT_LEVEL_TRIGGER | APIC_LVT_MASKED); value |= APIC_LVT_REMOTE_IRR | APIC_SEND_PENDING; value = SET_APIC_DELIVERY_MODE(value, APIC_MODE_NMI); apic_write(APIC_LVT1, value); }
/** * clear_local_APIC - shutdown the local APIC * * This is called, when a CPU is disabled and before rebooting, so the state of * the local APIC has no dangling leftovers. Also used to cleanout any BIOS * leftovers during boot. */ void clear_local_APIC(void) { int maxlvt = lapic_get_maxlvt(); unsigned long v; /* * Masking an LVT entry can trigger a local APIC error * if the vector is zero. Mask LVTERR first to prevent this. */ if (maxlvt >= 3) { v = ERROR_APIC_VECTOR; /* any non-zero vector will do */ apic_write_around(APIC_LVTERR, v | APIC_LVT_MASKED); } /* * Careful: we have to set masks only first to deassert * any level-triggered sources. */ v = apic_read(APIC_LVTT); apic_write_around(APIC_LVTT, v | APIC_LVT_MASKED); v = apic_read(APIC_LVT0); apic_write_around(APIC_LVT0, v | APIC_LVT_MASKED); v = apic_read(APIC_LVT1); apic_write_around(APIC_LVT1, v | APIC_LVT_MASKED); if (maxlvt >= 4) { v = apic_read(APIC_LVTPC); apic_write_around(APIC_LVTPC, v | APIC_LVT_MASKED); } /* lets not touch this if we didn't frob it */ #ifdef CONFIG_X86_MCE_P4THERMAL if (maxlvt >= 5) { v = apic_read(APIC_LVTTHMR); apic_write_around(APIC_LVTTHMR, v | APIC_LVT_MASKED); } #endif /* * Clean APIC state for other OSs: */ apic_write_around(APIC_LVTT, APIC_LVT_MASKED); apic_write_around(APIC_LVT0, APIC_LVT_MASKED); apic_write_around(APIC_LVT1, APIC_LVT_MASKED); if (maxlvt >= 3) apic_write_around(APIC_LVTERR, APIC_LVT_MASKED); if (maxlvt >= 4) apic_write_around(APIC_LVTPC, APIC_LVT_MASKED); #ifdef CONFIG_X86_MCE_P4THERMAL if (maxlvt >= 5) apic_write_around(APIC_LVTTHMR, APIC_LVT_MASKED); #endif /* Integrated APIC (!82489DX) ? */ if (lapic_is_integrated()) { if (maxlvt > 3) /* Clear ESR due to Pentium errata 3AP and 11AP */ apic_write(APIC_ESR, 0); apic_read(APIC_ESR); } }
/* * An initial setup of the virtual wire mode. */ void __init init_bsp_APIC(void) { unsigned long value, ver; /* * Don't do the setup now if we have a SMP BIOS as the * through-I/O-APIC virtual wire mode might be active. */ if (smp_found_config || !cpu_has_apic) return; value = apic_read(APIC_LVR); ver = GET_APIC_VERSION(value); /* * Do not trust the local APIC being empty at bootup. */ clear_local_APIC(); /* * Enable APIC. */ value = apic_read(APIC_SPIV); value &= ~APIC_VECTOR_MASK; value |= APIC_SPIV_APIC_ENABLED; value |= APIC_SPIV_FOCUS_DISABLED; value |= SPURIOUS_APIC_VECTOR; apic_write_around(APIC_SPIV, value); /* * Set up the virtual wire mode. */ apic_write_around(APIC_LVT0, APIC_DM_EXTINT); value = APIC_DM_NMI; if (!APIC_INTEGRATED(ver)) /* 82489DX */ value |= APIC_LVT_LEVEL_TRIGGER; apic_write_around(APIC_LVT1, value); }
static void __setup_APIC_LVTT(unsigned int clocks) { unsigned int lvtt_value, tmp_value, ver; int cpu = smp_processor_id(); ver = GET_APIC_VERSION(apic_read(APIC_LVR)); lvtt_value = APIC_LVT_TIMER_PERIODIC | LOCAL_TIMER_VECTOR; if (cpu_isset(cpu, timer_interrupt_broadcast_ipi_mask)) lvtt_value |= APIC_LVT_MASKED; apic_write(APIC_LVTT, lvtt_value); /* * Divide PICLK by 16 */ tmp_value = apic_read(APIC_TDCR); apic_write(APIC_TDCR, (tmp_value & ~(APIC_TDR_DIV_1 | APIC_TDR_DIV_TMBASE)) | APIC_TDR_DIV_16); apic_write(APIC_TMICT, clocks/APIC_DIVISOR); }
static void __setup_APIC_LVTT(unsigned int clocks) { unsigned int lvtt_value, tmp_value, ver; ver = GET_APIC_VERSION(apic_read(APIC_LVR)); /* NB. Xen uses local APIC timer in one-shot mode. */ lvtt_value = /*APIC_TIMER_MODE_PERIODIC |*/ LOCAL_TIMER_VECTOR; if (!APIC_INTEGRATED(ver)) lvtt_value |= SET_APIC_TIMER_BASE(APIC_TIMER_BASE_DIV); if ( tdt_enabled ) { lvtt_value &= (~APIC_TIMER_MODE_MASK); lvtt_value |= APIC_TIMER_MODE_TSC_DEADLINE; } apic_write_around(APIC_LVTT, lvtt_value); tmp_value = apic_read(APIC_TDCR); apic_write_around(APIC_TDCR, (tmp_value | APIC_TDR_DIV_1)); apic_write_around(APIC_TMICT, clocks/APIC_DIVISOR); }
void arch_smp_send_broadcast_ici(void) { uint32 config; cpu_status state = disable_interrupts(); config = apic_read(APIC_INTR_COMMAND_1) & APIC_INTR_COMMAND_1_MASK; apic_write(APIC_INTR_COMMAND_1, config | 0xfd | APIC_DELIVERY_MODE_FIXED | APIC_INTR_COMMAND_1_ASSERT | APIC_INTR_COMMAND_1_DEST_MODE_PHYSICAL | APIC_INTR_COMMAND_1_DEST_ALL_BUT_SELF); restore_interrupts(state); }
static void nmi_cpu_stop(void * dummy) { unsigned int v; int cpu = smp_processor_id(); struct op_msrs const * msrs = &cpu_msrs[cpu]; model->stop(msrs); /* restoring APIC_LVTPC can trigger an apic error because the delivery * mode and vector nr combination can be illegal. That's by design: on * power on apic lvt contain a zero vector nr which are legal only for * NMI delivery mode. So inhibit apic err before restoring lvtpc */ if ( (apic_read(APIC_LVTPC) & APIC_MODE_MASK) != APIC_DM_NMI || (apic_read(APIC_LVTPC) & APIC_LVT_MASKED) ) { printk("nmi_stop: APIC not good %ul\n", apic_read(APIC_LVTPC)); mdelay(5000); } v = apic_read(APIC_LVTERR); apic_write(APIC_LVTERR, v | APIC_LVT_MASKED); apic_write(APIC_LVTPC, saved_lvtpc[cpu]); apic_write(APIC_LVTERR, v); }
void error_interrupt(struct cpu_user_regs *regs) { unsigned long v, v1; /* First tickle the hardware, only then report what went on. -- REW */ v = apic_read(APIC_ESR); apic_write(APIC_ESR, 0); v1 = apic_read(APIC_ESR); ack_APIC_irq(); /* Here is what the APIC error bits mean: 0: Send CS error 1: Receive CS error 2: Send accept error 3: Receive accept error 4: Reserved 5: Send illegal vector 6: Received illegal vector 7: Illegal register address */ printk (KERN_DEBUG "APIC error on CPU%d: %02lx(%02lx)\n", smp_processor_id(), v , v1); }
void disable_local_APIC(void) { unsigned long value; clear_local_APIC(); /* * Disable APIC (implies clearing of registers * for 82489DX!). */ value = apic_read(APIC_SPIV); value &= ~APIC_SPIV_APIC_ENABLED; apic_write_around(APIC_SPIV, value); }
void __init lvtpc_apic_setup(void * dummy) { uint val; /* set up LVTPC as we need it */ /* IA32 V3, Figure 7.8 */ val = apic_read(APIC_LVTPC); saved_lvtpc[op_cpu_id()] = val; /* allow PC overflow interrupts */ val &= ~APIC_LVT_MASKED; /* set delivery to NMI */ val = SET_APIC_DELIVERY_MODE(val, APIC_MODE_NMI); apic_write(APIC_LVTPC, val); }
void clear_local_APIC(void) { int maxlvt; unsigned long v; maxlvt = get_maxlvt(); /* * Careful: we have to set masks only first to deassert * any level-triggered sources. */ v = apic_read(APIC_LVTT); apic_write_around(APIC_LVTT, v | APIC_LVT_MASKED); v = apic_read(APIC_LVT0); apic_write_around(APIC_LVT0, v | APIC_LVT_MASKED); v = apic_read(APIC_LVT1); apic_write_around(APIC_LVT1, v | APIC_LVT_MASKED); if (maxlvt >= 3) { v = apic_read(APIC_LVTERR); apic_write_around(APIC_LVTERR, v | APIC_LVT_MASKED); } if (maxlvt >= 4) { v = apic_read(APIC_LVTPC); apic_write_around(APIC_LVTPC, v | APIC_LVT_MASKED); } /* * Clean APIC state for other OSs: */ apic_write_around(APIC_LVTT, APIC_LVT_MASKED); apic_write_around(APIC_LVT0, APIC_LVT_MASKED); apic_write_around(APIC_LVT1, APIC_LVT_MASKED); if (maxlvt >= 3) apic_write_around(APIC_LVTERR, APIC_LVT_MASKED); if (maxlvt >= 4) apic_write_around(APIC_LVTPC, APIC_LVT_MASKED); }
static int lapic_resume(struct sys_device *dev) { unsigned int l, h; unsigned long flags; if (!apic_pm_state.active) return 0; /* XXX: Pavel needs this for S3 resume, but can't explain why */ set_fixmap_nocache(FIX_APIC_BASE, APIC_DEFAULT_PHYS_BASE); local_irq_save(flags); rdmsr(MSR_IA32_APICBASE, l, h); l &= ~MSR_IA32_APICBASE_BASE; l |= MSR_IA32_APICBASE_ENABLE | APIC_DEFAULT_PHYS_BASE; wrmsr(MSR_IA32_APICBASE, l, h); apic_write(APIC_LVTERR, ERROR_APIC_VECTOR | APIC_LVT_MASKED); apic_write(APIC_ID, apic_pm_state.apic_id); apic_write(APIC_DFR, apic_pm_state.apic_dfr); apic_write(APIC_LDR, apic_pm_state.apic_ldr); apic_write(APIC_TASKPRI, apic_pm_state.apic_taskpri); apic_write(APIC_SPIV, apic_pm_state.apic_spiv); apic_write(APIC_LVT0, apic_pm_state.apic_lvt0); apic_write(APIC_LVT1, apic_pm_state.apic_lvt1); apic_write(APIC_LVTTHMR, apic_pm_state.apic_thmr); apic_write(APIC_LVTPC, apic_pm_state.apic_lvtpc); apic_write(APIC_LVTT, apic_pm_state.apic_lvtt); apic_write(APIC_TDCR, apic_pm_state.apic_tdcr); apic_write(APIC_TMICT, apic_pm_state.apic_tmict); apic_write(APIC_ESR, 0); apic_read(APIC_ESR); apic_write(APIC_LVTERR, apic_pm_state.apic_lvterr); apic_write(APIC_ESR, 0); apic_read(APIC_ESR); local_irq_restore(flags); return 0; }
void calibrate_APIC_clock(void) { long tt1, tt2; int i; const int LOOPS = HZ / 10; dprintf("calibrating APIC timer ...\n"); setup_APIC_LVTT(0xffffffff); disable_APIC_clock(0 /*dummy */ ); /* disable timer IRQ */ /* Let's wait for a wraparound to start exact measurement */ wait_8254_wraparound(); /* We wrapped around just now. Let's start */ tt1 = apic_read(APIC_TMCCT); /* Let's wait LOOPS wraprounds */ for (i = 0; i < LOOPS; i++) wait_8254_wraparound(); tt2 = apic_read(APIC_TMCCT); calibration_result = ((tt1 - tt2) /* clocks for LOOPS */ /LOOPS); /* clocks per LOOP */ /* init timer to std timeslice */ set_APIC_clock(XXX); #ifdef SMP wait_8254_wraparound(); //ttt smp_call_function(APIC_DEST_ALLBUT, setup_APIC_LVTT, (void *) (XXX * calibration_result), 1, NULL); #endif dprintf("..... host bus clock speed is %ld.%04ld MHz.\n", (calibration_result * APIC_DIVISOR) / (1000000 / HZ), (calibration_result * APIC_DIVISOR) % (1000000 / HZ)); }
/* * For high res timers we want a single shot timer. * This means, for profiling, that we must load it each * interrupt, but it works best for timers as a one shot and * it is little overhead for the profiling which, we hope is * not done that often, nor on production machines. */ void __setup_APIC_LVTT(unsigned int clocks) { unsigned int lvtt_value, tmp_value, ver; ver = GET_APIC_VERSION(apic_read(APIC_LVR)); lvtt_value = #ifndef CONFIG_HIGH_RES_TIMERS APIC_LVT_TIMER_PERIODIC | #endif LOCAL_TIMER_VECTOR; if (!APIC_INTEGRATED(ver)) lvtt_value |= SET_APIC_TIMER_BASE(APIC_TIMER_BASE_DIV); apic_write_around(APIC_LVTT, lvtt_value); /* * Divide PICLK by 16 */ tmp_value = apic_read(APIC_TDCR); apic_write_around(APIC_TDCR, (tmp_value & ~(APIC_TDR_DIV_1 | APIC_TDR_DIV_TMBASE)) | APIC_TDR_DIV_16); apic_write_around(APIC_TMICT, clocks/APIC_DIVISOR); }
uint32_t apic_wait_for_send(struct apic_dev * apic) { uint32_t res; int n = 0; do { if (!(res = apic_read(apic, APIC_REG_ICR) & ICR_SEND_PENDING)) { break; } udelay(100); } while (n++ < 1000); return res; }
asmlinkage void smp_error_interrupt(void) { unsigned int v, v1; /* First tickle the hardware, only then report what went on. -- REW */ v = apic_read(APIC_ESR); apic_write(APIC_ESR, 0); v1 = apic_read(APIC_ESR); ack_APIC_irq(); atomic_inc(&irq_err_count); /* Here is what the APIC error bits mean: 0: Send CS error 1: Receive CS error 2: Send accept error 3: Receive accept error 4: Reserved 5: Send illegal vector 6: Received illegal vector 7: Illegal register address */ printk (KERN_ERR "APIC error on CPU%d: %02x(%02x)\n", smp_processor_id(), v , v1); }
void __init sync_Arb_IDs(void) { /* Unsupported on P4 - see Intel Dev. Manual Vol. 3, Ch. 8.6.1 */ unsigned int ver = GET_APIC_VERSION(apic_read(APIC_LVR)); if (ver >= 0x14) /* P4 or higher */ return; /* * Wait for idle. */ apic_wait_icr_idle(); apic_printk(APIC_DEBUG, "Synchronizing Arb IDs.\n"); apic_write_around(APIC_ICR, APIC_DEST_ALLINC | APIC_INT_LEVELTRIG | APIC_DM_INIT); }
u32 safe_apic_wait_icr_idle(void) { u32 send_status; int timeout; timeout = 0; do { send_status = apic_read(APIC_ICR) & APIC_ICR_BUSY; if (!send_status) break; udelay(100); } while (timeout++ < 1000); return send_status; }
/* * This is to verify that we're looking at a real local APIC. * Check these against your board if the CPUs aren't getting * started for no apparent reason. */ int __init verify_local_APIC(void) { unsigned int reg0, reg1; /* * The version register is read-only in a real APIC. */ reg0 = apic_read(APIC_LVR); Dprintk("Getting VERSION: %x\n", reg0); apic_write(APIC_LVR, reg0 ^ APIC_LVR_MASK); reg1 = apic_read(APIC_LVR); Dprintk("Getting VERSION: %x\n", reg1); /* * The two version reads above should print the same * numbers. If the second one is different, then we * poke at a non-APIC. */ if (reg1 != reg0) return 0; /* * Check if the version looks reasonably. */ reg1 = GET_APIC_VERSION(reg0); if (reg1 == 0x00 || reg1 == 0xff) return 0; reg1 = get_maxlvt(); if (reg1 < 0x02 || reg1 == 0xff) return 0; /* * The ID register is read/write in a real APIC. */ reg0 = apic_read(APIC_ID); Dprintk("Getting ID: %x\n", reg0); apic_write(APIC_ID, reg0 ^ APIC_ID_MASK); reg1 = apic_read(APIC_ID); Dprintk("Getting ID: %x\n", reg1); apic_write(APIC_ID, reg0); if (reg1 != (reg0 ^ APIC_ID_MASK)) return 0; /* * The next two are just to see if we have sane values. * They're only really relevant if we're in Virtual Wire * compatibility mode, but most boxes are anymore. */ reg0 = apic_read(APIC_LVT0); Dprintk("Getting LVT0: %x\n", reg0); reg1 = apic_read(APIC_LVT1); Dprintk("Getting LVT1: %x\n", reg1); return 1; }