Example #1
0
void
lapic_setup(int boot)
{
	struct lapic *la;
	u_int32_t maxlvt;
	register_t saveintr;
	char buf[MAXCOMLEN + 1];

	la = &lapics[lapic_id()];
	KASSERT(la->la_present, ("missing APIC structure"));
	saveintr = intr_disable();
	maxlvt = (lapic->version & APIC_VER_MAXLVT) >> MAXLVTSHIFT;

	/* Initialize the TPR to allow all interrupts. */
	lapic_set_tpr(0);

	/* Setup spurious vector and enable the local APIC. */
	lapic_enable();

	/* Program LINT[01] LVT entries. */
	lapic->lvt_lint0 = lvt_mode(la, LVT_LINT0, lapic->lvt_lint0);
	lapic->lvt_lint1 = lvt_mode(la, LVT_LINT1, lapic->lvt_lint1);

	/* Program the PMC LVT entry if present. */
	if (maxlvt >= LVT_PMC)
		lapic->lvt_pcint = lvt_mode(la, LVT_PMC, lapic->lvt_pcint);

	/* Program timer LVT and setup handler. */
	la->lvt_timer_cache = lapic->lvt_timer =
	    lvt_mode(la, LVT_TIMER, lapic->lvt_timer);
	if (boot) {
		snprintf(buf, sizeof(buf), "cpu%d:timer", PCPU_GET(cpuid));
		intrcnt_add(buf, &la->la_timer_count);
	}

	/* Setup the timer if configured. */
	if (la->la_timer_mode != 0) {
		KASSERT(la->la_timer_period != 0, ("lapic%u: zero divisor",
		    lapic_id()));
		lapic_timer_set_divisor(lapic_timer_divisor);
		if (la->la_timer_mode == 1)
			lapic_timer_periodic(la, la->la_timer_period, 1);
		else
			lapic_timer_oneshot(la, la->la_timer_period, 1);
	}

	/* Program error LVT and clear any existing errors. */
	lapic->lvt_error = lvt_mode(la, LVT_ERROR, lapic->lvt_error);
	lapic->esr = 0;

	/* XXX: Thermal LVT */

	/* Program the CMCI LVT entry if present. */
	if (maxlvt >= LVT_CMCI)
		lapic->lvt_cmci = lvt_mode(la, LVT_CMCI, lapic->lvt_cmci);
	    
	intr_restore(saveintr);
}
Example #2
0
static int
lapic_et_start(struct eventtimer *et,
    struct bintime *first, struct bintime *period)
{
	struct lapic *la;
	u_long value;

	la = &lapics[PCPU_GET(apic_id)];
	if (et->et_frequency == 0) {
		/* Start off with a divisor of 2 (power on reset default). */
		lapic_timer_divisor = 2;
		/* Try to calibrate the local APIC timer. */
		do {
			lapic_timer_set_divisor(lapic_timer_divisor);
			lapic_timer_oneshot(la, APIC_TIMER_MAX_COUNT, 0);
			DELAY(1000000);
			value = APIC_TIMER_MAX_COUNT - lapic->ccr_timer;
			if (value != APIC_TIMER_MAX_COUNT)
				break;
			lapic_timer_divisor <<= 1;
		} while (lapic_timer_divisor <= 128);
		if (lapic_timer_divisor > 128)
			panic("lapic: Divisor too big");
		if (bootverbose)
			printf("lapic: Divisor %lu, Frequency %lu Hz\n",
			    lapic_timer_divisor, value);
		et->et_frequency = value;
		et->et_min_period.sec = 0;
		et->et_min_period.frac =
		    ((0x00000002LLU << 32) / et->et_frequency) << 32;
		et->et_max_period.sec = 0xfffffffeLLU / et->et_frequency;
		et->et_max_period.frac =
		    ((0xfffffffeLLU << 32) / et->et_frequency) << 32;
	}
	if (la->la_timer_mode == 0)
		lapic_timer_set_divisor(lapic_timer_divisor);
	if (period != NULL) {
		la->la_timer_mode = 1;
		la->la_timer_period =
		    (et->et_frequency * (period->frac >> 32)) >> 32;
		if (period->sec != 0)
			la->la_timer_period += et->et_frequency * period->sec;
		lapic_timer_periodic(la, la->la_timer_period, 1);
	} else {
Example #3
0
static void
lapic_timer_calibrate(void)
{
	sysclock_t value;

	/* Try to calibrate the local APIC timer. */
	for (lapic_timer_divisor_idx = 0;
	     lapic_timer_divisor_idx < APIC_TIMER_NDIVISORS;
	     lapic_timer_divisor_idx++) {
		lapic_timer_set_divisor(lapic_timer_divisor_idx);
		lapic_timer_oneshot(APIC_TIMER_MAX_COUNT);
		DELAY(2000000);
		value = APIC_TIMER_MAX_COUNT - lapic->ccr_timer;
		if (value != APIC_TIMER_MAX_COUNT)
			break;
	}
	if (lapic_timer_divisor_idx >= APIC_TIMER_NDIVISORS)
		panic("lapic: no proper timer divisor?!");
	lapic_cputimer_intr.freq = value / 2;

	kprintf("lapic: divisor index %d, frequency %u Hz\n",
		lapic_timer_divisor_idx, lapic_cputimer_intr.freq);
}