local_apic.c revision 215751
1121986Sjhb/*-
2121986Sjhb * Copyright (c) 2003 John Baldwin <jhb@FreeBSD.org>
3121986Sjhb * Copyright (c) 1996, by Steve Passe
4121986Sjhb * All rights reserved.
5121986Sjhb *
6121986Sjhb * Redistribution and use in source and binary forms, with or without
7121986Sjhb * modification, are permitted provided that the following conditions
8121986Sjhb * are met:
9121986Sjhb * 1. Redistributions of source code must retain the above copyright
10121986Sjhb *    notice, this list of conditions and the following disclaimer.
11121986Sjhb * 2. The name of the developer may NOT be used to endorse or promote products
12121986Sjhb *    derived from this software without specific prior written permission.
13121986Sjhb * 3. Neither the name of the author nor the names of any co-contributors
14121986Sjhb *    may be used to endorse or promote products derived from this software
15121986Sjhb *    without specific prior written permission.
16121986Sjhb *
17121986Sjhb * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
18121986Sjhb * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19121986Sjhb * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20121986Sjhb * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
21121986Sjhb * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22121986Sjhb * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
23121986Sjhb * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24121986Sjhb * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25121986Sjhb * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
26121986Sjhb * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27121986Sjhb * SUCH DAMAGE.
28121986Sjhb */
29121986Sjhb
30121986Sjhb/*
31121986Sjhb * Local APIC support on Pentium and later processors.
32121986Sjhb */
33121986Sjhb
34121986Sjhb#include <sys/cdefs.h>
35121986Sjhb__FBSDID("$FreeBSD: head/sys/x86/x86/local_apic.c 215751 2010-11-23 14:36:14Z avg $");
36121986Sjhb
37147565Speter#include "opt_hwpmc_hooks.h"
38179277Sjb#include "opt_kdtrace.h"
39147565Speter
40151979Sjhb#include "opt_ddb.h"
41151979Sjhb
42121986Sjhb#include <sys/param.h>
43121986Sjhb#include <sys/systm.h>
44121986Sjhb#include <sys/bus.h>
45121986Sjhb#include <sys/kernel.h>
46151979Sjhb#include <sys/lock.h>
47151979Sjhb#include <sys/mutex.h>
48121986Sjhb#include <sys/pcpu.h>
49187880Sjeff#include <sys/proc.h>
50187880Sjeff#include <sys/sched.h>
51141538Sjhb#include <sys/smp.h>
52209371Smav#include <sys/timeet.h>
53121986Sjhb
54121986Sjhb#include <vm/vm.h>
55121986Sjhb#include <vm/pmap.h>
56121986Sjhb
57214631Sjhb#include <x86/apicreg.h>
58153666Sjhb#include <machine/cpu.h>
59121986Sjhb#include <machine/cputypes.h>
60121986Sjhb#include <machine/frame.h>
61121986Sjhb#include <machine/intr_machdep.h>
62121986Sjhb#include <machine/apicvar.h>
63214630Sjhb#include <x86/mca.h>
64121986Sjhb#include <machine/md_var.h>
65121986Sjhb#include <machine/smp.h>
66121986Sjhb#include <machine/specialreg.h>
67121986Sjhb
68151979Sjhb#ifdef DDB
69151979Sjhb#include <sys/interrupt.h>
70151979Sjhb#include <ddb/ddb.h>
71151979Sjhb#endif
72151979Sjhb
73208452Smav#ifdef __amd64__
74208452Smav#define	SDT_APIC	SDT_SYSIGT
75208452Smav#define	SDT_APICT	SDT_SYSIGT
76208452Smav#define	GSEL_APIC	0
77208452Smav#else
78208452Smav#define	SDT_APIC	SDT_SYS386IGT
79208452Smav#define	SDT_APICT	SDT_SYS386TGT
80208452Smav#define	GSEL_APIC	GSEL(GCODE_SEL, SEL_KPL)
81208452Smav#endif
82208452Smav
83122690Sjhb/* Sanity checks on IDT vectors. */
84139240SjhbCTASSERT(APIC_IO_INTS + APIC_NUM_IOINTS == APIC_TIMER_INT);
85139240SjhbCTASSERT(APIC_TIMER_INT < APIC_LOCAL_INTS);
86139240SjhbCTASSERT(APIC_LOCAL_INTS == 240);
87122690SjhbCTASSERT(IPI_STOP < APIC_SPURIOUS_INT);
88122690Sjhb
89151979Sjhb/* Magic IRQ values for the timer and syscalls. */
90151979Sjhb#define	IRQ_TIMER	(NUM_IO_INTS + 1)
91151979Sjhb#define	IRQ_SYSCALL	(NUM_IO_INTS + 2)
92212004Srpaulo#define	IRQ_DTRACE_RET	(NUM_IO_INTS + 3)
93151979Sjhb
94121986Sjhb/*
95121986Sjhb * Support for local APICs.  Local APICs manage interrupts on each
96121986Sjhb * individual processor as opposed to I/O APICs which receive interrupts
97121986Sjhb * from I/O devices and then forward them on to the local APICs.
98121986Sjhb *
99121986Sjhb * Local APICs can also send interrupts to each other thus providing the
100121986Sjhb * mechanism for IPIs.
101121986Sjhb */
102121986Sjhb
103121986Sjhbstruct lvt {
104121986Sjhb	u_int lvt_edgetrigger:1;
105121986Sjhb	u_int lvt_activehi:1;
106121986Sjhb	u_int lvt_masked:1;
107121986Sjhb	u_int lvt_active:1;
108121986Sjhb	u_int lvt_mode:16;
109121986Sjhb	u_int lvt_vector:8;
110121986Sjhb};
111121986Sjhb
112121986Sjhbstruct lapic {
113121986Sjhb	struct lvt la_lvts[LVT_MAX + 1];
114121986Sjhb	u_int la_id:8;
115121986Sjhb	u_int la_cluster:4;
116121986Sjhb	u_int la_cluster_id:2;
117121986Sjhb	u_int la_present:1;
118141538Sjhb	u_long *la_timer_count;
119209371Smav	u_long la_timer_period;
120209371Smav	u_int la_timer_mode;
121187880Sjeff	/* Include IDT_SYSCALL to make indexing easier. */
122191720Smav	int la_ioint_irqs[APIC_NUM_IOINTS + 1];
123169395Sjhb} static lapics[MAX_APIC_ID + 1];
124121986Sjhb
125121986Sjhb/* Global defaults for local APIC LVT entries. */
126121986Sjhbstatic struct lvt lvts[LVT_MAX + 1] = {
127121986Sjhb	{ 1, 1, 1, 1, APIC_LVT_DM_EXTINT, 0 },	/* LINT0: masked ExtINT */
128121986Sjhb	{ 1, 1, 0, 1, APIC_LVT_DM_NMI, 0 },	/* LINT1: NMI */
129139245Sjhb	{ 1, 1, 1, 1, APIC_LVT_DM_FIXED, APIC_TIMER_INT },	/* Timer */
130205851Sjhb	{ 1, 1, 0, 1, APIC_LVT_DM_FIXED, APIC_ERROR_INT },	/* Error */
131196224Sjhb	{ 1, 1, 1, 1, APIC_LVT_DM_NMI, 0 },	/* PMC */
132139245Sjhb	{ 1, 1, 1, 1, APIC_LVT_DM_FIXED, APIC_THERMAL_INT },	/* Thermal */
133208507Sjhb	{ 1, 1, 1, 1, APIC_LVT_DM_FIXED, APIC_CMC_INT },	/* CMCI */
134121986Sjhb};
135121986Sjhb
136121986Sjhbstatic inthand_t *ioint_handlers[] = {
137121986Sjhb	NULL,			/* 0 - 31 */
138121986Sjhb	IDTVEC(apic_isr1),	/* 32 - 63 */
139121986Sjhb	IDTVEC(apic_isr2),	/* 64 - 95 */
140121986Sjhb	IDTVEC(apic_isr3),	/* 96 - 127 */
141121986Sjhb	IDTVEC(apic_isr4),	/* 128 - 159 */
142121986Sjhb	IDTVEC(apic_isr5),	/* 160 - 191 */
143122690Sjhb	IDTVEC(apic_isr6),	/* 192 - 223 */
144122690Sjhb	IDTVEC(apic_isr7),	/* 224 - 255 */
145121986Sjhb};
146121986Sjhb
147151979Sjhb
148195249Sjhbstatic u_int32_t lapic_timer_divisors[] = {
149141538Sjhb	APIC_TDCR_1, APIC_TDCR_2, APIC_TDCR_4, APIC_TDCR_8, APIC_TDCR_16,
150141538Sjhb	APIC_TDCR_32, APIC_TDCR_64, APIC_TDCR_128
151141538Sjhb};
152141538Sjhb
153169391Sjhbextern inthand_t IDTVEC(rsvd);
154169391Sjhb
155121986Sjhbvolatile lapic_t *lapic;
156167747Sjhbvm_paddr_t lapic_paddr;
157209371Smavstatic u_long lapic_timer_divisor;
158209371Smavstatic struct eventtimer lapic_et;
159121986Sjhb
160139245Sjhbstatic void	lapic_enable(void);
161163219Sjhbstatic void	lapic_resume(struct pic *pic);
162141538Sjhbstatic void	lapic_timer_enable_intr(void);
163141538Sjhbstatic void	lapic_timer_oneshot(u_int count);
164141538Sjhbstatic void	lapic_timer_periodic(u_int count);
165209371Smavstatic void	lapic_timer_stop(void);
166141538Sjhbstatic void	lapic_timer_set_divisor(u_int divisor);
167139245Sjhbstatic uint32_t	lvt_mode(struct lapic *la, u_int pin, uint32_t value);
168209371Smavstatic int	lapic_et_start(struct eventtimer *et,
169209371Smav    struct bintime *first, struct bintime *period);
170209371Smavstatic int	lapic_et_stop(struct eventtimer *et);
171139245Sjhb
172163219Sjhbstruct pic lapic_pic = { .pic_resume = lapic_resume };
173163219Sjhb
174121986Sjhbstatic uint32_t
175121986Sjhblvt_mode(struct lapic *la, u_int pin, uint32_t value)
176121986Sjhb{
177121986Sjhb	struct lvt *lvt;
178121986Sjhb
179121986Sjhb	KASSERT(pin <= LVT_MAX, ("%s: pin %u out of range", __func__, pin));
180121986Sjhb	if (la->la_lvts[pin].lvt_active)
181121986Sjhb		lvt = &la->la_lvts[pin];
182121986Sjhb	else
183121986Sjhb		lvt = &lvts[pin];
184121986Sjhb
185121986Sjhb	value &= ~(APIC_LVT_M | APIC_LVT_TM | APIC_LVT_IIPP | APIC_LVT_DM |
186121986Sjhb	    APIC_LVT_VECTOR);
187121986Sjhb	if (lvt->lvt_edgetrigger == 0)
188121986Sjhb		value |= APIC_LVT_TM;
189121986Sjhb	if (lvt->lvt_activehi == 0)
190121986Sjhb		value |= APIC_LVT_IIPP_INTALO;
191121986Sjhb	if (lvt->lvt_masked)
192121986Sjhb		value |= APIC_LVT_M;
193121986Sjhb	value |= lvt->lvt_mode;
194121986Sjhb	switch (lvt->lvt_mode) {
195121986Sjhb	case APIC_LVT_DM_NMI:
196121986Sjhb	case APIC_LVT_DM_SMI:
197121986Sjhb	case APIC_LVT_DM_INIT:
198121986Sjhb	case APIC_LVT_DM_EXTINT:
199121986Sjhb		if (!lvt->lvt_edgetrigger) {
200121986Sjhb			printf("lapic%u: Forcing LINT%u to edge trigger\n",
201121986Sjhb			    la->la_id, pin);
202121986Sjhb			value |= APIC_LVT_TM;
203121986Sjhb		}
204121986Sjhb		/* Use a vector of 0. */
205121986Sjhb		break;
206121986Sjhb	case APIC_LVT_DM_FIXED:
207121986Sjhb		value |= lvt->lvt_vector;
208121986Sjhb		break;
209121986Sjhb	default:
210121986Sjhb		panic("bad APIC LVT delivery mode: %#x\n", value);
211121986Sjhb	}
212121986Sjhb	return (value);
213121986Sjhb}
214121986Sjhb
215121986Sjhb/*
216121986Sjhb * Map the local APIC and setup necessary interrupt vectors.
217121986Sjhb */
218121986Sjhbvoid
219167247Sjhblapic_init(vm_paddr_t addr)
220121986Sjhb{
221209371Smav	u_int regs[4];
222209371Smav	int i, arat;
223121986Sjhb
224121986Sjhb	/* Map the local APIC and setup the spurious interrupt handler. */
225121986Sjhb	KASSERT(trunc_page(addr) == addr,
226121986Sjhb	    ("local APIC not aligned on a page boundary"));
227156920Sjhb	lapic = pmap_mapdev(addr, sizeof(lapic_t));
228167747Sjhb	lapic_paddr = addr;
229208452Smav	setidt(APIC_SPURIOUS_INT, IDTVEC(spuriousint), SDT_APIC, SEL_KPL,
230208452Smav	    GSEL_APIC);
231121986Sjhb
232121986Sjhb	/* Perform basic initialization of the BSP's local APIC. */
233139245Sjhb	lapic_enable();
234121986Sjhb
235121986Sjhb	/* Set BSP's per-CPU local APIC ID. */
236121986Sjhb	PCPU_SET(apic_id, lapic_id());
237121986Sjhb
238141538Sjhb	/* Local APIC timer interrupt. */
239208452Smav	setidt(APIC_TIMER_INT, IDTVEC(timerint), SDT_APIC, SEL_KPL, GSEL_APIC);
240141538Sjhb
241205851Sjhb	/* Local APIC error interrupt. */
242208452Smav	setidt(APIC_ERROR_INT, IDTVEC(errorint), SDT_APIC, SEL_KPL, GSEL_APIC);
243205851Sjhb
244205851Sjhb	/* XXX: Thermal interrupt */
245208507Sjhb
246208507Sjhb	/* Local APIC CMCI. */
247208507Sjhb	setidt(APIC_CMC_INT, IDTVEC(cmcint), SDT_APICT, SEL_KPL, GSEL_APIC);
248209371Smav
249209371Smav	if ((resource_int_value("apic", 0, "clock", &i) != 0 || i != 0)) {
250209371Smav		arat = 0;
251209371Smav		/* Intel CPUID 0x06 EAX[2] set if APIC timer runs in C3. */
252209371Smav		if (cpu_vendor_id == CPU_VENDOR_INTEL && cpu_high >= 6) {
253209371Smav			do_cpuid(0x06, regs);
254215751Savg			if ((regs[0] & CPUTPM1_ARAT) != 0)
255209371Smav				arat = 1;
256209371Smav		}
257209371Smav		bzero(&lapic_et, sizeof(lapic_et));
258209371Smav		lapic_et.et_name = "LAPIC";
259209371Smav		lapic_et.et_flags = ET_FLAGS_PERIODIC | ET_FLAGS_ONESHOT |
260209371Smav		    ET_FLAGS_PERCPU;
261209371Smav		lapic_et.et_quality = 600;
262209371Smav		if (!arat) {
263209371Smav			lapic_et.et_flags |= ET_FLAGS_C3STOP;
264212541Smav			lapic_et.et_quality -= 200;
265209371Smav		}
266209371Smav		lapic_et.et_frequency = 0;
267210290Smav		/* We don't know frequency yet, so trying to guess. */
268210290Smav		lapic_et.et_min_period.sec = 0;
269210290Smav		lapic_et.et_min_period.frac = 0x00001000LL << 32;
270210290Smav		lapic_et.et_max_period.sec = 1;
271210290Smav		lapic_et.et_max_period.frac = 0;
272209371Smav		lapic_et.et_start = lapic_et_start;
273209371Smav		lapic_et.et_stop = lapic_et_stop;
274209371Smav		lapic_et.et_priv = NULL;
275209371Smav		et_register(&lapic_et);
276209371Smav	}
277121986Sjhb}
278121986Sjhb
279121986Sjhb/*
280121986Sjhb * Create a local APIC instance.
281121986Sjhb */
282121986Sjhbvoid
283121986Sjhblapic_create(u_int apic_id, int boot_cpu)
284121986Sjhb{
285121986Sjhb	int i;
286121986Sjhb
287169395Sjhb	if (apic_id > MAX_APIC_ID) {
288121986Sjhb		printf("APIC: Ignoring local APIC with ID %d\n", apic_id);
289121986Sjhb		if (boot_cpu)
290121986Sjhb			panic("Can't ignore BSP");
291121986Sjhb		return;
292121986Sjhb	}
293121986Sjhb	KASSERT(!lapics[apic_id].la_present, ("duplicate local APIC %u",
294121986Sjhb	    apic_id));
295121986Sjhb
296121986Sjhb	/*
297121986Sjhb	 * Assume no local LVT overrides and a cluster of 0 and
298121986Sjhb	 * intra-cluster ID of 0.
299121986Sjhb	 */
300121986Sjhb	lapics[apic_id].la_present = 1;
301121986Sjhb	lapics[apic_id].la_id = apic_id;
302208507Sjhb	for (i = 0; i <= LVT_MAX; i++) {
303121986Sjhb		lapics[apic_id].la_lvts[i] = lvts[i];
304121986Sjhb		lapics[apic_id].la_lvts[i].lvt_active = 0;
305121986Sjhb	}
306191720Smav	for (i = 0; i <= APIC_NUM_IOINTS; i++)
307191720Smav	    lapics[apic_id].la_ioint_irqs[i] = -1;
308187880Sjeff	lapics[apic_id].la_ioint_irqs[IDT_SYSCALL - APIC_IO_INTS] = IRQ_SYSCALL;
309187880Sjeff	lapics[apic_id].la_ioint_irqs[APIC_TIMER_INT - APIC_IO_INTS] =
310187880Sjeff	    IRQ_TIMER;
311212004Srpaulo#ifdef KDTRACE_HOOKS
312212004Srpaulo	lapics[apic_id].la_ioint_irqs[IDT_DTRACE_RET - APIC_IO_INTS] = IRQ_DTRACE_RET;
313212004Srpaulo#endif
314121986Sjhb
315212004Srpaulo
316121986Sjhb#ifdef SMP
317121986Sjhb	cpu_add(apic_id, boot_cpu);
318121986Sjhb#endif
319121986Sjhb}
320121986Sjhb
321121986Sjhb/*
322121986Sjhb * Dump contents of local APIC registers
323121986Sjhb */
324121986Sjhbvoid
325121986Sjhblapic_dump(const char* str)
326121986Sjhb{
327215001Sjhb	uint32_t maxlvt;
328121986Sjhb
329215001Sjhb	maxlvt = (lapic->version & APIC_VER_MAXLVT) >> MAXLVTSHIFT;
330121986Sjhb	printf("cpu%d %s:\n", PCPU_GET(cpuid), str);
331121986Sjhb	printf("     ID: 0x%08x   VER: 0x%08x LDR: 0x%08x DFR: 0x%08x\n",
332121986Sjhb	    lapic->id, lapic->version, lapic->ldr, lapic->dfr);
333121986Sjhb	printf("  lint0: 0x%08x lint1: 0x%08x TPR: 0x%08x SVR: 0x%08x\n",
334121986Sjhb	    lapic->lvt_lint0, lapic->lvt_lint1, lapic->tpr, lapic->svr);
335215001Sjhb	printf("  timer: 0x%08x therm: 0x%08x err: 0x%08x",
336215001Sjhb	    lapic->lvt_timer, lapic->lvt_thermal, lapic->lvt_error);
337215001Sjhb	if (maxlvt >= LVT_PMC)
338215001Sjhb		printf(" pmc: 0x%08x", lapic->lvt_pcint);
339215001Sjhb	printf("\n");
340215001Sjhb	if (maxlvt >= LVT_CMCI)
341215001Sjhb		printf("   cmci: 0x%08x\n", lapic->lvt_cmci);
342121986Sjhb}
343121986Sjhb
344121986Sjhbvoid
345163219Sjhblapic_setup(int boot)
346121986Sjhb{
347121986Sjhb	struct lapic *la;
348156124Sjhb	u_int32_t maxlvt;
349214347Sjhb	register_t saveintr;
350141538Sjhb	char buf[MAXCOMLEN + 1];
351121986Sjhb
352121986Sjhb	la = &lapics[lapic_id()];
353121986Sjhb	KASSERT(la->la_present, ("missing APIC structure"));
354214347Sjhb	saveintr = intr_disable();
355121986Sjhb	maxlvt = (lapic->version & APIC_VER_MAXLVT) >> MAXLVTSHIFT;
356121986Sjhb
357139240Sjhb	/* Initialize the TPR to allow all interrupts. */
358139240Sjhb	lapic_set_tpr(0);
359121986Sjhb
360121986Sjhb	/* Setup spurious vector and enable the local APIC. */
361139245Sjhb	lapic_enable();
362139245Sjhb
363139245Sjhb	/* Program LINT[01] LVT entries. */
364139245Sjhb	lapic->lvt_lint0 = lvt_mode(la, LVT_LINT0, lapic->lvt_lint0);
365139245Sjhb	lapic->lvt_lint1 = lvt_mode(la, LVT_LINT1, lapic->lvt_lint1);
366185933Sjhb
367145256Sjkoshy	/* Program the PMC LVT entry if present. */
368145256Sjkoshy	if (maxlvt >= LVT_PMC)
369145256Sjkoshy		lapic->lvt_pcint = lvt_mode(la, LVT_PMC, lapic->lvt_pcint);
370139245Sjhb
371141538Sjhb	/* Program timer LVT and setup handler. */
372141538Sjhb	lapic->lvt_timer = lvt_mode(la, LVT_TIMER, lapic->lvt_timer);
373163219Sjhb	if (boot) {
374209371Smav		snprintf(buf, sizeof(buf), "cpu%d:timer", PCPU_GET(cpuid));
375163219Sjhb		intrcnt_add(buf, &la->la_timer_count);
376163219Sjhb	}
377163219Sjhb
378209371Smav	/* Setup the timer if configured. */
379209371Smav	if (la->la_timer_mode != 0) {
380209371Smav		KASSERT(la->la_timer_period != 0, ("lapic%u: zero divisor",
381141538Sjhb		    lapic_id()));
382211756Smav		lapic_timer_stop();
383141538Sjhb		lapic_timer_set_divisor(lapic_timer_divisor);
384211756Smav		lapic_timer_enable_intr();
385209371Smav		if (la->la_timer_mode == 1)
386209371Smav			lapic_timer_periodic(la->la_timer_period);
387209371Smav		else
388209371Smav			lapic_timer_oneshot(la->la_timer_period);
389141538Sjhb	}
390139245Sjhb
391205851Sjhb	/* Program error LVT and clear any existing errors. */
392205851Sjhb	lapic->lvt_error = lvt_mode(la, LVT_ERROR, lapic->lvt_error);
393205851Sjhb	lapic->esr = 0;
394141538Sjhb
395205851Sjhb	/* XXX: Thermal LVT */
396205851Sjhb
397208507Sjhb	/* Program the CMCI LVT entry if present. */
398208507Sjhb	if (maxlvt >= LVT_CMCI)
399208507Sjhb		lapic->lvt_cmci = lvt_mode(la, LVT_CMCI, lapic->lvt_cmci);
400208507Sjhb
401214347Sjhb	intr_restore(saveintr);
402121986Sjhb}
403121986Sjhb
404196224Sjhbvoid
405196224Sjhblapic_reenable_pmc(void)
406196224Sjhb{
407196224Sjhb#ifdef HWPMC_HOOKS
408196224Sjhb	uint32_t value;
409196224Sjhb
410196224Sjhb	value =  lapic->lvt_pcint;
411196224Sjhb	value &= ~APIC_LVT_M;
412196224Sjhb	lapic->lvt_pcint = value;
413196224Sjhb#endif
414196224Sjhb}
415196224Sjhb
416196224Sjhb#ifdef HWPMC_HOOKS
417196224Sjhbstatic void
418196224Sjhblapic_update_pmc(void *dummy)
419196224Sjhb{
420196224Sjhb	struct lapic *la;
421196224Sjhb
422196224Sjhb	la = &lapics[lapic_id()];
423196224Sjhb	lapic->lvt_pcint = lvt_mode(la, LVT_PMC, lapic->lvt_pcint);
424196224Sjhb}
425196224Sjhb#endif
426196224Sjhb
427196224Sjhbint
428196224Sjhblapic_enable_pmc(void)
429196224Sjhb{
430196224Sjhb#ifdef HWPMC_HOOKS
431196224Sjhb	u_int32_t maxlvt;
432196224Sjhb
433196224Sjhb	/* Fail if the local APIC is not present. */
434196224Sjhb	if (lapic == NULL)
435196224Sjhb		return (0);
436196224Sjhb
437196224Sjhb	/* Fail if the PMC LVT is not present. */
438196224Sjhb	maxlvt = (lapic->version & APIC_VER_MAXLVT) >> MAXLVTSHIFT;
439196224Sjhb	if (maxlvt < LVT_PMC)
440196224Sjhb		return (0);
441196224Sjhb
442196224Sjhb	lvts[LVT_PMC].lvt_masked = 0;
443196224Sjhb
444196224Sjhb#ifdef SMP
445196224Sjhb	/*
446196224Sjhb	 * If hwpmc was loaded at boot time then the APs may not be
447196224Sjhb	 * started yet.  In that case, don't forward the request to
448196224Sjhb	 * them as they will program the lvt when they start.
449196224Sjhb	 */
450196224Sjhb	if (smp_started)
451196224Sjhb		smp_rendezvous(NULL, lapic_update_pmc, NULL, NULL);
452196224Sjhb	else
453196224Sjhb#endif
454196224Sjhb		lapic_update_pmc(NULL);
455196224Sjhb	return (1);
456196224Sjhb#else
457196224Sjhb	return (0);
458196224Sjhb#endif
459196224Sjhb}
460196224Sjhb
461196224Sjhbvoid
462196224Sjhblapic_disable_pmc(void)
463196224Sjhb{
464196224Sjhb#ifdef HWPMC_HOOKS
465196224Sjhb	u_int32_t maxlvt;
466196224Sjhb
467196224Sjhb	/* Fail if the local APIC is not present. */
468196224Sjhb	if (lapic == NULL)
469196224Sjhb		return;
470196224Sjhb
471196224Sjhb	/* Fail if the PMC LVT is not present. */
472196224Sjhb	maxlvt = (lapic->version & APIC_VER_MAXLVT) >> MAXLVTSHIFT;
473196224Sjhb	if (maxlvt < LVT_PMC)
474196224Sjhb		return;
475196224Sjhb
476196224Sjhb	lvts[LVT_PMC].lvt_masked = 1;
477196224Sjhb
478196224Sjhb#ifdef SMP
479196224Sjhb	/* The APs should always be started when hwpmc is unloaded. */
480196224Sjhb	KASSERT(mp_ncpus == 1 || smp_started, ("hwpmc unloaded too early"));
481196224Sjhb#endif
482196224Sjhb	smp_rendezvous(NULL, lapic_update_pmc, NULL, NULL);
483196224Sjhb#endif
484196224Sjhb}
485196224Sjhb
486209371Smavstatic int
487209371Smavlapic_et_start(struct eventtimer *et,
488209371Smav    struct bintime *first, struct bintime *period)
489141538Sjhb{
490209371Smav	struct lapic *la;
491141538Sjhb	u_long value;
492141538Sjhb
493209371Smav	if (et->et_frequency == 0) {
494209371Smav		/* Start off with a divisor of 2 (power on reset default). */
495209371Smav		lapic_timer_divisor = 2;
496209371Smav		/* Try to calibrate the local APIC timer. */
497209371Smav		do {
498209371Smav			lapic_timer_set_divisor(lapic_timer_divisor);
499209371Smav			lapic_timer_oneshot(APIC_TIMER_MAX_COUNT);
500209371Smav			DELAY(1000000);
501209371Smav			value = APIC_TIMER_MAX_COUNT - lapic->ccr_timer;
502209371Smav			if (value != APIC_TIMER_MAX_COUNT)
503209371Smav				break;
504209371Smav			lapic_timer_divisor <<= 1;
505209371Smav		} while (lapic_timer_divisor <= 128);
506209371Smav		if (lapic_timer_divisor > 128)
507209371Smav			panic("lapic: Divisor too big");
508209371Smav		if (bootverbose)
509209371Smav			printf("lapic: Divisor %lu, Frequency %lu Hz\n",
510209371Smav			    lapic_timer_divisor, value);
511209371Smav		et->et_frequency = value;
512210290Smav		et->et_min_period.sec = 0;
513210290Smav		et->et_min_period.frac =
514210298Smav		    ((0x00000002LLU << 32) / et->et_frequency) << 32;
515210298Smav		et->et_max_period.sec = 0xfffffffeLLU / et->et_frequency;
516210290Smav		et->et_max_period.frac =
517210298Smav		    ((0xfffffffeLLU << 32) / et->et_frequency) << 32;
518204641Sattilio	}
519211756Smav	lapic_timer_stop();
520211756Smav	lapic_timer_set_divisor(lapic_timer_divisor);
521211756Smav	lapic_timer_enable_intr();
522209371Smav	la = &lapics[lapic_id()];
523209371Smav	if (period != NULL) {
524209371Smav		la->la_timer_mode = 1;
525209371Smav		la->la_timer_period =
526209371Smav		    (et->et_frequency * (period->frac >> 32)) >> 32;
527209371Smav		if (period->sec != 0)
528209371Smav			la->la_timer_period += et->et_frequency * period->sec;
529209371Smav		lapic_timer_periodic(la->la_timer_period);
530209371Smav	} else {
531209371Smav		la->la_timer_mode = 2;
532209371Smav		la->la_timer_period =
533209371Smav		    (et->et_frequency * (first->frac >> 32)) >> 32;
534209371Smav		if (first->sec != 0)
535209371Smav			la->la_timer_period += et->et_frequency * first->sec;
536209371Smav		lapic_timer_oneshot(la->la_timer_period);
537209371Smav	}
538209371Smav	return (0);
539141538Sjhb}
540141538Sjhb
541209371Smavstatic int
542209371Smavlapic_et_stop(struct eventtimer *et)
543209371Smav{
544209371Smav	struct lapic *la = &lapics[lapic_id()];
545209371Smav
546209371Smav	la->la_timer_mode = 0;
547209371Smav	lapic_timer_stop();
548209371Smav	return (0);
549209371Smav}
550209371Smav
551121986Sjhbvoid
552121986Sjhblapic_disable(void)
553121986Sjhb{
554121986Sjhb	uint32_t value;
555121986Sjhb
556121986Sjhb	/* Software disable the local APIC. */
557121986Sjhb	value = lapic->svr;
558121986Sjhb	value &= ~APIC_SVR_SWEN;
559121986Sjhb	lapic->svr = value;
560121986Sjhb}
561121986Sjhb
562139245Sjhbstatic void
563139245Sjhblapic_enable(void)
564139245Sjhb{
565139245Sjhb	u_int32_t value;
566139245Sjhb
567139245Sjhb	/* Program the spurious vector to enable the local APIC. */
568139245Sjhb	value = lapic->svr;
569139245Sjhb	value &= ~(APIC_SVR_VECTOR | APIC_SVR_FOCUS);
570139245Sjhb	value |= (APIC_SVR_FEN | APIC_SVR_SWEN | APIC_SPURIOUS_INT);
571139245Sjhb	lapic->svr = value;
572139245Sjhb}
573139245Sjhb
574163219Sjhb/* Reset the local APIC on the BSP during resume. */
575163219Sjhbstatic void
576163219Sjhblapic_resume(struct pic *pic)
577163219Sjhb{
578163219Sjhb
579163219Sjhb	lapic_setup(0);
580163219Sjhb}
581163219Sjhb
582121986Sjhbint
583121986Sjhblapic_id(void)
584121986Sjhb{
585121986Sjhb
586121986Sjhb	KASSERT(lapic != NULL, ("local APIC is not mapped"));
587121986Sjhb	return (lapic->id >> APIC_ID_SHIFT);
588121986Sjhb}
589121986Sjhb
590121986Sjhbint
591121986Sjhblapic_intr_pending(u_int vector)
592121986Sjhb{
593121986Sjhb	volatile u_int32_t *irr;
594121986Sjhb
595121986Sjhb	/*
596121986Sjhb	 * The IRR registers are an array of 128-bit registers each of
597121986Sjhb	 * which only describes 32 interrupts in the low 32 bits..  Thus,
598121986Sjhb	 * we divide the vector by 32 to get the 128-bit index.  We then
599121986Sjhb	 * multiply that index by 4 to get the equivalent index from
600121986Sjhb	 * treating the IRR as an array of 32-bit registers.  Finally, we
601121986Sjhb	 * modulus the vector by 32 to determine the individual bit to
602121986Sjhb	 * test.
603121986Sjhb	 */
604121986Sjhb	irr = &lapic->irr0;
605121986Sjhb	return (irr[(vector / 32) * 4] & 1 << (vector % 32));
606121986Sjhb}
607121986Sjhb
608121986Sjhbvoid
609121986Sjhblapic_set_logical_id(u_int apic_id, u_int cluster, u_int cluster_id)
610121986Sjhb{
611121986Sjhb	struct lapic *la;
612121986Sjhb
613121986Sjhb	KASSERT(lapics[apic_id].la_present, ("%s: APIC %u doesn't exist",
614121986Sjhb	    __func__, apic_id));
615121986Sjhb	KASSERT(cluster <= APIC_MAX_CLUSTER, ("%s: cluster %u too big",
616121986Sjhb	    __func__, cluster));
617121986Sjhb	KASSERT(cluster_id <= APIC_MAX_INTRACLUSTER_ID,
618121986Sjhb	    ("%s: intra cluster id %u too big", __func__, cluster_id));
619121986Sjhb	la = &lapics[apic_id];
620121986Sjhb	la->la_cluster = cluster;
621121986Sjhb	la->la_cluster_id = cluster_id;
622121986Sjhb}
623121986Sjhb
624121986Sjhbint
625121986Sjhblapic_set_lvt_mask(u_int apic_id, u_int pin, u_char masked)
626121986Sjhb{
627121986Sjhb
628121986Sjhb	if (pin > LVT_MAX)
629121986Sjhb		return (EINVAL);
630121986Sjhb	if (apic_id == APIC_ID_ALL) {
631121986Sjhb		lvts[pin].lvt_masked = masked;
632121986Sjhb		if (bootverbose)
633121986Sjhb			printf("lapic:");
634121986Sjhb	} else {
635121986Sjhb		KASSERT(lapics[apic_id].la_present,
636121986Sjhb		    ("%s: missing APIC %u", __func__, apic_id));
637121986Sjhb		lapics[apic_id].la_lvts[pin].lvt_masked = masked;
638121986Sjhb		lapics[apic_id].la_lvts[pin].lvt_active = 1;
639121986Sjhb		if (bootverbose)
640121986Sjhb			printf("lapic%u:", apic_id);
641121986Sjhb	}
642121986Sjhb	if (bootverbose)
643121986Sjhb		printf(" LINT%u %s\n", pin, masked ? "masked" : "unmasked");
644121986Sjhb	return (0);
645121986Sjhb}
646121986Sjhb
647121986Sjhbint
648121986Sjhblapic_set_lvt_mode(u_int apic_id, u_int pin, u_int32_t mode)
649121986Sjhb{
650121986Sjhb	struct lvt *lvt;
651121986Sjhb
652121986Sjhb	if (pin > LVT_MAX)
653121986Sjhb		return (EINVAL);
654121986Sjhb	if (apic_id == APIC_ID_ALL) {
655121986Sjhb		lvt = &lvts[pin];
656121986Sjhb		if (bootverbose)
657121986Sjhb			printf("lapic:");
658121986Sjhb	} else {
659121986Sjhb		KASSERT(lapics[apic_id].la_present,
660121986Sjhb		    ("%s: missing APIC %u", __func__, apic_id));
661121986Sjhb		lvt = &lapics[apic_id].la_lvts[pin];
662121986Sjhb		lvt->lvt_active = 1;
663121986Sjhb		if (bootverbose)
664121986Sjhb			printf("lapic%u:", apic_id);
665121986Sjhb	}
666121986Sjhb	lvt->lvt_mode = mode;
667121986Sjhb	switch (mode) {
668121986Sjhb	case APIC_LVT_DM_NMI:
669121986Sjhb	case APIC_LVT_DM_SMI:
670121986Sjhb	case APIC_LVT_DM_INIT:
671121986Sjhb	case APIC_LVT_DM_EXTINT:
672121986Sjhb		lvt->lvt_edgetrigger = 1;
673121986Sjhb		lvt->lvt_activehi = 1;
674121986Sjhb		if (mode == APIC_LVT_DM_EXTINT)
675121986Sjhb			lvt->lvt_masked = 1;
676121986Sjhb		else
677121986Sjhb			lvt->lvt_masked = 0;
678121986Sjhb		break;
679121986Sjhb	default:
680121986Sjhb		panic("Unsupported delivery mode: 0x%x\n", mode);
681121986Sjhb	}
682121986Sjhb	if (bootverbose) {
683121986Sjhb		printf(" Routing ");
684121986Sjhb		switch (mode) {
685121986Sjhb		case APIC_LVT_DM_NMI:
686121986Sjhb			printf("NMI");
687121986Sjhb			break;
688121986Sjhb		case APIC_LVT_DM_SMI:
689121986Sjhb			printf("SMI");
690121986Sjhb			break;
691121986Sjhb		case APIC_LVT_DM_INIT:
692121986Sjhb			printf("INIT");
693121986Sjhb			break;
694121986Sjhb		case APIC_LVT_DM_EXTINT:
695121986Sjhb			printf("ExtINT");
696121986Sjhb			break;
697121986Sjhb		}
698121986Sjhb		printf(" -> LINT%u\n", pin);
699121986Sjhb	}
700121986Sjhb	return (0);
701121986Sjhb}
702121986Sjhb
703121986Sjhbint
704128930Sjhblapic_set_lvt_polarity(u_int apic_id, u_int pin, enum intr_polarity pol)
705121986Sjhb{
706121986Sjhb
707128930Sjhb	if (pin > LVT_MAX || pol == INTR_POLARITY_CONFORM)
708121986Sjhb		return (EINVAL);
709121986Sjhb	if (apic_id == APIC_ID_ALL) {
710128930Sjhb		lvts[pin].lvt_activehi = (pol == INTR_POLARITY_HIGH);
711121986Sjhb		if (bootverbose)
712121986Sjhb			printf("lapic:");
713121986Sjhb	} else {
714121986Sjhb		KASSERT(lapics[apic_id].la_present,
715121986Sjhb		    ("%s: missing APIC %u", __func__, apic_id));
716121986Sjhb		lapics[apic_id].la_lvts[pin].lvt_active = 1;
717128930Sjhb		lapics[apic_id].la_lvts[pin].lvt_activehi =
718128930Sjhb		    (pol == INTR_POLARITY_HIGH);
719121986Sjhb		if (bootverbose)
720121986Sjhb			printf("lapic%u:", apic_id);
721121986Sjhb	}
722121986Sjhb	if (bootverbose)
723140254Sjhb		printf(" LINT%u polarity: %s\n", pin,
724128930Sjhb		    pol == INTR_POLARITY_HIGH ? "high" : "low");
725121986Sjhb	return (0);
726121986Sjhb}
727121986Sjhb
728121986Sjhbint
729128930Sjhblapic_set_lvt_triggermode(u_int apic_id, u_int pin, enum intr_trigger trigger)
730121986Sjhb{
731121986Sjhb
732128930Sjhb	if (pin > LVT_MAX || trigger == INTR_TRIGGER_CONFORM)
733121986Sjhb		return (EINVAL);
734121986Sjhb	if (apic_id == APIC_ID_ALL) {
735128930Sjhb		lvts[pin].lvt_edgetrigger = (trigger == INTR_TRIGGER_EDGE);
736121986Sjhb		if (bootverbose)
737121986Sjhb			printf("lapic:");
738121986Sjhb	} else {
739121986Sjhb		KASSERT(lapics[apic_id].la_present,
740121986Sjhb		    ("%s: missing APIC %u", __func__, apic_id));
741128930Sjhb		lapics[apic_id].la_lvts[pin].lvt_edgetrigger =
742128930Sjhb		    (trigger == INTR_TRIGGER_EDGE);
743121986Sjhb		lapics[apic_id].la_lvts[pin].lvt_active = 1;
744121986Sjhb		if (bootverbose)
745121986Sjhb			printf("lapic%u:", apic_id);
746121986Sjhb	}
747121986Sjhb	if (bootverbose)
748121986Sjhb		printf(" LINT%u trigger: %s\n", pin,
749128930Sjhb		    trigger == INTR_TRIGGER_EDGE ? "edge" : "level");
750121986Sjhb	return (0);
751121986Sjhb}
752121986Sjhb
753139240Sjhb/*
754139240Sjhb * Adjust the TPR of the current CPU so that it blocks all interrupts below
755139240Sjhb * the passed in vector.
756139240Sjhb */
757121986Sjhbvoid
758139240Sjhblapic_set_tpr(u_int vector)
759139240Sjhb{
760139240Sjhb#ifdef CHEAP_TPR
761139240Sjhb	lapic->tpr = vector;
762139240Sjhb#else
763139240Sjhb	u_int32_t tpr;
764139240Sjhb
765139240Sjhb	tpr = lapic->tpr & ~APIC_TPR_PRIO;
766139240Sjhb	tpr |= vector;
767139240Sjhb	lapic->tpr = tpr;
768139240Sjhb#endif
769139240Sjhb}
770139240Sjhb
771139240Sjhbvoid
772122572Sjhblapic_eoi(void)
773122572Sjhb{
774122572Sjhb
775122572Sjhb	lapic->eoi = 0;
776122572Sjhb}
777122572Sjhb
778122572Sjhbvoid
779165302Skmacylapic_handle_intr(int vector, struct trapframe *frame)
780121986Sjhb{
781121986Sjhb	struct intsrc *isrc;
782121986Sjhb
783153146Sjhb	if (vector == -1)
784121986Sjhb		panic("Couldn't get vector from ISR!");
785187880Sjeff	isrc = intr_lookup_source(apic_idt_to_irq(PCPU_GET(apic_id),
786187880Sjeff	    vector));
787165302Skmacy	intr_execute_handlers(isrc, frame);
788121986Sjhb}
789121986Sjhb
790141538Sjhbvoid
791165302Skmacylapic_handle_timer(struct trapframe *frame)
792141538Sjhb{
793141538Sjhb	struct lapic *la;
794209371Smav	struct trapframe *oldframe;
795209371Smav	struct thread *td;
796141538Sjhb
797153141Sjhb	/* Send EOI first thing. */
798153141Sjhb	lapic_eoi();
799153141Sjhb
800162708Ssobomax#if defined(SMP) && !defined(SCHED_ULE)
801162042Ssobomax	/*
802162042Ssobomax	 * Don't do any accounting for the disabled HTT cores, since it
803162042Ssobomax	 * will provide misleading numbers for the userland.
804162042Ssobomax	 *
805162042Ssobomax	 * No locking is necessary here, since even if we loose the race
806162042Ssobomax	 * when hlt_cpus_mask changes it is not a big deal, really.
807162713Ssobomax	 *
808162713Ssobomax	 * Don't do that for ULE, since ULE doesn't consider hlt_cpus_mask
809162713Ssobomax	 * and unlike other schedulers it actually schedules threads to
810162713Ssobomax	 * those CPUs.
811162042Ssobomax	 */
812162042Ssobomax	if ((hlt_cpus_mask & (1 << PCPU_GET(cpuid))) != 0)
813162042Ssobomax		return;
814162087Ssobomax#endif
815162042Ssobomax
816153141Sjhb	/* Look up our local APIC structure for the tick counters. */
817141538Sjhb	la = &lapics[PCPU_GET(apic_id)];
818141538Sjhb	(*la->la_timer_count)++;
819141538Sjhb	critical_enter();
820209371Smav	if (lapic_et.et_active) {
821209371Smav		td = curthread;
822210444Smav		td->td_intr_nesting_level++;
823209371Smav		oldframe = td->td_intr_frame;
824209371Smav		td->td_intr_frame = frame;
825209990Smav		lapic_et.et_event_cb(&lapic_et, lapic_et.et_arg);
826209371Smav		td->td_intr_frame = oldframe;
827210444Smav		td->td_intr_nesting_level--;
828209371Smav	}
829141538Sjhb	critical_exit();
830141538Sjhb}
831141538Sjhb
832141538Sjhbstatic void
833141538Sjhblapic_timer_set_divisor(u_int divisor)
834141538Sjhb{
835141538Sjhb
836141538Sjhb	KASSERT(powerof2(divisor), ("lapic: invalid divisor %u", divisor));
837141538Sjhb	KASSERT(ffs(divisor) <= sizeof(lapic_timer_divisors) /
838141538Sjhb	    sizeof(u_int32_t), ("lapic: invalid divisor %u", divisor));
839141538Sjhb	lapic->dcr_timer = lapic_timer_divisors[ffs(divisor) - 1];
840141538Sjhb}
841141538Sjhb
842141538Sjhbstatic void
843141538Sjhblapic_timer_oneshot(u_int count)
844141538Sjhb{
845141538Sjhb	u_int32_t value;
846141538Sjhb
847141538Sjhb	value = lapic->lvt_timer;
848141538Sjhb	value &= ~APIC_LVTT_TM;
849141538Sjhb	value |= APIC_LVTT_TM_ONE_SHOT;
850141538Sjhb	lapic->lvt_timer = value;
851141538Sjhb	lapic->icr_timer = count;
852141538Sjhb}
853141538Sjhb
854141538Sjhbstatic void
855141538Sjhblapic_timer_periodic(u_int count)
856141538Sjhb{
857141538Sjhb	u_int32_t value;
858141538Sjhb
859141538Sjhb	value = lapic->lvt_timer;
860141538Sjhb	value &= ~APIC_LVTT_TM;
861141538Sjhb	value |= APIC_LVTT_TM_PERIODIC;
862141538Sjhb	lapic->lvt_timer = value;
863141538Sjhb	lapic->icr_timer = count;
864141538Sjhb}
865141538Sjhb
866141538Sjhbstatic void
867209371Smavlapic_timer_stop(void)
868209371Smav{
869209371Smav	u_int32_t value;
870209371Smav
871209371Smav	value = lapic->lvt_timer;
872209371Smav	value &= ~APIC_LVTT_TM;
873211756Smav	value |= APIC_LVT_M;
874209371Smav	lapic->lvt_timer = value;
875211756Smav	lapic->icr_timer = 0;
876209371Smav}
877209371Smav
878209371Smavstatic void
879141538Sjhblapic_timer_enable_intr(void)
880141538Sjhb{
881141538Sjhb	u_int32_t value;
882141538Sjhb
883141538Sjhb	value = lapic->lvt_timer;
884141538Sjhb	value &= ~APIC_LVT_M;
885141538Sjhb	lapic->lvt_timer = value;
886141538Sjhb}
887141538Sjhb
888205851Sjhbvoid
889208507Sjhblapic_handle_cmc(void)
890208507Sjhb{
891208507Sjhb
892208507Sjhb	lapic_eoi();
893208507Sjhb	cmc_intr();
894208507Sjhb}
895208507Sjhb
896208507Sjhb/*
897208507Sjhb * Called from the mca_init() to activate the CMC interrupt if this CPU is
898208507Sjhb * responsible for monitoring any MC banks for CMC events.  Since mca_init()
899208507Sjhb * is called prior to lapic_setup() during boot, this just needs to unmask
900208507Sjhb * this CPU's LVT_CMCI entry.
901208507Sjhb */
902208507Sjhbvoid
903208507Sjhblapic_enable_cmc(void)
904208507Sjhb{
905208507Sjhb	u_int apic_id;
906208507Sjhb
907208507Sjhb	apic_id = PCPU_GET(apic_id);
908208507Sjhb	KASSERT(lapics[apic_id].la_present,
909208507Sjhb	    ("%s: missing APIC %u", __func__, apic_id));
910208507Sjhb	lapics[apic_id].la_lvts[LVT_CMCI].lvt_masked = 0;
911208507Sjhb	lapics[apic_id].la_lvts[LVT_CMCI].lvt_active = 1;
912208507Sjhb	if (bootverbose)
913208507Sjhb		printf("lapic%u: CMCI unmasked\n", apic_id);
914208507Sjhb}
915208507Sjhb
916208507Sjhbvoid
917205851Sjhblapic_handle_error(void)
918205851Sjhb{
919205851Sjhb	u_int32_t esr;
920205851Sjhb
921205851Sjhb	/*
922205851Sjhb	 * Read the contents of the error status register.  Write to
923205851Sjhb	 * the register first before reading from it to force the APIC
924205851Sjhb	 * to update its value to indicate any errors that have
925205851Sjhb	 * occurred since the previous write to the register.
926205851Sjhb	 */
927205851Sjhb	lapic->esr = 0;
928205851Sjhb	esr = lapic->esr;
929205851Sjhb
930205851Sjhb	printf("CPU%d: local APIC error 0x%x\n", PCPU_GET(cpuid), esr);
931205851Sjhb	lapic_eoi();
932205851Sjhb}
933205851Sjhb
934187880Sjeffu_int
935187880Sjeffapic_cpuid(u_int apic_id)
936187880Sjeff{
937187880Sjeff#ifdef SMP
938187880Sjeff	return apic_cpuids[apic_id];
939187880Sjeff#else
940187880Sjeff	return 0;
941187880Sjeff#endif
942187880Sjeff}
943187880Sjeff
944151979Sjhb/* Request a free IDT vector to be used by the specified IRQ. */
945121986Sjhbu_int
946187880Sjeffapic_alloc_vector(u_int apic_id, u_int irq)
947121986Sjhb{
948121986Sjhb	u_int vector;
949121986Sjhb
950121986Sjhb	KASSERT(irq < NUM_IO_INTS, ("Invalid IRQ %u", irq));
951151979Sjhb
952151979Sjhb	/*
953151979Sjhb	 * Search for a free vector.  Currently we just use a very simple
954151979Sjhb	 * algorithm to find the first free vector.
955151979Sjhb	 */
956151979Sjhb	mtx_lock_spin(&icu_lock);
957151979Sjhb	for (vector = 0; vector < APIC_NUM_IOINTS; vector++) {
958191720Smav		if (lapics[apic_id].la_ioint_irqs[vector] != -1)
959151979Sjhb			continue;
960187880Sjeff		lapics[apic_id].la_ioint_irqs[vector] = irq;
961151979Sjhb		mtx_unlock_spin(&icu_lock);
962151979Sjhb		return (vector + APIC_IO_INTS);
963151979Sjhb	}
964151979Sjhb	mtx_unlock_spin(&icu_lock);
965195249Sjhb	return (0);
966121986Sjhb}
967121986Sjhb
968164265Sjhb/*
969164265Sjhb * Request 'count' free contiguous IDT vectors to be used by 'count'
970164265Sjhb * IRQs.  'count' must be a power of two and the vectors will be
971164265Sjhb * aligned on a boundary of 'align'.  If the request cannot be
972164265Sjhb * satisfied, 0 is returned.
973164265Sjhb */
974164265Sjhbu_int
975187880Sjeffapic_alloc_vectors(u_int apic_id, u_int *irqs, u_int count, u_int align)
976164265Sjhb{
977164265Sjhb	u_int first, run, vector;
978164265Sjhb
979164265Sjhb	KASSERT(powerof2(count), ("bad count"));
980164265Sjhb	KASSERT(powerof2(align), ("bad align"));
981164265Sjhb	KASSERT(align >= count, ("align < count"));
982164265Sjhb#ifdef INVARIANTS
983164265Sjhb	for (run = 0; run < count; run++)
984164265Sjhb		KASSERT(irqs[run] < NUM_IO_INTS, ("Invalid IRQ %u at index %u",
985164265Sjhb		    irqs[run], run));
986164265Sjhb#endif
987164265Sjhb
988164265Sjhb	/*
989164265Sjhb	 * Search for 'count' free vectors.  As with apic_alloc_vector(),
990164265Sjhb	 * this just uses a simple first fit algorithm.
991164265Sjhb	 */
992164265Sjhb	run = 0;
993164265Sjhb	first = 0;
994164265Sjhb	mtx_lock_spin(&icu_lock);
995164265Sjhb	for (vector = 0; vector < APIC_NUM_IOINTS; vector++) {
996164265Sjhb
997164265Sjhb		/* Vector is in use, end run. */
998191720Smav		if (lapics[apic_id].la_ioint_irqs[vector] != -1) {
999164265Sjhb			run = 0;
1000164265Sjhb			first = 0;
1001164265Sjhb			continue;
1002164265Sjhb		}
1003164265Sjhb
1004164265Sjhb		/* Start a new run if run == 0 and vector is aligned. */
1005164265Sjhb		if (run == 0) {
1006164265Sjhb			if ((vector & (align - 1)) != 0)
1007164265Sjhb				continue;
1008164265Sjhb			first = vector;
1009164265Sjhb		}
1010164265Sjhb		run++;
1011164265Sjhb
1012164265Sjhb		/* Keep looping if the run isn't long enough yet. */
1013164265Sjhb		if (run < count)
1014164265Sjhb			continue;
1015164265Sjhb
1016164265Sjhb		/* Found a run, assign IRQs and return the first vector. */
1017164265Sjhb		for (vector = 0; vector < count; vector++)
1018187880Sjeff			lapics[apic_id].la_ioint_irqs[first + vector] =
1019187880Sjeff			    irqs[vector];
1020164265Sjhb		mtx_unlock_spin(&icu_lock);
1021164265Sjhb		return (first + APIC_IO_INTS);
1022164265Sjhb	}
1023164265Sjhb	mtx_unlock_spin(&icu_lock);
1024164265Sjhb	printf("APIC: Couldn't find APIC vectors for %u IRQs\n", count);
1025164265Sjhb	return (0);
1026164265Sjhb}
1027164265Sjhb
1028187880Sjeff/*
1029187880Sjeff * Enable a vector for a particular apic_id.  Since all lapics share idt
1030187880Sjeff * entries and ioint_handlers this enables the vector on all lapics.  lapics
1031187880Sjeff * which do not have the vector configured would report spurious interrupts
1032187880Sjeff * should it fire.
1033187880Sjeff */
1034151979Sjhbvoid
1035187880Sjeffapic_enable_vector(u_int apic_id, u_int vector)
1036151979Sjhb{
1037151979Sjhb
1038151979Sjhb	KASSERT(vector != IDT_SYSCALL, ("Attempt to overwrite syscall entry"));
1039151979Sjhb	KASSERT(ioint_handlers[vector / 32] != NULL,
1040151979Sjhb	    ("No ISR handler for vector %u", vector));
1041212004Srpaulo#ifdef KDTRACE_HOOKS
1042212004Srpaulo	KASSERT(vector != IDT_DTRACE_RET,
1043212004Srpaulo	    ("Attempt to overwrite DTrace entry"));
1044212004Srpaulo#endif
1045208452Smav	setidt(vector, ioint_handlers[vector / 32], SDT_APIC, SEL_KPL,
1046208452Smav	    GSEL_APIC);
1047151979Sjhb}
1048151979Sjhb
1049169391Sjhbvoid
1050187880Sjeffapic_disable_vector(u_int apic_id, u_int vector)
1051169391Sjhb{
1052169391Sjhb
1053169391Sjhb	KASSERT(vector != IDT_SYSCALL, ("Attempt to overwrite syscall entry"));
1054212004Srpaulo#ifdef KDTRACE_HOOKS
1055212004Srpaulo	KASSERT(vector != IDT_DTRACE_RET,
1056212004Srpaulo	    ("Attempt to overwrite DTrace entry"));
1057212004Srpaulo#endif
1058169391Sjhb	KASSERT(ioint_handlers[vector / 32] != NULL,
1059169391Sjhb	    ("No ISR handler for vector %u", vector));
1060188904Sjeff#ifdef notyet
1061188904Sjeff	/*
1062188904Sjeff	 * We can not currently clear the idt entry because other cpus
1063188904Sjeff	 * may have a valid vector at this offset.
1064188904Sjeff	 */
1065208452Smav	setidt(vector, &IDTVEC(rsvd), SDT_APICT, SEL_KPL, GSEL_APIC);
1066188904Sjeff#endif
1067169391Sjhb}
1068169391Sjhb
1069151979Sjhb/* Release an APIC vector when it's no longer in use. */
1070151979Sjhbvoid
1071187880Sjeffapic_free_vector(u_int apic_id, u_int vector, u_int irq)
1072151979Sjhb{
1073187880Sjeff	struct thread *td;
1074194889Sjhb
1075151979Sjhb	KASSERT(vector >= APIC_IO_INTS && vector != IDT_SYSCALL &&
1076151979Sjhb	    vector <= APIC_IO_INTS + APIC_NUM_IOINTS,
1077151979Sjhb	    ("Vector %u does not map to an IRQ line", vector));
1078151979Sjhb	KASSERT(irq < NUM_IO_INTS, ("Invalid IRQ %u", irq));
1079187880Sjeff	KASSERT(lapics[apic_id].la_ioint_irqs[vector - APIC_IO_INTS] ==
1080187880Sjeff	    irq, ("IRQ mismatch"));
1081212004Srpaulo#ifdef KDTRACE_HOOKS
1082212004Srpaulo	KASSERT(vector != IDT_DTRACE_RET,
1083212004Srpaulo	    ("Attempt to overwrite DTrace entry"));
1084212004Srpaulo#endif
1085187880Sjeff
1086187880Sjeff	/*
1087187880Sjeff	 * Bind us to the cpu that owned the vector before freeing it so
1088187880Sjeff	 * we don't lose an interrupt delivery race.
1089187880Sjeff	 */
1090187880Sjeff	td = curthread;
1091196745Sjhb	if (!rebooting) {
1092196745Sjhb		thread_lock(td);
1093196745Sjhb		if (sched_is_bound(td))
1094196745Sjhb			panic("apic_free_vector: Thread already bound.\n");
1095196745Sjhb		sched_bind(td, apic_cpuid(apic_id));
1096196745Sjhb		thread_unlock(td);
1097196745Sjhb	}
1098151979Sjhb	mtx_lock_spin(&icu_lock);
1099191720Smav	lapics[apic_id].la_ioint_irqs[vector - APIC_IO_INTS] = -1;
1100151979Sjhb	mtx_unlock_spin(&icu_lock);
1101196745Sjhb	if (!rebooting) {
1102196745Sjhb		thread_lock(td);
1103196745Sjhb		sched_unbind(td);
1104196745Sjhb		thread_unlock(td);
1105196745Sjhb	}
1106151979Sjhb}
1107151979Sjhb
1108151979Sjhb/* Map an IDT vector (APIC) to an IRQ (interrupt source). */
1109121986Sjhbu_int
1110187880Sjeffapic_idt_to_irq(u_int apic_id, u_int vector)
1111121986Sjhb{
1112191730Smav	int irq;
1113121986Sjhb
1114122690Sjhb	KASSERT(vector >= APIC_IO_INTS && vector != IDT_SYSCALL &&
1115151979Sjhb	    vector <= APIC_IO_INTS + APIC_NUM_IOINTS,
1116121986Sjhb	    ("Vector %u does not map to an IRQ line", vector));
1117212004Srpaulo#ifdef KDTRACE_HOOKS
1118212004Srpaulo	KASSERT(vector != IDT_DTRACE_RET,
1119212004Srpaulo	    ("Attempt to overwrite DTrace entry"));
1120212004Srpaulo#endif
1121191730Smav	irq = lapics[apic_id].la_ioint_irqs[vector - APIC_IO_INTS];
1122191730Smav	if (irq < 0)
1123191730Smav		irq = 0;
1124191730Smav	return (irq);
1125121986Sjhb}
1126121986Sjhb
1127151979Sjhb#ifdef DDB
1128121986Sjhb/*
1129151979Sjhb * Dump data about APIC IDT vector mappings.
1130151979Sjhb */
1131151979SjhbDB_SHOW_COMMAND(apic, db_show_apic)
1132151979Sjhb{
1133151979Sjhb	struct intsrc *isrc;
1134160312Sjhb	int i, verbose;
1135187880Sjeff	u_int apic_id;
1136151979Sjhb	u_int irq;
1137151979Sjhb
1138151979Sjhb	if (strcmp(modif, "vv") == 0)
1139151979Sjhb		verbose = 2;
1140151979Sjhb	else if (strcmp(modif, "v") == 0)
1141151979Sjhb		verbose = 1;
1142151979Sjhb	else
1143151979Sjhb		verbose = 0;
1144187880Sjeff	for (apic_id = 0; apic_id <= MAX_APIC_ID; apic_id++) {
1145187880Sjeff		if (lapics[apic_id].la_present == 0)
1146187880Sjeff			continue;
1147187880Sjeff		db_printf("Interrupts bound to lapic %u\n", apic_id);
1148187880Sjeff		for (i = 0; i < APIC_NUM_IOINTS + 1 && !db_pager_quit; i++) {
1149187880Sjeff			irq = lapics[apic_id].la_ioint_irqs[i];
1150191720Smav			if (irq == -1 || irq == IRQ_SYSCALL)
1151187880Sjeff				continue;
1152212004Srpaulo#ifdef KDTRACE_HOOKS
1153212004Srpaulo			if (irq == IRQ_DTRACE_RET)
1154212004Srpaulo				continue;
1155212004Srpaulo#endif
1156151979Sjhb			db_printf("vec 0x%2x -> ", i + APIC_IO_INTS);
1157151979Sjhb			if (irq == IRQ_TIMER)
1158151979Sjhb				db_printf("lapic timer\n");
1159151979Sjhb			else if (irq < NUM_IO_INTS) {
1160151979Sjhb				isrc = intr_lookup_source(irq);
1161151979Sjhb				if (isrc == NULL || verbose == 0)
1162151979Sjhb					db_printf("IRQ %u\n", irq);
1163151979Sjhb				else
1164151979Sjhb					db_dump_intr_event(isrc->is_event,
1165151979Sjhb					    verbose == 2);
1166151979Sjhb			} else
1167151979Sjhb				db_printf("IRQ %u ???\n", irq);
1168151979Sjhb		}
1169151979Sjhb	}
1170151979Sjhb}
1171162233Sjhb
1172162233Sjhbstatic void
1173162233Sjhbdump_mask(const char *prefix, uint32_t v, int base)
1174162233Sjhb{
1175162233Sjhb	int i, first;
1176162233Sjhb
1177162233Sjhb	first = 1;
1178162233Sjhb	for (i = 0; i < 32; i++)
1179162233Sjhb		if (v & (1 << i)) {
1180162233Sjhb			if (first) {
1181162233Sjhb				db_printf("%s:", prefix);
1182162233Sjhb				first = 0;
1183162233Sjhb			}
1184162233Sjhb			db_printf(" %02x", base + i);
1185162233Sjhb		}
1186162233Sjhb	if (!first)
1187162233Sjhb		db_printf("\n");
1188162233Sjhb}
1189162233Sjhb
1190162233Sjhb/* Show info from the lapic regs for this CPU. */
1191162233SjhbDB_SHOW_COMMAND(lapic, db_show_lapic)
1192162233Sjhb{
1193162233Sjhb	uint32_t v;
1194162233Sjhb
1195162233Sjhb	db_printf("lapic ID = %d\n", lapic_id());
1196162233Sjhb	v = lapic->version;
1197162233Sjhb	db_printf("version  = %d.%d\n", (v & APIC_VER_VERSION) >> 4,
1198162233Sjhb	    v & 0xf);
1199162233Sjhb	db_printf("max LVT  = %d\n", (v & APIC_VER_MAXLVT) >> MAXLVTSHIFT);
1200162233Sjhb	v = lapic->svr;
1201162233Sjhb	db_printf("SVR      = %02x (%s)\n", v & APIC_SVR_VECTOR,
1202162233Sjhb	    v & APIC_SVR_ENABLE ? "enabled" : "disabled");
1203162233Sjhb	db_printf("TPR      = %02x\n", lapic->tpr);
1204162233Sjhb
1205162233Sjhb#define dump_field(prefix, index)					\
1206162233Sjhb	dump_mask(__XSTRING(prefix ## index), lapic->prefix ## index,	\
1207162233Sjhb	    index * 32)
1208162233Sjhb
1209162233Sjhb	db_printf("In-service Interrupts:\n");
1210162233Sjhb	dump_field(isr, 0);
1211162233Sjhb	dump_field(isr, 1);
1212162233Sjhb	dump_field(isr, 2);
1213162233Sjhb	dump_field(isr, 3);
1214162233Sjhb	dump_field(isr, 4);
1215162233Sjhb	dump_field(isr, 5);
1216162233Sjhb	dump_field(isr, 6);
1217162233Sjhb	dump_field(isr, 7);
1218162233Sjhb
1219162233Sjhb	db_printf("TMR Interrupts:\n");
1220162233Sjhb	dump_field(tmr, 0);
1221162233Sjhb	dump_field(tmr, 1);
1222162233Sjhb	dump_field(tmr, 2);
1223162233Sjhb	dump_field(tmr, 3);
1224162233Sjhb	dump_field(tmr, 4);
1225162233Sjhb	dump_field(tmr, 5);
1226162233Sjhb	dump_field(tmr, 6);
1227162233Sjhb	dump_field(tmr, 7);
1228162233Sjhb
1229162233Sjhb	db_printf("IRR Interrupts:\n");
1230162233Sjhb	dump_field(irr, 0);
1231162233Sjhb	dump_field(irr, 1);
1232162233Sjhb	dump_field(irr, 2);
1233162233Sjhb	dump_field(irr, 3);
1234162233Sjhb	dump_field(irr, 4);
1235162233Sjhb	dump_field(irr, 5);
1236162233Sjhb	dump_field(irr, 6);
1237162233Sjhb	dump_field(irr, 7);
1238162233Sjhb
1239162233Sjhb#undef dump_field
1240162233Sjhb}
1241151979Sjhb#endif
1242151979Sjhb
1243151979Sjhb/*
1244121986Sjhb * APIC probing support code.  This includes code to manage enumerators.
1245121986Sjhb */
1246121986Sjhb
1247121986Sjhbstatic SLIST_HEAD(, apic_enumerator) enumerators =
1248121986Sjhb	SLIST_HEAD_INITIALIZER(enumerators);
1249121986Sjhbstatic struct apic_enumerator *best_enum;
1250195249Sjhb
1251121986Sjhbvoid
1252121986Sjhbapic_register_enumerator(struct apic_enumerator *enumerator)
1253121986Sjhb{
1254121986Sjhb#ifdef INVARIANTS
1255121986Sjhb	struct apic_enumerator *apic_enum;
1256121986Sjhb
1257121986Sjhb	SLIST_FOREACH(apic_enum, &enumerators, apic_next) {
1258121986Sjhb		if (apic_enum == enumerator)
1259121986Sjhb			panic("%s: Duplicate register of %s", __func__,
1260121986Sjhb			    enumerator->apic_name);
1261121986Sjhb	}
1262121986Sjhb#endif
1263121986Sjhb	SLIST_INSERT_HEAD(&enumerators, enumerator, apic_next);
1264121986Sjhb}
1265121986Sjhb
1266121986Sjhb/*
1267208479Smav * We have to look for CPU's very, very early because certain subsystems
1268208479Smav * want to know how many CPU's we have extremely early on in the boot
1269208479Smav * process.
1270121986Sjhb */
1271121986Sjhbstatic void
1272121986Sjhbapic_init(void *dummy __unused)
1273121986Sjhb{
1274121986Sjhb	struct apic_enumerator *enumerator;
1275208452Smav#ifndef __amd64__
1276123133Sjhb	uint64_t apic_base;
1277208452Smav#endif
1278121986Sjhb	int retval, best;
1279121986Sjhb
1280153383Sjhb	/* We only support built in local APICs. */
1281153383Sjhb	if (!(cpu_feature & CPUID_APIC))
1282121986Sjhb		return;
1283121986Sjhb
1284123133Sjhb	/* Don't probe if APIC mode is disabled. */
1285123133Sjhb	if (resource_disabled("apic", 0))
1286123133Sjhb		return;
1287123133Sjhb
1288215009Sjhb	/* Probe all the enumerators to find the best match. */
1289121986Sjhb	best_enum = NULL;
1290121986Sjhb	best = 0;
1291121986Sjhb	SLIST_FOREACH(enumerator, &enumerators, apic_next) {
1292121986Sjhb		retval = enumerator->apic_probe();
1293121986Sjhb		if (retval > 0)
1294121986Sjhb			continue;
1295121986Sjhb		if (best_enum == NULL || best < retval) {
1296121986Sjhb			best_enum = enumerator;
1297121986Sjhb			best = retval;
1298121986Sjhb		}
1299121986Sjhb	}
1300121986Sjhb	if (best_enum == NULL) {
1301121986Sjhb		if (bootverbose)
1302121986Sjhb			printf("APIC: Could not find any APICs.\n");
1303121986Sjhb		return;
1304121986Sjhb	}
1305121986Sjhb
1306121986Sjhb	if (bootverbose)
1307121986Sjhb		printf("APIC: Using the %s enumerator.\n",
1308121986Sjhb		    best_enum->apic_name);
1309121986Sjhb
1310208452Smav#ifndef __amd64__
1311121986Sjhb	/*
1312121986Sjhb	 * To work around an errata, we disable the local APIC on some
1313121986Sjhb	 * CPUs during early startup.  We need to turn the local APIC back
1314121986Sjhb	 * on on such CPUs now.
1315121986Sjhb	 */
1316185341Sjkim	if (cpu == CPU_686 && cpu_vendor_id == CPU_VENDOR_INTEL &&
1317121986Sjhb	    (cpu_id & 0xff0) == 0x610) {
1318121986Sjhb		apic_base = rdmsr(MSR_APICBASE);
1319121986Sjhb		apic_base |= APICBASE_ENABLED;
1320121986Sjhb		wrmsr(MSR_APICBASE, apic_base);
1321121986Sjhb	}
1322208452Smav#endif
1323123133Sjhb
1324215009Sjhb	/* Probe the CPU's in the system. */
1325123133Sjhb	retval = best_enum->apic_probe_cpus();
1326123133Sjhb	if (retval != 0)
1327123133Sjhb		printf("%s: Failed to probe CPUs: returned %d\n",
1328123133Sjhb		    best_enum->apic_name, retval);
1329123133Sjhb
1330208479Smav}
1331208479SmavSYSINIT(apic_init, SI_SUB_TUNABLES - 1, SI_ORDER_SECOND, apic_init, NULL);
1332208479Smav
1333208479Smav/*
1334208479Smav * Setup the local APIC.  We have to do this prior to starting up the APs
1335208479Smav * in the SMP case.
1336208479Smav */
1337208479Smavstatic void
1338208479Smavapic_setup_local(void *dummy __unused)
1339208479Smav{
1340208479Smav	int retval;
1341208479Smav
1342208479Smav	if (best_enum == NULL)
1343208479Smav		return;
1344215009Sjhb
1345215009Sjhb	/* Initialize the local APIC. */
1346121986Sjhb	retval = best_enum->apic_setup_local();
1347121986Sjhb	if (retval != 0)
1348121986Sjhb		printf("%s: Failed to setup the local APIC: returned %d\n",
1349121986Sjhb		    best_enum->apic_name, retval);
1350121986Sjhb}
1351215009SjhbSYSINIT(apic_setup_local, SI_SUB_CPU, SI_ORDER_SECOND, apic_setup_local, NULL);
1352121986Sjhb
1353121986Sjhb/*
1354121986Sjhb * Setup the I/O APICs.
1355121986Sjhb */
1356121986Sjhbstatic void
1357121986Sjhbapic_setup_io(void *dummy __unused)
1358121986Sjhb{
1359121986Sjhb	int retval;
1360121986Sjhb
1361121986Sjhb	if (best_enum == NULL)
1362121986Sjhb		return;
1363121986Sjhb	retval = best_enum->apic_setup_io();
1364121986Sjhb	if (retval != 0)
1365121986Sjhb		printf("%s: Failed to setup I/O APICs: returned %d\n",
1366121986Sjhb		    best_enum->apic_name, retval);
1367121986Sjhb
1368182902Skmacy#ifdef XEN
1369182902Skmacy	return;
1370182902Skmacy#endif
1371121986Sjhb	/*
1372121986Sjhb	 * Finish setting up the local APIC on the BSP once we know how to
1373121986Sjhb	 * properly program the LINT pins.
1374121986Sjhb	 */
1375163219Sjhb	lapic_setup(1);
1376163219Sjhb	intr_register_pic(&lapic_pic);
1377121986Sjhb	if (bootverbose)
1378121986Sjhb		lapic_dump("BSP");
1379164265Sjhb
1380164265Sjhb	/* Enable the MSI "pic". */
1381164265Sjhb	msi_init();
1382121986Sjhb}
1383177253SrwatsonSYSINIT(apic_setup_io, SI_SUB_INTR, SI_ORDER_SECOND, apic_setup_io, NULL);
1384121986Sjhb
1385121986Sjhb#ifdef SMP
1386121986Sjhb/*
1387121986Sjhb * Inter Processor Interrupt functions.  The lapic_ipi_*() functions are
1388208452Smav * private to the MD code.  The public interface for the rest of the
1389121986Sjhb * kernel is defined in mp_machdep.c.
1390121986Sjhb */
1391121986Sjhbint
1392121986Sjhblapic_ipi_wait(int delay)
1393121986Sjhb{
1394121986Sjhb	int x, incr;
1395121986Sjhb
1396121986Sjhb	/*
1397121986Sjhb	 * Wait delay loops for IPI to be sent.  This is highly bogus
1398121986Sjhb	 * since this is sensitive to CPU clock speed.  If delay is
1399121986Sjhb	 * -1, we wait forever.
1400121986Sjhb	 */
1401121986Sjhb	if (delay == -1) {
1402121986Sjhb		incr = 0;
1403121986Sjhb		delay = 1;
1404121986Sjhb	} else
1405121986Sjhb		incr = 1;
1406121986Sjhb	for (x = 0; x < delay; x += incr) {
1407121986Sjhb		if ((lapic->icr_lo & APIC_DELSTAT_MASK) == APIC_DELSTAT_IDLE)
1408121986Sjhb			return (1);
1409121986Sjhb		ia32_pause();
1410121986Sjhb	}
1411121986Sjhb	return (0);
1412121986Sjhb}
1413121986Sjhb
1414121986Sjhbvoid
1415121986Sjhblapic_ipi_raw(register_t icrlo, u_int dest)
1416121986Sjhb{
1417214347Sjhb	register_t value, saveintr;
1418121986Sjhb
1419121986Sjhb	/* XXX: Need more sanity checking of icrlo? */
1420121986Sjhb	KASSERT(lapic != NULL, ("%s called too early", __func__));
1421121986Sjhb	KASSERT((dest & ~(APIC_ID_MASK >> APIC_ID_SHIFT)) == 0,
1422121986Sjhb	    ("%s: invalid dest field", __func__));
1423121986Sjhb	KASSERT((icrlo & APIC_ICRLO_RESV_MASK) == 0,
1424121986Sjhb	    ("%s: reserved bits set in ICR LO register", __func__));
1425121986Sjhb
1426121986Sjhb	/* Set destination in ICR HI register if it is being used. */
1427214347Sjhb	saveintr = intr_disable();
1428121986Sjhb	if ((icrlo & APIC_DEST_MASK) == APIC_DEST_DESTFLD) {
1429121986Sjhb		value = lapic->icr_hi;
1430121986Sjhb		value &= ~APIC_ID_MASK;
1431121986Sjhb		value |= dest << APIC_ID_SHIFT;
1432121986Sjhb		lapic->icr_hi = value;
1433121986Sjhb	}
1434121986Sjhb
1435121986Sjhb	/* Program the contents of the IPI and dispatch it. */
1436121986Sjhb	value = lapic->icr_lo;
1437121986Sjhb	value &= APIC_ICRLO_RESV_MASK;
1438121986Sjhb	value |= icrlo;
1439121986Sjhb	lapic->icr_lo = value;
1440214347Sjhb	intr_restore(saveintr);
1441121986Sjhb}
1442121986Sjhb
1443125317Sjeff#define	BEFORE_SPIN	1000000
1444121986Sjhb#ifdef DETECT_DEADLOCK
1445121986Sjhb#define	AFTER_SPIN	1000
1446121986Sjhb#endif
1447121986Sjhb
1448121986Sjhbvoid
1449121986Sjhblapic_ipi_vectored(u_int vector, int dest)
1450121986Sjhb{
1451121986Sjhb	register_t icrlo, destfield;
1452121986Sjhb
1453121986Sjhb	KASSERT((vector & ~APIC_VECTOR_MASK) == 0,
1454121986Sjhb	    ("%s: invalid vector %d", __func__, vector));
1455121986Sjhb
1456196196Sattilio	icrlo = APIC_DESTMODE_PHY | APIC_TRIGMOD_EDGE;
1457196196Sattilio
1458196196Sattilio	/*
1459196196Sattilio	 * IPI_STOP_HARD is just a "fake" vector used to send a NMI.
1460196196Sattilio	 * Use special rules regard NMI if passed, otherwise specify
1461196196Sattilio	 * the vector.
1462196196Sattilio	 */
1463196196Sattilio	if (vector == IPI_STOP_HARD)
1464196196Sattilio		icrlo |= APIC_DELMODE_NMI | APIC_LEVEL_ASSERT;
1465196196Sattilio	else
1466196196Sattilio		icrlo |= vector | APIC_DELMODE_FIXED | APIC_LEVEL_DEASSERT;
1467121986Sjhb	destfield = 0;
1468121986Sjhb	switch (dest) {
1469121986Sjhb	case APIC_IPI_DEST_SELF:
1470121986Sjhb		icrlo |= APIC_DEST_SELF;
1471121986Sjhb		break;
1472121986Sjhb	case APIC_IPI_DEST_ALL:
1473121986Sjhb		icrlo |= APIC_DEST_ALLISELF;
1474121986Sjhb		break;
1475121986Sjhb	case APIC_IPI_DEST_OTHERS:
1476121986Sjhb		icrlo |= APIC_DEST_ALLESELF;
1477121986Sjhb		break;
1478121986Sjhb	default:
1479121986Sjhb		KASSERT((dest & ~(APIC_ID_MASK >> APIC_ID_SHIFT)) == 0,
1480121986Sjhb		    ("%s: invalid destination 0x%x", __func__, dest));
1481121986Sjhb		destfield = dest;
1482121986Sjhb	}
1483121986Sjhb
1484125317Sjeff	/* Wait for an earlier IPI to finish. */
1485150176Sjhb	if (!lapic_ipi_wait(BEFORE_SPIN)) {
1486150176Sjhb		if (panicstr != NULL)
1487150176Sjhb			return;
1488150176Sjhb		else
1489150176Sjhb			panic("APIC: Previous IPI is stuck");
1490150176Sjhb	}
1491121986Sjhb
1492121986Sjhb	lapic_ipi_raw(icrlo, destfield);
1493121986Sjhb
1494121986Sjhb#ifdef DETECT_DEADLOCK
1495121986Sjhb	/* Wait for IPI to be delivered. */
1496121986Sjhb	if (!lapic_ipi_wait(AFTER_SPIN)) {
1497121986Sjhb#ifdef needsattention
1498121986Sjhb		/*
1499121986Sjhb		 * XXX FIXME:
1500121986Sjhb		 *
1501121986Sjhb		 * The above function waits for the message to actually be
1502121986Sjhb		 * delivered.  It breaks out after an arbitrary timeout
1503121986Sjhb		 * since the message should eventually be delivered (at
1504121986Sjhb		 * least in theory) and that if it wasn't we would catch
1505121986Sjhb		 * the failure with the check above when the next IPI is
1506121986Sjhb		 * sent.
1507121986Sjhb		 *
1508139240Sjhb		 * We could skip this wait entirely, EXCEPT it probably
1509121986Sjhb		 * protects us from other routines that assume that the
1510121986Sjhb		 * message was delivered and acted upon when this function
1511121986Sjhb		 * returns.
1512121986Sjhb		 */
1513121986Sjhb		printf("APIC: IPI might be stuck\n");
1514121986Sjhb#else /* !needsattention */
1515121986Sjhb		/* Wait until mesage is sent without a timeout. */
1516121986Sjhb		while (lapic->icr_lo & APIC_DELSTAT_PEND)
1517121986Sjhb			ia32_pause();
1518121986Sjhb#endif /* needsattention */
1519121986Sjhb	}
1520121986Sjhb#endif /* DETECT_DEADLOCK */
1521121986Sjhb}
1522121986Sjhb#endif /* SMP */
1523