void lapic_startclock(void) { /* * Start local apic countdown timer running, in repeated mode. * * Mask the clock interrupt and set mode, * then set divisor, * then unmask and set the vector. */ i82489_writereg(LAPIC_LVTT, LAPIC_LVTT_TM|LAPIC_LVTT_M); i82489_writereg(LAPIC_DCR_TIMER, LAPIC_DCRT_DIV1); i82489_writereg(LAPIC_ICR_TIMER, lapic_tval); i82489_writereg(LAPIC_LVTT, LAPIC_LVTT_TM|LAPIC_TIMER_VECTOR); }
static void tprof_amdpmi_stop_cpu(void *arg1, void *arg2) { struct cpu_info * const ci = curcpu(); wrmsr(PERFEVTSEL(ctrno), 0); i82489_writereg(LAPIC_PCINT, tprof_amdpmi_lapic_saved[cpu_index(ci)]); }
static void tprof_amdpmi_start_cpu(void *arg1, void *arg2) { struct cpu_info * const ci = curcpu(); uint64_t pesr; uint64_t event_lo; uint64_t event_hi; event_hi = event >> 8; event_lo = event & 0xff; pesr = PESR_USR | PESR_OS | PESR_INT | __SHIFTIN(event_lo, PESR_EVENT_MASK_LO) | __SHIFTIN(event_hi, PESR_EVENT_MASK_HI) | __SHIFTIN(0, PESR_COUNTER_MASK) | __SHIFTIN(unit, PESR_UNIT_MASK); wrmsr(PERFCTR(ctrno), counter_reset_val); wrmsr(PERFEVTSEL(ctrno), pesr); tprof_amdpmi_lapic_saved[cpu_index(ci)] = i82489_readreg(LAPIC_PCINT); i82489_writereg(LAPIC_PCINT, LAPIC_DLMODE_NMI); wrmsr(PERFEVTSEL(ctrno), pesr | PESR_EN); }
/* * Calibrate the local apic count-down timer (which is running at * bus-clock speed) vs. the i8254 counter/timer (which is running at * a fixed rate). * * The Intel MP spec says: "An MP operating system may use the IRQ8 * real-time clock as a reference to determine the actual APIC timer clock * speed." * * We're actually using the IRQ0 timer. Hmm. */ void lapic_calibrate_timer(struct cpu_info *ci) { unsigned int startapic, endapic; u_int64_t dtick, dapic, tmp; int i, ef = read_eflags(); if (mp_verbose) printf("%s: calibrating local timer\n", ci->ci_dev.dv_xname); /* * Configure timer to one-shot, interrupt masked, * large positive number. */ i82489_writereg(LAPIC_LVTT, LAPIC_LVTT_M); i82489_writereg(LAPIC_DCR_TIMER, LAPIC_DCRT_DIV1); i82489_writereg(LAPIC_ICR_TIMER, 0x80000000); disable_intr(); /* wait for current cycle to finish */ wait_next_cycle(); startapic = lapic_gettick(); /* wait the next hz cycles */ for (i = 0; i < hz; i++) wait_next_cycle(); endapic = lapic_gettick(); write_eflags(ef); dtick = hz * TIMER_DIV(hz); dapic = startapic-endapic; /* * there are TIMER_FREQ ticks per second. * in dtick ticks, there are dapic bus clocks. */ tmp = (TIMER_FREQ * dapic) / dtick; lapic_per_second = tmp; printf("%s: apic clock running at %lldMHz\n", ci->ci_dev.dv_xname, tmp / (1000 * 1000)); if (lapic_per_second != 0) { /* * reprogram the apic timer to run in periodic mode. * XXX need to program timer on other cpu's, too. */ lapic_tval = (lapic_per_second * 2) / hz; lapic_tval = (lapic_tval / 2) + (lapic_tval & 0x1); i82489_writereg(LAPIC_LVTT, LAPIC_LVTT_TM | LAPIC_LVTT_M | LAPIC_TIMER_VECTOR); i82489_writereg(LAPIC_DCR_TIMER, LAPIC_DCRT_DIV1); i82489_writereg(LAPIC_ICR_TIMER, lapic_tval); /* * Compute fixed-point ratios between cycles and * microseconds to avoid having to do any division * in lapic_delay. */ tmp = (1000000 * (u_int64_t)1 << 32) / lapic_per_second; lapic_frac_usec_per_cycle = tmp; tmp = (lapic_per_second * (u_int64_t)1 << 32) / 1000000; lapic_frac_cycle_per_usec = tmp; /* * Compute delay in cycles for likely short delays in usec. */ for (i = 0; i < 26; i++) lapic_delaytab[i] = (lapic_frac_cycle_per_usec * i) >> 32; /* * Now that the timer's calibrated, use the apic timer routines * for all our timing needs.. */ delay_func = lapic_delay; initclock_func = lapic_initclocks; }
void lapic_set_lvt(void) { struct cpu_info *ci = curcpu(); int i; struct mp_intr_map *mpi; #ifdef MULTIPROCESSOR if (mp_verbose) { apic_format_redir(ci->ci_dev.dv_xname, "prelint", 0, 0, i82489_readreg(LAPIC_LVINT0)); apic_format_redir(ci->ci_dev.dv_xname, "prelint", 1, 0, i82489_readreg(LAPIC_LVINT1)); } #endif if (strcmp(cpu_vendor, "AuthenticAMD") == 0) { /* * Detect the presence of C1E capability mostly on latest * dual-cores (or future) k8 family. This mis-feature renders * the local APIC timer dead, so we disable it by reading * the Interrupt Pending Message register and clearing both * C1eOnCmpHalt (bit 28) and SmiOnCmpHalt (bit 27). * * Reference: * "BIOS and Kernel Developer's Guide for AMD NPT * Family 0Fh Processors" * #32559 revision 3.00 */ if ((cpu_id & 0x00000f00) == 0x00000f00 && (cpu_id & 0x0fff0000) >= 0x00040000) { uint64_t msr; msr = rdmsr(MSR_INT_PEN_MSG); if (msr & (IPM_C1E_CMP_HLT|IPM_SMI_CMP_HLT)) { msr &= ~(IPM_C1E_CMP_HLT|IPM_SMI_CMP_HLT); wrmsr(MSR_INT_PEN_MSG, msr); } } } for (i = 0; i < mp_nintrs; i++) { mpi = &mp_intrs[i]; if (mpi->ioapic == NULL && (mpi->cpu_id == MPS_ALL_APICS || mpi->cpu_id == ci->ci_apicid)) { #ifdef DIAGNOSTIC if (mpi->ioapic_pin > 1) panic("lapic_set_lvt: bad pin value %d", mpi->ioapic_pin); #endif if (mpi->ioapic_pin == 0) i82489_writereg(LAPIC_LVINT0, mpi->redir); else i82489_writereg(LAPIC_LVINT1, mpi->redir); } } #ifdef MULTIPROCESSOR if (mp_verbose) { apic_format_redir(ci->ci_dev.dv_xname, "timer", 0, 0, i82489_readreg(LAPIC_LVTT)); apic_format_redir(ci->ci_dev.dv_xname, "pcint", 0, 0, i82489_readreg(LAPIC_PCINT)); apic_format_redir(ci->ci_dev.dv_xname, "lint", 0, 0, i82489_readreg(LAPIC_LVINT0)); apic_format_redir(ci->ci_dev.dv_xname, "lint", 1, 0, i82489_readreg(LAPIC_LVINT1)); apic_format_redir(ci->ci_dev.dv_xname, "err", 0, 0, i82489_readreg(LAPIC_LVERR)); } #endif }
void lapic_disable(void) { i82489_writereg(LAPIC_SVR, 0); }
/* * enable local apic */ void lapic_enable(void) { i82489_writereg(LAPIC_SVR, LAPIC_SVR_ENABLE | LAPIC_SPURIOUS_VECTOR); }
void i386_self_ipi(int vector) { i82489_writereg(LAPIC_ICRLO, vector | LAPIC_DLMODE_FIXED | LAPIC_LVL_ASSERT | LAPIC_DEST_SELF); }