1119452Sobrien/*-
2121991Sjhb * Copyright (c) 2003 John Baldwin <jhb@FreeBSD.org>
325164Speter * Copyright (c) 1996, by Steve Passe
425164Speter * All rights reserved.
525164Speter *
625164Speter * Redistribution and use in source and binary forms, with or without
725164Speter * modification, are permitted provided that the following conditions
825164Speter * are met:
925164Speter * 1. Redistributions of source code must retain the above copyright
1025164Speter *    notice, this list of conditions and the following disclaimer.
1125164Speter * 2. The name of the developer may NOT be used to endorse or promote products
1225164Speter *    derived from this software without specific prior written permission.
1325164Speter *
1425164Speter * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
1525164Speter * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
1625164Speter * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
1725164Speter * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
1825164Speter * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
1925164Speter * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
2025164Speter * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
2125164Speter * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
2225164Speter * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
2325164Speter * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
2425164Speter * SUCH DAMAGE.
2525164Speter */
2625164Speter
27115683Sobrien#include <sys/cdefs.h>
28115683Sobrien__FBSDID("$FreeBSD: releng/10.3/sys/x86/x86/mptable.c 262141 2014-02-18 01:15:32Z jhb $");
29115683Sobrien
30122490Sjhb#include "opt_mptable_force_htt.h"
3128743Sbde#include <sys/param.h>
3276166Smarkm#include <sys/systm.h>
3365557Sjasone#include <sys/bus.h>
3428808Speter#include <sys/kernel.h>
35224069Sjhb#include <sys/limits.h>
3646703Speter#include <sys/malloc.h>
37224069Sjhb#ifdef NEW_PCIB
38224069Sjhb#include <sys/rman.h>
39224069Sjhb#endif
4025164Speter
4128808Speter#include <vm/vm.h>
4228808Speter#include <vm/vm_param.h>
4328808Speter#include <vm/pmap.h>
4425164Speter
45224069Sjhb#include <dev/pci/pcivar.h>
46224069Sjhb#ifdef NEW_PCIB
47224069Sjhb#include <dev/pci/pcib_private.h>
48224069Sjhb#endif
49214631Sjhb#include <x86/apicreg.h>
50215051Sattilio#include <x86/mptable.h>
51121991Sjhb#include <machine/frame.h>
52121991Sjhb#include <machine/intr_machdep.h>
53121991Sjhb#include <machine/apicvar.h>
54121991Sjhb#include <machine/md_var.h>
55224069Sjhb#ifdef NEW_PCIB
56224069Sjhb#include <machine/resource.h>
57224069Sjhb#endif
5826896Stegge#include <machine/specialreg.h>
5925164Speter
60121991Sjhb/* string defined by the Intel MP Spec as identifying the MP table */
61121991Sjhb#define	MP_SIG			0x5f504d5f	/* _MP_ */
6225164Speter
63214446Sattilio#ifdef __amd64__
64214446Sattilio#define	MAX_LAPIC_ID		63	/* Max local APIC ID for HTT fixup */
65214446Sattilio#else
66169395Sjhb#define	MAX_LAPIC_ID		31	/* Max local APIC ID for HTT fixup */
67214446Sattilio#endif
68121991Sjhb
6940067Skato#ifdef PC98
7040067Skato#define BIOS_BASE		(0xe8000)
7140067Skato#define BIOS_SIZE		(0x18000)
7240067Skato#else
7327005Sfsmp#define BIOS_BASE		(0xf0000)
7427005Sfsmp#define BIOS_SIZE		(0x10000)
7540067Skato#endif
7627005Sfsmp#define BIOS_COUNT		(BIOS_SIZE/4)
7725164Speter
78121991Sjhbtypedef	void mptable_entry_handler(u_char *entry, void *arg);
79224069Sjhbtypedef	void mptable_extended_entry_handler(ext_entry_ptr entry, void *arg);
8025164Speter
81121991Sjhbstatic basetable_entry basetable_entry_types[] =
82121991Sjhb{
83121991Sjhb	{0, 20, "Processor"},
84121991Sjhb	{1, 8, "Bus"},
85121991Sjhb	{2, 8, "I/O APIC"},
86121991Sjhb	{3, 8, "I/O INT"},
87121991Sjhb	{4, 8, "Local INT"}
88121991Sjhb};
8926155Sfsmp
90121991Sjhbtypedef struct BUSDATA {
9126155Sfsmp	u_char  bus_id;
92121991Sjhb	enum busTypes bus_type;
93121991Sjhb}       bus_datum;
9426155Sfsmp
95121991Sjhbtypedef struct INTDATA {
9626155Sfsmp	u_char  int_type;
9726155Sfsmp	u_short int_flags;
9826155Sfsmp	u_char  src_bus_id;
9926155Sfsmp	u_char  src_bus_irq;
10026155Sfsmp	u_char  dst_apic_id;
10126155Sfsmp	u_char  dst_apic_int;
102121991Sjhb	u_char	int_vector;
103121991Sjhb}       io_int, local_int;
10426155Sfsmp
105121991Sjhbtypedef struct BUSTYPENAME {
10626155Sfsmp	u_char  type;
107121991Sjhb	char    name[7];
108121991Sjhb}       bus_type_name;
10926155Sfsmp
110121991Sjhb/* From MP spec v1.4, table 4-8. */
111121991Sjhbstatic bus_type_name bus_type_table[] =
112121991Sjhb{
113121991Sjhb	{UNKNOWN_BUSTYPE, "CBUS  "},
114121991Sjhb	{UNKNOWN_BUSTYPE, "CBUSII"},
115121991Sjhb	{EISA, "EISA  "},
116121991Sjhb	{UNKNOWN_BUSTYPE, "FUTURE"},
117121991Sjhb	{UNKNOWN_BUSTYPE, "INTERN"},
118121991Sjhb	{ISA, "ISA   "},
119121991Sjhb	{UNKNOWN_BUSTYPE, "MBI   "},
120121991Sjhb	{UNKNOWN_BUSTYPE, "MBII  "},
121121991Sjhb	{MCA, "MCA   "},
122121991Sjhb	{UNKNOWN_BUSTYPE, "MPI   "},
123121991Sjhb	{UNKNOWN_BUSTYPE, "MPSA  "},
124121991Sjhb	{UNKNOWN_BUSTYPE, "NUBUS "},
125121991Sjhb	{PCI, "PCI   "},
126121991Sjhb	{UNKNOWN_BUSTYPE, "PCMCIA"},
127121991Sjhb	{UNKNOWN_BUSTYPE, "TC    "},
128121991Sjhb	{UNKNOWN_BUSTYPE, "VL    "},
129121991Sjhb	{UNKNOWN_BUSTYPE, "VME   "},
130121991Sjhb	{UNKNOWN_BUSTYPE, "XPRESS"}
131121991Sjhb};
13225164Speter
133121991Sjhb/* From MP spec v1.4, table 5-1. */
134121991Sjhbstatic int default_data[7][5] =
135121991Sjhb{
136121991Sjhb/*   nbus, id0, type0, id1, type1 */
137121991Sjhb	{1, 0, ISA, 255, NOBUS},
138121991Sjhb	{1, 0, EISA, 255, NOBUS},
139121991Sjhb	{1, 0, EISA, 255, NOBUS},
140121991Sjhb	{1, 0, MCA, 255, NOBUS},
141121991Sjhb	{2, 0, ISA, 1, PCI},
142121991Sjhb	{2, 0, EISA, 1, PCI},
143121991Sjhb	{2, 0, MCA, 1, PCI}
144121991Sjhb};
14525164Speter
146121991Sjhbstruct pci_probe_table_args {
147121991Sjhb	u_char bus;
148121991Sjhb	u_char found;
149121991Sjhb};
15025164Speter
151121991Sjhbstruct pci_route_interrupt_args {
152121991Sjhb	u_char bus;		/* Source bus. */
153121991Sjhb	u_char irq;		/* Source slot:pin. */
154121991Sjhb	int vector;		/* Return value. */
155121991Sjhb};
15625164Speter
157121991Sjhbstatic mpfps_t mpfps;
158121991Sjhbstatic mpcth_t mpct;
159224069Sjhbstatic ext_entry_ptr mpet;
160169395Sjhbstatic void *ioapics[MAX_APIC_ID + 1];
161121991Sjhbstatic bus_datum *busses;
162121991Sjhbstatic int mptable_nioapics, mptable_nbusses, mptable_maxbusid;
163121991Sjhbstatic int pci0 = -1;
16425164Speter
165151897Srwatsonstatic MALLOC_DEFINE(M_MPTABLE, "mptable", "MP Table Items");
16625164Speter
167128930Sjhbstatic enum intr_polarity conforming_polarity(u_char src_bus,
168128930Sjhb	    u_char src_bus_irq);
169128930Sjhbstatic enum intr_trigger conforming_trigger(u_char src_bus, u_char src_bus_irq);
170128930Sjhbstatic enum intr_polarity intentry_polarity(int_entry_ptr intr);
171128930Sjhbstatic enum intr_trigger intentry_trigger(int_entry_ptr intr);
172121991Sjhbstatic int	lookup_bus_type(char *name);
173121991Sjhbstatic void	mptable_count_items(void);
174121991Sjhbstatic void	mptable_count_items_handler(u_char *entry, void *arg);
175122490Sjhb#ifdef MPTABLE_FORCE_HTT
176121991Sjhbstatic void	mptable_hyperthread_fixup(u_int id_mask);
177122490Sjhb#endif
178121991Sjhbstatic void	mptable_parse_apics_and_busses(void);
179121991Sjhbstatic void	mptable_parse_apics_and_busses_handler(u_char *entry,
180121991Sjhb    void *arg);
181139864Sjhbstatic void	mptable_parse_default_config_ints(void);
182121991Sjhbstatic void	mptable_parse_ints(void);
183121991Sjhbstatic void	mptable_parse_ints_handler(u_char *entry, void *arg);
184121991Sjhbstatic void	mptable_parse_io_int(int_entry_ptr intr);
185121991Sjhbstatic void	mptable_parse_local_int(int_entry_ptr intr);
186121991Sjhbstatic void	mptable_pci_probe_table_handler(u_char *entry, void *arg);
187121991Sjhbstatic void	mptable_pci_route_interrupt_handler(u_char *entry, void *arg);
188121991Sjhbstatic void	mptable_pci_setup(void);
189121991Sjhbstatic int	mptable_probe(void);
190121991Sjhbstatic int	mptable_probe_cpus(void);
191121991Sjhbstatic void	mptable_probe_cpus_handler(u_char *entry, void *arg __unused);
192121991Sjhbstatic void	mptable_register(void *dummy);
193121991Sjhbstatic int	mptable_setup_local(void);
194121991Sjhbstatic int	mptable_setup_io(void);
195224096Sjhb#ifdef NEW_PCIB
196224069Sjhbstatic void	mptable_walk_extended_table(
197224069Sjhb    mptable_extended_entry_handler *handler, void *arg);
198224096Sjhb#endif
199121991Sjhbstatic void	mptable_walk_table(mptable_entry_handler *handler, void *arg);
20026155Sfsmpstatic int	search_for_sig(u_int32_t target, int count);
20125164Speter
202121991Sjhbstatic struct apic_enumerator mptable_enumerator = {
203121991Sjhb	"MPTable",
204121991Sjhb	mptable_probe,
205121991Sjhb	mptable_probe_cpus,
206121991Sjhb	mptable_setup_local,
207121991Sjhb	mptable_setup_io
208121991Sjhb};
20925164Speter
21025164Speter/*
211121991Sjhb * look for the MP spec signature
21271525Sjhb */
21371525Sjhb
214121991Sjhbstatic int
215121991Sjhbsearch_for_sig(u_int32_t target, int count)
21671525Sjhb{
217121991Sjhb	int     x;
218121991Sjhb	u_int32_t *addr = (u_int32_t *) (KERNBASE + target);
21971525Sjhb
220121991Sjhb	for (x = 0; x < count; x += 4)
221121991Sjhb		if (addr[x] == MP_SIG)
222121991Sjhb			/* make array index a byte index */
223121991Sjhb			return (target + (x * sizeof(u_int32_t)));
224121991Sjhb	return (-1);
22571525Sjhb}
22671525Sjhb
227121991Sjhbstatic int
228121991Sjhblookup_bus_type(char *name)
22925164Speter{
230121991Sjhb	int     x;
23127005Sfsmp
232121991Sjhb	for (x = 0; x < MAX_BUSTYPE; ++x)
233121991Sjhb		if (strncmp(bus_type_table[x].name, name, 6) == 0)
234121991Sjhb			return (bus_type_table[x].type);
23525164Speter
236121991Sjhb	return (UNKNOWN_BUSTYPE);
23725164Speter}
23825164Speter
23927289Sfsmp/*
24027289Sfsmp * Look for an Intel MP spec table (ie, SMP capable hardware).
24127289Sfsmp */
242121991Sjhbstatic int
243121991Sjhbmptable_probe(void)
24426155Sfsmp{
24526155Sfsmp	int     x;
24626155Sfsmp	u_long  segment;
24726155Sfsmp	u_int32_t target;
24826155Sfsmp
24926155Sfsmp	/* see if EBDA exists */
25043314Sdillon	if ((segment = (u_long) * (u_short *) (KERNBASE + 0x40e)) != 0) {
25126155Sfsmp		/* search first 1K of EBDA */
25226155Sfsmp		target = (u_int32_t) (segment << 4);
25326155Sfsmp		if ((x = search_for_sig(target, 1024 / 4)) >= 0)
25426155Sfsmp			goto found;
25526155Sfsmp	} else {
25626155Sfsmp		/* last 1K of base memory, effective 'top of base' passed in */
257122697Speter		target = (u_int32_t) ((basemem * 1024) - 0x400);
25826155Sfsmp		if ((x = search_for_sig(target, 1024 / 4)) >= 0)
25926155Sfsmp			goto found;
26026155Sfsmp	}
26126155Sfsmp
26226155Sfsmp	/* search the BIOS */
26326155Sfsmp	target = (u_int32_t) BIOS_BASE;
26426155Sfsmp	if ((x = search_for_sig(target, BIOS_COUNT)) >= 0)
26526155Sfsmp		goto found;
26626155Sfsmp
26726155Sfsmp	/* nothing found */
268121991Sjhb	return (ENXIO);
26926155Sfsmp
27027289Sfsmpfound:
271121991Sjhb	mpfps = (mpfps_t)(KERNBASE + x);
27226155Sfsmp
273121991Sjhb	/* Map in the configuration table if it exists. */
274139864Sjhb	if (mpfps->config_type != 0) {
275139864Sjhb		if (bootverbose)
276139864Sjhb			printf(
277139864Sjhb		"MP Table version 1.%d found using Default Configuration %d\n",
278139864Sjhb			    mpfps->spec_rev, mpfps->config_type);
279139864Sjhb		if (mpfps->config_type != 5 && mpfps->config_type != 6) {
280139864Sjhb			printf(
281139864Sjhb			"MP Table Default Configuration %d is unsupported\n",
282139864Sjhb			    mpfps->config_type);
283139864Sjhb			return (ENXIO);
284139864Sjhb		}
285121991Sjhb		mpct = NULL;
286139864Sjhb	} else {
287121991Sjhb		if ((uintptr_t)mpfps->pap >= 1024 * 1024) {
288121991Sjhb			printf("%s: Unable to map MP Configuration Table\n",
289121991Sjhb			    __func__);
290121991Sjhb			return (ENXIO);
291121991Sjhb		}
292121991Sjhb		mpct = (mpcth_t)(KERNBASE + (uintptr_t)mpfps->pap);
293121991Sjhb		if (mpct->base_table_length + (uintptr_t)mpfps->pap >=
294121991Sjhb		    1024 * 1024) {
295121991Sjhb			printf("%s: Unable to map end of MP Config Table\n",
296121991Sjhb			    __func__);
297121991Sjhb			return (ENXIO);
298121991Sjhb		}
299224069Sjhb		if (mpct->extended_table_length != 0 &&
300224069Sjhb		    mpct->extended_table_length + mpct->base_table_length +
301224069Sjhb		    (uintptr_t)mpfps->pap < 1024 * 1024)
302224069Sjhb			mpet = (ext_entry_ptr)((char *)mpct +
303224069Sjhb			    mpct->base_table_length);
304121991Sjhb		if (mpct->signature[0] != 'P' || mpct->signature[1] != 'C' ||
305121991Sjhb		    mpct->signature[2] != 'M' || mpct->signature[3] != 'P') {
306121991Sjhb			printf("%s: MP Config Table has bad signature: %c%c%c%c\n",
307121991Sjhb			    __func__, mpct->signature[0], mpct->signature[1],
308121991Sjhb			    mpct->signature[2], mpct->signature[3]);
309121991Sjhb			return (ENXIO);
310121991Sjhb		}
311121991Sjhb		if (bootverbose)
312121991Sjhb			printf(
313121991Sjhb			"MP Configuration Table version 1.%d found at %p\n",
314121991Sjhb			    mpct->spec_rev, mpct);
315121991Sjhb	}
31626155Sfsmp
317121991Sjhb	return (-100);
31876078Sjhb}
31926155Sfsmp
32025164Speter/*
321121991Sjhb * Run through the MP table enumerating CPUs.
32225164Speter */
323121991Sjhbstatic int
324121991Sjhbmptable_probe_cpus(void)
32525164Speter{
326121991Sjhb	u_int cpu_mask;
32727005Sfsmp
328121991Sjhb	/* Is this a pre-defined config? */
329121991Sjhb	if (mpfps->config_type != 0) {
330121991Sjhb		lapic_create(0, 1);
331121991Sjhb		lapic_create(1, 0);
332121991Sjhb	} else {
333121991Sjhb		cpu_mask = 0;
334121991Sjhb		mptable_walk_table(mptable_probe_cpus_handler, &cpu_mask);
335122490Sjhb#ifdef MPTABLE_FORCE_HTT
336121991Sjhb		mptable_hyperthread_fixup(cpu_mask);
337122490Sjhb#endif
338121991Sjhb	}
339121991Sjhb	return (0);
34025164Speter}
34125164Speter
34225164Speter/*
343121991Sjhb * Initialize the local APIC on the BSP.
34425164Speter */
345121991Sjhbstatic int
346121991Sjhbmptable_setup_local(void)
34725164Speter{
348167364Sjhb	vm_paddr_t addr;
34925164Speter
350121991Sjhb	/* Is this a pre-defined config? */
351121991Sjhb	printf("MPTable: <");
352121991Sjhb	if (mpfps->config_type != 0) {
353167364Sjhb		addr = DEFAULT_APIC_BASE;
354139864Sjhb		printf("Default Configuration %d", mpfps->config_type);
355121991Sjhb	} else {
356167364Sjhb		addr = mpct->apic_address;
357122713Speter		printf("%.*s %.*s", (int)sizeof(mpct->oem_id), mpct->oem_id,
358122713Speter		    (int)sizeof(mpct->product_id), mpct->product_id);
35925164Speter	}
360121991Sjhb	printf(">\n");
361167364Sjhb	lapic_init(addr);
362121991Sjhb	return (0);
36325164Speter}
36425164Speter
36525164Speter/*
366121991Sjhb * Run through the MP table enumerating I/O APICs.
36725164Speter */
368121991Sjhbstatic int
369121991Sjhbmptable_setup_io(void)
37025164Speter{
371121991Sjhb	int i;
372121991Sjhb	u_char byte;
37325164Speter
374121991Sjhb	/* First, we count individual items and allocate arrays. */
375121991Sjhb	mptable_count_items();
376121991Sjhb	busses = malloc((mptable_maxbusid + 1) * sizeof(bus_datum), M_MPTABLE,
377121991Sjhb	    M_WAITOK);
378121991Sjhb	for (i = 0; i <= mptable_maxbusid; i++)
379121991Sjhb		busses[i].bus_type = NOBUS;
38046129Sluoqi
381121991Sjhb	/* Second, we run through adding I/O APIC's and busses. */
382121991Sjhb	mptable_parse_apics_and_busses();
38346129Sluoqi
384121991Sjhb	/* Third, we run through the table tweaking interrupt sources. */
385121991Sjhb	mptable_parse_ints();
38646129Sluoqi
387121991Sjhb	/* Fourth, we register all the I/O APIC's. */
388169395Sjhb	for (i = 0; i <= MAX_APIC_ID; i++)
389121991Sjhb		if (ioapics[i] != NULL)
390121991Sjhb			ioapic_register(ioapics[i]);
39146129Sluoqi
392121991Sjhb	/* Fifth, we setup data structures to handle PCI interrupt routing. */
393121991Sjhb	mptable_pci_setup();
39425164Speter
395121991Sjhb	/* Finally, we throw the switch to enable the I/O APIC's. */
396121991Sjhb	if (mpfps->mpfb2 & MPFB2_IMCR_PRESENT) {
39725164Speter		outb(0x22, 0x70);	/* select IMCR */
39825164Speter		byte = inb(0x23);	/* current contents */
39927289Sfsmp		byte |= 0x01;		/* mask external INTR */
40025164Speter		outb(0x23, byte);	/* disconnect 8259s/NMI */
40125164Speter	}
40227001Sfsmp
403121991Sjhb	return (0);
404121991Sjhb}
40527001Sfsmp
406121991Sjhbstatic void
407121991Sjhbmptable_register(void *dummy __unused)
408121991Sjhb{
40927001Sfsmp
410121991Sjhb	apic_register_enumerator(&mptable_enumerator);
41125164Speter}
412215009SjhbSYSINIT(mptable_register, SI_SUB_TUNABLES - 1, SI_ORDER_FIRST, mptable_register,
413177253Srwatson    NULL);
41425164Speter
41525164Speter/*
416224069Sjhb * Call the handler routine for each entry in the MP config base table.
41725164Speter */
41825164Speterstatic void
419121991Sjhbmptable_walk_table(mptable_entry_handler *handler, void *arg)
42025164Speter{
421121991Sjhb	u_int i;
422121991Sjhb	u_char *entry;
42325164Speter
424121991Sjhb	entry = (u_char *)(mpct + 1);
425121991Sjhb	for (i = 0; i < mpct->entry_count; i++) {
426121991Sjhb		switch (*entry) {
427121991Sjhb		case MPCT_ENTRY_PROCESSOR:
428121991Sjhb		case MPCT_ENTRY_IOAPIC:
429121991Sjhb		case MPCT_ENTRY_BUS:
430121991Sjhb		case MPCT_ENTRY_INT:
431121991Sjhb		case MPCT_ENTRY_LOCAL_INT:
432121991Sjhb			break;
433121991Sjhb		default:
434121991Sjhb			panic("%s: Unknown MP Config Entry %d\n", __func__,
435121991Sjhb			    (int)*entry);
436121991Sjhb		}
437121991Sjhb		handler(entry, arg);
438121991Sjhb		entry += basetable_entry_types[*entry].length;
43925164Speter	}
44025164Speter}
44125164Speter
442224096Sjhb#ifdef NEW_PCIB
443224069Sjhb/*
444224069Sjhb * Call the handler routine for each entry in the MP config extended
445224069Sjhb * table.
446224069Sjhb */
447121991Sjhbstatic void
448224069Sjhbmptable_walk_extended_table(mptable_extended_entry_handler *handler, void *arg)
449224069Sjhb{
450224069Sjhb	ext_entry_ptr end, entry;
451224069Sjhb
452224069Sjhb	if (mpet == NULL)
453224069Sjhb		return;
454224069Sjhb	entry = mpet;
455224069Sjhb	end = (ext_entry_ptr)((char *)mpet + mpct->extended_table_length);
456224069Sjhb	while (entry < end) {
457224069Sjhb		handler(entry, arg);
458224069Sjhb		entry = (ext_entry_ptr)((char *)entry + entry->length);
459224069Sjhb	}
460224069Sjhb}
461224096Sjhb#endif
462224069Sjhb
463224069Sjhbstatic void
464121991Sjhbmptable_probe_cpus_handler(u_char *entry, void *arg)
46525164Speter{
466121991Sjhb	proc_entry_ptr proc;
467121991Sjhb	u_int *cpu_mask;
46825164Speter
469121991Sjhb	switch (*entry) {
470121991Sjhb	case MPCT_ENTRY_PROCESSOR:
471121991Sjhb		proc = (proc_entry_ptr)entry;
472121991Sjhb		if (proc->cpu_flags & PROCENTRY_FLAG_EN) {
473121991Sjhb			lapic_create(proc->apic_id, proc->cpu_flags &
474121991Sjhb			    PROCENTRY_FLAG_BP);
475169395Sjhb			if (proc->apic_id < MAX_LAPIC_ID) {
476169395Sjhb				cpu_mask = (u_int *)arg;
477169395Sjhb				*cpu_mask |= (1ul << proc->apic_id);
478169395Sjhb			}
479121991Sjhb		}
480121991Sjhb		break;
481121991Sjhb	}
48225164Speter}
48325164Speter
48466277Spsstatic void
485121991Sjhbmptable_count_items_handler(u_char *entry, void *arg __unused)
48625164Speter{
487121991Sjhb	io_apic_entry_ptr apic;
488121991Sjhb	bus_entry_ptr bus;
48925164Speter
490121991Sjhb	switch (*entry) {
491121991Sjhb	case MPCT_ENTRY_BUS:
492121991Sjhb		bus = (bus_entry_ptr)entry;
493121991Sjhb		mptable_nbusses++;
494121991Sjhb		if (bus->bus_id > mptable_maxbusid)
495121991Sjhb			mptable_maxbusid = bus->bus_id;
496121991Sjhb		break;
497121991Sjhb	case MPCT_ENTRY_IOAPIC:
498121991Sjhb		apic = (io_apic_entry_ptr)entry;
499121991Sjhb		if (apic->apic_flags & IOAPICENTRY_FLAG_EN)
500121991Sjhb			mptable_nioapics++;
501121991Sjhb		break;
50226155Sfsmp	}
50326108Sfsmp}
50426108Sfsmp
50526108Sfsmp/*
506121991Sjhb * Count items in the table.
50726108Sfsmp */
508121991Sjhbstatic void
509121991Sjhbmptable_count_items(void)
51026108Sfsmp{
51126108Sfsmp
512121991Sjhb	/* Is this a pre-defined config? */
513121991Sjhb	if (mpfps->config_type != 0) {
514121991Sjhb		mptable_nioapics = 1;
515121991Sjhb		switch (mpfps->config_type) {
51625164Speter		case 1:
51725164Speter		case 2:
51825164Speter		case 3:
51925164Speter		case 4:
520121991Sjhb			mptable_nbusses = 1;
52125164Speter			break;
522121991Sjhb		case 5:
523121991Sjhb		case 6:
524121991Sjhb		case 7:
525121991Sjhb			mptable_nbusses = 2;
526121991Sjhb			break;
52725164Speter		default:
528121991Sjhb			panic("Unknown pre-defined MP Table config type %d",
529121991Sjhb			    mpfps->config_type);
53025164Speter		}
531121991Sjhb		mptable_maxbusid = mptable_nbusses - 1;
532121991Sjhb	} else
533121991Sjhb		mptable_walk_table(mptable_count_items_handler, NULL);
53425164Speter}
53525164Speter
536108914Sjhb/*
537121991Sjhb * Add a bus or I/O APIC from an entry in the table.
538108914Sjhb */
539108914Sjhbstatic void
540121991Sjhbmptable_parse_apics_and_busses_handler(u_char *entry, void *arg __unused)
541108914Sjhb{
542121991Sjhb	io_apic_entry_ptr apic;
543121991Sjhb	bus_entry_ptr bus;
544121991Sjhb	enum busTypes bus_type;
545121991Sjhb	int i;
54625164Speter
547108914Sjhb
548121991Sjhb	switch (*entry) {
549121991Sjhb	case MPCT_ENTRY_BUS:
550121991Sjhb		bus = (bus_entry_ptr)entry;
551121991Sjhb		bus_type = lookup_bus_type(bus->bus_type);
552121991Sjhb		if (bus_type == UNKNOWN_BUSTYPE) {
553121991Sjhb			printf("MPTable: Unknown bus %d type \"", bus->bus_id);
554121991Sjhb			for (i = 0; i < 6; i++)
555121991Sjhb				printf("%c", bus->bus_type[i]);
556121991Sjhb			printf("\"\n");
557121991Sjhb		}
558121991Sjhb		busses[bus->bus_id].bus_id = bus->bus_id;
559121991Sjhb		busses[bus->bus_id].bus_type = bus_type;
560121991Sjhb		break;
561121991Sjhb	case MPCT_ENTRY_IOAPIC:
562121991Sjhb		apic = (io_apic_entry_ptr)entry;
563121991Sjhb		if (!(apic->apic_flags & IOAPICENTRY_FLAG_EN))
56464290Stegge			break;
565169395Sjhb		if (apic->apic_id > MAX_APIC_ID)
566121991Sjhb			panic("%s: I/O APIC ID %d too high", __func__,
567121991Sjhb			    apic->apic_id);
568121991Sjhb		if (ioapics[apic->apic_id] != NULL)
569121991Sjhb			panic("%s: Double APIC ID %d", __func__,
570121991Sjhb			    apic->apic_id);
571167247Sjhb		ioapics[apic->apic_id] = ioapic_create(apic->apic_address,
572167247Sjhb		    apic->apic_id, -1);
573121991Sjhb		break;
574121991Sjhb	default:
575121991Sjhb		break;
57664290Stegge	}
57764290Stegge}
57864290Stegge
57925164Speter/*
580121991Sjhb * Enumerate I/O APIC's and busses.
58125164Speter */
58225164Speterstatic void
583121991Sjhbmptable_parse_apics_and_busses(void)
58425164Speter{
58525164Speter
586121991Sjhb	/* Is this a pre-defined config? */
587121991Sjhb	if (mpfps->config_type != 0) {
588139864Sjhb		ioapics[2] = ioapic_create(DEFAULT_IO_APIC_BASE, 2, 0);
589121991Sjhb		busses[0].bus_id = 0;
590139864Sjhb		busses[0].bus_type = default_data[mpfps->config_type - 1][2];
591121991Sjhb		if (mptable_nbusses > 1) {
592121991Sjhb			busses[1].bus_id = 1;
593121991Sjhb			busses[1].bus_type =
594139864Sjhb			    default_data[mpfps->config_type - 1][4];
59525292Sfsmp		}
596121991Sjhb	} else
597121991Sjhb		mptable_walk_table(mptable_parse_apics_and_busses_handler,
598121991Sjhb		    NULL);
59925164Speter}
60025164Speter
601121991Sjhb/*
602121991Sjhb * Determine conforming polarity for a given bus type.
603121991Sjhb */
604128930Sjhbstatic enum intr_polarity
605128930Sjhbconforming_polarity(u_char src_bus, u_char src_bus_irq)
60638888Stegge{
60738888Stegge
608121991Sjhb	KASSERT(src_bus <= mptable_maxbusid, ("bus id %d too large", src_bus));
609121991Sjhb	switch (busses[src_bus].bus_type) {
610121991Sjhb	case ISA:
611129663Sjhb	case EISA:
612128930Sjhb		return (INTR_POLARITY_HIGH);
613128930Sjhb	case PCI:
614128930Sjhb		return (INTR_POLARITY_LOW);
615121991Sjhb	default:
616121991Sjhb		panic("%s: unknown bus type %d", __func__,
617121991Sjhb		    busses[src_bus].bus_type);
61838888Stegge	}
61938888Stegge}
62038888Stegge
621121991Sjhb/*
622121991Sjhb * Determine conforming trigger for a given bus type.
623121991Sjhb */
624128930Sjhbstatic enum intr_trigger
625121991Sjhbconforming_trigger(u_char src_bus, u_char src_bus_irq)
62625164Speter{
62725164Speter
628121991Sjhb	KASSERT(src_bus <= mptable_maxbusid, ("bus id %d too large", src_bus));
629121991Sjhb	switch (busses[src_bus].bus_type) {
630121991Sjhb	case ISA:
631140452Sjhb#ifndef PC98
632140452Sjhb		if (elcr_found)
633140452Sjhb			return (elcr_read_trigger(src_bus_irq));
634140452Sjhb		else
635140452Sjhb#endif
636140452Sjhb			return (INTR_TRIGGER_EDGE);
637121991Sjhb	case PCI:
638128930Sjhb		return (INTR_TRIGGER_LEVEL);
639129008Snyan#ifndef PC98
640121991Sjhb	case EISA:
641121991Sjhb		KASSERT(src_bus_irq < 16, ("Invalid EISA IRQ %d", src_bus_irq));
642140452Sjhb		KASSERT(elcr_found, ("Missing ELCR"));
643128930Sjhb		return (elcr_read_trigger(src_bus_irq));
644129008Snyan#endif
645121991Sjhb	default:
646121991Sjhb		panic("%s: unknown bus type %d", __func__,
647121991Sjhb		    busses[src_bus].bus_type);
64825164Speter	}
64925164Speter}
65025164Speter
651128930Sjhbstatic enum intr_polarity
652121991Sjhbintentry_polarity(int_entry_ptr intr)
65325164Speter{
65425164Speter
655121991Sjhb	switch (intr->int_flags & INTENTRY_FLAGS_POLARITY) {
656121991Sjhb	case INTENTRY_FLAGS_POLARITY_CONFORM:
657128930Sjhb		return (conforming_polarity(intr->src_bus_id,
658128930Sjhb			    intr->src_bus_irq));
659121991Sjhb	case INTENTRY_FLAGS_POLARITY_ACTIVEHI:
660128930Sjhb		return (INTR_POLARITY_HIGH);
661121991Sjhb	case INTENTRY_FLAGS_POLARITY_ACTIVELO:
662128930Sjhb		return (INTR_POLARITY_LOW);
663121991Sjhb	default:
664121991Sjhb		panic("Bogus interrupt flags");
66525164Speter	}
66625164Speter}
66725164Speter
668128930Sjhbstatic enum intr_trigger
669121991Sjhbintentry_trigger(int_entry_ptr intr)
67025164Speter{
67125164Speter
672121991Sjhb	switch (intr->int_flags & INTENTRY_FLAGS_TRIGGER) {
673121991Sjhb	case INTENTRY_FLAGS_TRIGGER_CONFORM:
674121991Sjhb		return (conforming_trigger(intr->src_bus_id,
675121991Sjhb			    intr->src_bus_irq));
676121991Sjhb	case INTENTRY_FLAGS_TRIGGER_EDGE:
677128930Sjhb		return (INTR_TRIGGER_EDGE);
678121991Sjhb	case INTENTRY_FLAGS_TRIGGER_LEVEL:
679128930Sjhb		return (INTR_TRIGGER_LEVEL);
680121991Sjhb	default:
681121991Sjhb		panic("Bogus interrupt flags");
68227255Sfsmp	}
68325419Sfsmp}
68425419Sfsmp
68525419Sfsmp/*
686121991Sjhb * Parse an interrupt entry for an I/O interrupt routed to a pin on an I/O APIC.
68725164Speter */
688121991Sjhbstatic void
689121991Sjhbmptable_parse_io_int(int_entry_ptr intr)
69025164Speter{
691121991Sjhb	void *ioapic;
692140129Sjhb	u_int pin, apic_id;
69325164Speter
694140129Sjhb	apic_id = intr->dst_apic_id;
695121991Sjhb	if (intr->dst_apic_id == 0xff) {
696140129Sjhb		/*
697140129Sjhb		 * An APIC ID of 0xff means that the interrupt is connected
698140129Sjhb		 * to the specified pin on all I/O APICs in the system.  If
699140129Sjhb		 * there is only one I/O APIC, then use that APIC to route
700140129Sjhb		 * the interrupts.  If there is more than one I/O APIC, then
701140129Sjhb		 * punt.
702140129Sjhb		 */
703140129Sjhb		if (mptable_nioapics == 1) {
704140129Sjhb			apic_id = 0;
705140129Sjhb			while (ioapics[apic_id] == NULL)
706140129Sjhb				apic_id++;
707140129Sjhb		} else {
708140129Sjhb			printf(
709140129Sjhb			"MPTable: Ignoring global interrupt entry for pin %d\n",
710140129Sjhb			    intr->dst_apic_int);
711140129Sjhb			return;
712140129Sjhb		}
71326950Sfsmp	}
714169395Sjhb	if (apic_id > MAX_APIC_ID) {
715121991Sjhb		printf("MPTable: Ignoring interrupt entry for ioapic%d\n",
716121991Sjhb		    intr->dst_apic_id);
717121991Sjhb		return;
71834990Stegge	}
719140129Sjhb	ioapic = ioapics[apic_id];
720121991Sjhb	if (ioapic == NULL) {
721121991Sjhb		printf(
722121991Sjhb	"MPTable: Ignoring interrupt entry for missing ioapic%d\n",
723140129Sjhb		    apic_id);
724121991Sjhb		return;
72534990Stegge	}
726121991Sjhb	pin = intr->dst_apic_int;
727121991Sjhb	switch (intr->int_type) {
728121991Sjhb	case INTENTRY_TYPE_INT:
729130980Sjhb		switch (busses[intr->src_bus_id].bus_type) {
730130980Sjhb		case NOBUS:
731121991Sjhb			panic("interrupt from missing bus");
732130980Sjhb		case ISA:
733130980Sjhb		case EISA:
734130980Sjhb			if (busses[intr->src_bus_id].bus_type == ISA)
735130980Sjhb				ioapic_set_bus(ioapic, pin, APIC_BUS_ISA);
736130980Sjhb			else
737130980Sjhb				ioapic_set_bus(ioapic, pin, APIC_BUS_EISA);
738130980Sjhb			if (intr->src_bus_irq == pin)
739130980Sjhb				break;
740121991Sjhb			ioapic_remap_vector(ioapic, pin, intr->src_bus_irq);
741122149Sjhb			if (ioapic_get_vector(ioapic, intr->src_bus_irq) ==
742122149Sjhb			    intr->src_bus_irq)
743122149Sjhb				ioapic_disable_pin(ioapic, intr->src_bus_irq);
744130980Sjhb			break;
745130980Sjhb		case PCI:
746130980Sjhb			ioapic_set_bus(ioapic, pin, APIC_BUS_PCI);
747130980Sjhb			break;
748130980Sjhb		default:
749130980Sjhb			ioapic_set_bus(ioapic, pin, APIC_BUS_UNKNOWN);
750130980Sjhb			break;
751122149Sjhb		}
75234990Stegge		break;
753121991Sjhb	case INTENTRY_TYPE_NMI:
754121991Sjhb		ioapic_set_nmi(ioapic, pin);
755121991Sjhb		break;
756121991Sjhb	case INTENTRY_TYPE_SMI:
757121991Sjhb		ioapic_set_smi(ioapic, pin);
758121991Sjhb		break;
759121991Sjhb	case INTENTRY_TYPE_EXTINT:
760121991Sjhb		ioapic_set_extint(ioapic, pin);
761121991Sjhb		break;
762121991Sjhb	default:
763121991Sjhb		panic("%s: invalid interrupt entry type %d\n", __func__,
764121991Sjhb		    intr->int_type);
76534990Stegge	}
766121991Sjhb	if (intr->int_type == INTENTRY_TYPE_INT ||
767121991Sjhb	    (intr->int_flags & INTENTRY_FLAGS_TRIGGER) !=
768121991Sjhb	    INTENTRY_FLAGS_TRIGGER_CONFORM)
769121991Sjhb		ioapic_set_triggermode(ioapic, pin, intentry_trigger(intr));
770121991Sjhb	if (intr->int_type == INTENTRY_TYPE_INT ||
771121991Sjhb	    (intr->int_flags & INTENTRY_FLAGS_POLARITY) !=
772121991Sjhb	    INTENTRY_FLAGS_POLARITY_CONFORM)
773121991Sjhb		ioapic_set_polarity(ioapic, pin, intentry_polarity(intr));
77434990Stegge}
77525164Speter
77625499Sfsmp/*
777121991Sjhb * Parse an interrupt entry for a local APIC LVT pin.
77825499Sfsmp */
779121991Sjhbstatic void
780121991Sjhbmptable_parse_local_int(int_entry_ptr intr)
78125164Speter{
782121991Sjhb	u_int apic_id, pin;
78325164Speter
784121991Sjhb	if (intr->dst_apic_id == 0xff)
785121991Sjhb		apic_id = APIC_ID_ALL;
786121991Sjhb	else
787121991Sjhb		apic_id = intr->dst_apic_id;
788121991Sjhb	if (intr->dst_apic_int == 0)
789262141Sjhb		pin = APIC_LVT_LINT0;
790121991Sjhb	else
791262141Sjhb		pin = APIC_LVT_LINT1;
792121991Sjhb	switch (intr->int_type) {
793121991Sjhb	case INTENTRY_TYPE_INT:
794121991Sjhb#if 1
795121991Sjhb		printf(
796121991Sjhb	"MPTable: Ignoring vectored local interrupt for LINTIN%d vector %d\n",
797121991Sjhb		    intr->dst_apic_int, intr->src_bus_irq);
798121991Sjhb		return;
79925499Sfsmp#else
800121991Sjhb		lapic_set_lvt_mode(apic_id, pin, APIC_LVT_DM_FIXED);
80125164Speter		break;
802121991Sjhb#endif
803121991Sjhb	case INTENTRY_TYPE_NMI:
804121991Sjhb		lapic_set_lvt_mode(apic_id, pin, APIC_LVT_DM_NMI);
80525164Speter		break;
806121991Sjhb	case INTENTRY_TYPE_SMI:
807121991Sjhb		lapic_set_lvt_mode(apic_id, pin, APIC_LVT_DM_SMI);
80825164Speter		break;
809121991Sjhb	case INTENTRY_TYPE_EXTINT:
810121991Sjhb		lapic_set_lvt_mode(apic_id, pin, APIC_LVT_DM_EXTINT);
81125164Speter		break;
81225164Speter	default:
813121991Sjhb		panic("%s: invalid interrupt entry type %d\n", __func__,
814121991Sjhb		    intr->int_type);
81525164Speter	}
816121991Sjhb	if ((intr->int_flags & INTENTRY_FLAGS_TRIGGER) !=
817121991Sjhb	    INTENTRY_FLAGS_TRIGGER_CONFORM)
818121991Sjhb		lapic_set_lvt_triggermode(apic_id, pin,
819121991Sjhb		    intentry_trigger(intr));
820121991Sjhb	if ((intr->int_flags & INTENTRY_FLAGS_POLARITY) !=
821121991Sjhb	    INTENTRY_FLAGS_POLARITY_CONFORM)
822121991Sjhb		lapic_set_lvt_polarity(apic_id, pin, intentry_polarity(intr));
82325164Speter}
82425164Speter
82525164Speter/*
826121991Sjhb * Parse interrupt entries.
82725164Speter */
828121991Sjhbstatic void
829121991Sjhbmptable_parse_ints_handler(u_char *entry, void *arg __unused)
83025164Speter{
831121991Sjhb	int_entry_ptr intr;
83225164Speter
833121991Sjhb	intr = (int_entry_ptr)entry;
834121991Sjhb	switch (*entry) {
835121991Sjhb	case MPCT_ENTRY_INT:
836121991Sjhb		mptable_parse_io_int(intr);
837121991Sjhb		break;
838121991Sjhb	case MPCT_ENTRY_LOCAL_INT:
839121991Sjhb		mptable_parse_local_int(intr);
840121991Sjhb		break;
84125164Speter	}
84225164Speter}
843139864Sjhb
84425164Speter/*
845139864Sjhb * Configure interrupt pins for a default configuration.  For details see
846139864Sjhb * Table 5-2 in Section 5 of the MP Table specification.
847139864Sjhb */
848139864Sjhbstatic void
849139864Sjhbmptable_parse_default_config_ints(void)
850139864Sjhb{
851139864Sjhb	struct INTENTRY entry;
852139864Sjhb	int pin;
853139864Sjhb
854139864Sjhb	/*
855139864Sjhb	 * All default configs route IRQs from bus 0 to the first 16 pins
856139864Sjhb	 * of the first I/O APIC with an APIC ID of 2.
857139864Sjhb	 */
858139864Sjhb	entry.type = MPCT_ENTRY_INT;
859139864Sjhb	entry.int_flags = INTENTRY_FLAGS_POLARITY_CONFORM |
860139864Sjhb	    INTENTRY_FLAGS_TRIGGER_CONFORM;
861139864Sjhb	entry.src_bus_id = 0;
862139864Sjhb	entry.dst_apic_id = 2;
863139864Sjhb
864139864Sjhb	/* Run through all 16 pins. */
865139864Sjhb	for (pin = 0; pin < 16; pin++) {
866139864Sjhb		entry.dst_apic_int = pin;
867139864Sjhb		switch (pin) {
868139864Sjhb		case 0:
869139864Sjhb			/* Pin 0 is an ExtINT pin. */
870139864Sjhb			entry.int_type = INTENTRY_TYPE_EXTINT;
871139864Sjhb			break;
872139864Sjhb		case 2:
873139864Sjhb			/* IRQ 0 is routed to pin 2. */
874139864Sjhb			entry.int_type = INTENTRY_TYPE_INT;
875139864Sjhb			entry.src_bus_irq = 0;
876139864Sjhb			break;
877139864Sjhb		default:
878139864Sjhb			/* All other pins are identity mapped. */
879139864Sjhb			entry.int_type = INTENTRY_TYPE_INT;
880139864Sjhb			entry.src_bus_irq = pin;
881139864Sjhb			break;
882139864Sjhb		}
883139864Sjhb		mptable_parse_io_int(&entry);
884139864Sjhb	}
885139864Sjhb
886139864Sjhb	/* Certain configs disable certain pins. */
887139864Sjhb	if (mpfps->config_type == 7)
888139864Sjhb		ioapic_disable_pin(ioapics[2], 0);
889139864Sjhb	if (mpfps->config_type == 2) {
890139864Sjhb		ioapic_disable_pin(ioapics[2], 2);
891139864Sjhb		ioapic_disable_pin(ioapics[2], 13);
892139864Sjhb	}
893139864Sjhb}
894139864Sjhb
895139864Sjhb/*
896121991Sjhb * Configure the interrupt pins
89725164Speter */
89825164Speterstatic void
899121991Sjhbmptable_parse_ints(void)
90025164Speter{
90125164Speter
902121991Sjhb	/* Is this a pre-defined config? */
903121991Sjhb	if (mpfps->config_type != 0) {
904121991Sjhb		/* Configure LINT pins. */
905262141Sjhb		lapic_set_lvt_mode(APIC_ID_ALL, APIC_LVT_LINT0,
906262141Sjhb		    APIC_LVT_DM_EXTINT);
907262141Sjhb		lapic_set_lvt_mode(APIC_ID_ALL, APIC_LVT_LINT1, APIC_LVT_DM_NMI);
90827005Sfsmp
909121991Sjhb		/* Configure I/O APIC pins. */
910139864Sjhb		mptable_parse_default_config_ints();
911121991Sjhb	} else
912121991Sjhb		mptable_walk_table(mptable_parse_ints_handler, NULL);
91325164Speter}
91425164Speter
915122490Sjhb#ifdef MPTABLE_FORCE_HTT
91625164Speter/*
917121991Sjhb * Perform a hyperthreading "fix-up" to enumerate any logical CPU's
918121991Sjhb * that aren't already listed in the table.
919121991Sjhb *
920121991Sjhb * XXX: We assume that all of the physical CPUs in the
921121991Sjhb * system have the same number of logical CPUs.
922121991Sjhb *
923121991Sjhb * XXX: We assume that APIC ID's are allocated such that
924121991Sjhb * the APIC ID's for a physical processor are aligned
925121991Sjhb * with the number of logical CPU's in the processor.
92625164Speter */
927121991Sjhbstatic void
928121991Sjhbmptable_hyperthread_fixup(u_int id_mask)
92925164Speter{
930121991Sjhb	u_int i, id, logical_cpus;
93125164Speter
932121991Sjhb	/* Nothing to do if there is no HTT support. */
933121991Sjhb	if ((cpu_feature & CPUID_HTT) == 0)
934121991Sjhb		return;
935121991Sjhb	logical_cpus = (cpu_procinfo & CPUID_HTT_CORES) >> 16;
936121991Sjhb	if (logical_cpus <= 1)
937121991Sjhb		return;
93827005Sfsmp
93925164Speter	/*
940121991Sjhb	 * For each APIC ID of a CPU that is set in the mask,
941121991Sjhb	 * scan the other candidate APIC ID's for this
942121991Sjhb	 * physical processor.  If any of those ID's are
943121991Sjhb	 * already in the table, then kill the fixup.
94425164Speter	 */
945169395Sjhb	for (id = 0; id <= MAX_LAPIC_ID; id++) {
946121991Sjhb		if ((id_mask & 1 << id) == 0)
947121991Sjhb			continue;
948121991Sjhb		/* First, make sure we are on a logical_cpus boundary. */
949121991Sjhb		if (id % logical_cpus != 0)
950121991Sjhb			return;
951121991Sjhb		for (i = id + 1; i < id + logical_cpus; i++)
952121991Sjhb			if ((id_mask & 1 << i) != 0)
953121991Sjhb				return;
954121991Sjhb	}
95525164Speter
95625164Speter	/*
957121991Sjhb	 * Ok, the ID's checked out, so perform the fixup by
958121991Sjhb	 * adding the logical CPUs.
95925164Speter	 */
960121991Sjhb	while ((id = ffs(id_mask)) != 0) {
961121991Sjhb		id--;
962121991Sjhb		for (i = id + 1; i < id + logical_cpus; i++) {
963121991Sjhb			if (bootverbose)
964121991Sjhb				printf(
965121991Sjhb			"MPTable: Adding logical CPU %d from main CPU %d\n",
966121991Sjhb				    i, id);
967121991Sjhb			lapic_create(i, 0);
968121991Sjhb		}
969121991Sjhb		id_mask &= ~(1 << id);
970121991Sjhb	}
97125164Speter}
972122490Sjhb#endif /* MPTABLE_FORCE_HTT */
97325164Speter
97425164Speter/*
975121991Sjhb * Support code for routing PCI interrupts using the MP Table.
97699862Speter */
97799862Speterstatic void
978121991Sjhbmptable_pci_setup(void)
97999862Speter{
980121991Sjhb	int i;
98199862Speter
982121991Sjhb	/*
983121991Sjhb	 * Find the first pci bus and call it 0.  Panic if pci0 is not
984121991Sjhb	 * bus zero and there are multiple PCI busses.
985121991Sjhb	 */
986121991Sjhb	for (i = 0; i <= mptable_maxbusid; i++)
987121991Sjhb		if (busses[i].bus_type == PCI) {
988121991Sjhb			if (pci0 == -1)
989121991Sjhb				pci0 = i;
990121991Sjhb			else if (pci0 != 0)
991121991Sjhb				panic(
992121991Sjhb		"MPTable contains multiple PCI busses but no PCI bus 0");
993121991Sjhb		}
99499862Speter}
99599862Speter
99699862Speterstatic void
997121991Sjhbmptable_pci_probe_table_handler(u_char *entry, void *arg)
99899862Speter{
999121991Sjhb	struct pci_probe_table_args *args;
1000121991Sjhb	int_entry_ptr intr;
100199862Speter
1002121991Sjhb	if (*entry != MPCT_ENTRY_INT)
100331639Sfsmp		return;
1004121991Sjhb	intr = (int_entry_ptr)entry;
1005121991Sjhb	args = (struct pci_probe_table_args *)arg;
1006121991Sjhb	KASSERT(args->bus <= mptable_maxbusid,
1007121991Sjhb	    ("bus %d is too big", args->bus));
1008121991Sjhb	KASSERT(busses[args->bus].bus_type == PCI, ("probing for non-PCI bus"));
1009121991Sjhb	if (intr->src_bus_id == args->bus)
1010121991Sjhb		args->found = 1;
101131639Sfsmp}
101231639Sfsmp
1013121991Sjhbint
1014121991Sjhbmptable_pci_probe_table(int bus)
101531639Sfsmp{
1016121991Sjhb	struct pci_probe_table_args args;
101731639Sfsmp
1018121991Sjhb	if (bus < 0)
1019121991Sjhb		return (EINVAL);
1020139864Sjhb	if (mpct == NULL || pci0 == -1 || pci0 + bus > mptable_maxbusid)
1021121991Sjhb		return (ENXIO);
1022122511Sjhb	if (busses[pci0 + bus].bus_type != PCI)
1023122511Sjhb		return (ENXIO);
1024121991Sjhb	args.bus = pci0 + bus;
1025121991Sjhb	args.found = 0;
1026121991Sjhb	mptable_walk_table(mptable_pci_probe_table_handler, &args);
1027121991Sjhb	if (args.found == 0)
1028121991Sjhb		return (ENXIO);
1029121991Sjhb	return (0);
103031639Sfsmp}
103131639Sfsmp
1032105216Sphkstatic void
1033121991Sjhbmptable_pci_route_interrupt_handler(u_char *entry, void *arg)
103465557Sjasone{
1035121991Sjhb	struct pci_route_interrupt_args *args;
1036121991Sjhb	int_entry_ptr intr;
1037122123Sjhb	int vector;
1038102543Speter
1039121991Sjhb	if (*entry != MPCT_ENTRY_INT)
1040111382Stegge		return;
1041121991Sjhb	intr = (int_entry_ptr)entry;
1042121991Sjhb	args = (struct pci_route_interrupt_args *)arg;
1043121991Sjhb	if (intr->src_bus_id != args->bus || intr->src_bus_irq != args->irq)
1044121991Sjhb		return;
1045122123Sjhb
1046122123Sjhb	/* Make sure the APIC maps to a known APIC. */
1047121991Sjhb	KASSERT(ioapics[intr->dst_apic_id] != NULL,
1048121991Sjhb	    ("No I/O APIC %d to route interrupt to", intr->dst_apic_id));
1049122123Sjhb
1050122123Sjhb	/*
1051122123Sjhb	 * Look up the vector for this APIC / pin combination.  If we
1052122123Sjhb	 * have previously matched an entry for this PCI IRQ but it
1053122123Sjhb	 * has the same vector as this entry, just return.  Otherwise,
1054122123Sjhb	 * we use the vector for this APIC / pin combination.
1055122123Sjhb	 */
1056122123Sjhb	vector = ioapic_get_vector(ioapics[intr->dst_apic_id],
1057121991Sjhb	    intr->dst_apic_int);
1058122123Sjhb	if (args->vector == vector)
1059122123Sjhb		return;
1060122123Sjhb	KASSERT(args->vector == -1,
1061135754Sjhb	    ("Multiple IRQs for PCI interrupt %d.%d.INT%c: %d and %d\n",
1062135754Sjhb	    args->bus, args->irq >> 2, 'A' + (args->irq & 0x3), args->vector,
1063135754Sjhb	    vector));
1064122123Sjhb	args->vector = vector;
106565557Sjasone}
1066112687Sps
1067121991Sjhbint
1068121991Sjhbmptable_pci_route_interrupt(device_t pcib, device_t dev, int pin)
1069112687Sps{
1070121991Sjhb	struct pci_route_interrupt_args args;
1071121991Sjhb	int slot;
1072112687Sps
1073121991Sjhb	/* Like ACPI, pin numbers are 0-3, not 1-4. */
1074121991Sjhb	pin--;
1075121991Sjhb	KASSERT(pci0 != -1, ("do not know how to route PCI interrupts"));
1076121991Sjhb	args.bus = pci_get_bus(dev) + pci0;
1077121991Sjhb	slot = pci_get_slot(dev);
1078112687Sps
1079121991Sjhb	/*
1080121991Sjhb	 * PCI interrupt entries in the MP Table encode both the slot and
1081121991Sjhb	 * pin into the IRQ with the pin being the two least significant
1082121991Sjhb	 * bits, the slot being the next five bits, and the most significant
1083121991Sjhb	 * bit being reserved.
1084121991Sjhb	 */
1085121991Sjhb	args.irq = slot << 2 | pin;
1086121991Sjhb	args.vector = -1;
1087121991Sjhb	mptable_walk_table(mptable_pci_route_interrupt_handler, &args);
1088121991Sjhb	if (args.vector < 0) {
1089121991Sjhb		device_printf(pcib, "unable to route slot %d INT%c\n", slot,
1090121991Sjhb		    'A' + pin);
1091121991Sjhb		return (PCI_INVALID_IRQ);
1092112687Sps	}
1093131398Sjhb	if (bootverbose)
1094131398Sjhb		device_printf(pcib, "slot %d INT%c routed to irq %d\n", slot,
1095131398Sjhb		    'A' + pin, args.vector);
1096121991Sjhb	return (args.vector);
1097112687Sps}
1098224069Sjhb
1099224069Sjhb#ifdef NEW_PCIB
1100224069Sjhbstruct host_res_args {
1101224069Sjhb	struct mptable_hostb_softc *sc;
1102224069Sjhb	device_t dev;
1103224069Sjhb	u_char	bus;
1104224069Sjhb};
1105224069Sjhb
1106224069Sjhb/*
1107224069Sjhb * Initialize a Host-PCI bridge so it can restrict resource allocation
1108224069Sjhb * requests to the resources it actually decodes according to MP
1109224069Sjhb * config table extended entries.
1110224069Sjhb */
1111224069Sjhbstatic void
1112224069Sjhbmptable_host_res_handler(ext_entry_ptr entry, void *arg)
1113224069Sjhb{
1114224069Sjhb	struct host_res_args *args;
1115224069Sjhb	cbasm_entry_ptr cbasm;
1116224069Sjhb	sas_entry_ptr sas;
1117224069Sjhb	const char *name;
1118224069Sjhb	uint64_t start, end;
1119224069Sjhb	int error, *flagp, flags, type;
1120224069Sjhb
1121224069Sjhb	args = arg;
1122224069Sjhb	switch (entry->type) {
1123224069Sjhb	case MPCT_EXTENTRY_SAS:
1124224069Sjhb		sas = (sas_entry_ptr)entry;
1125224069Sjhb		if (sas->bus_id != args->bus)
1126224069Sjhb			break;
1127224069Sjhb		switch (sas->address_type) {
1128224069Sjhb		case SASENTRY_TYPE_IO:
1129224069Sjhb			type = SYS_RES_IOPORT;
1130224069Sjhb			flags = 0;
1131224069Sjhb			break;
1132224069Sjhb		case SASENTRY_TYPE_MEMORY:
1133224069Sjhb			type = SYS_RES_MEMORY;
1134224069Sjhb			flags = 0;
1135224069Sjhb			break;
1136224069Sjhb		case SASENTRY_TYPE_PREFETCH:
1137224069Sjhb			type = SYS_RES_MEMORY;
1138224069Sjhb			flags = RF_PREFETCHABLE;
1139224069Sjhb			break;
1140224069Sjhb		default:
1141224069Sjhb			printf(
1142224069Sjhb	    "MPTable: Unknown systems address space type for bus %u: %d\n",
1143224069Sjhb			    sas->bus_id, sas->address_type);
1144224069Sjhb			return;
1145224069Sjhb		}
1146224069Sjhb		start = sas->address_base;
1147224069Sjhb		end = sas->address_base + sas->address_length - 1;
1148224069Sjhb#ifdef __i386__
1149224069Sjhb		if (start > ULONG_MAX) {
1150224069Sjhb			device_printf(args->dev,
1151224069Sjhb			    "Ignoring %d range above 4GB (%#jx-%#jx)\n",
1152224069Sjhb			    type, (uintmax_t)start, (uintmax_t)end);
1153224069Sjhb			break;
1154224069Sjhb		}
1155224069Sjhb		if (end > ULONG_MAX) {
1156224069Sjhb			device_printf(args->dev,
1157224069Sjhb		    "Truncating end of %d range above 4GB (%#jx-%#jx)\n",
1158224069Sjhb			    type, (uintmax_t)start, (uintmax_t)end);
1159224069Sjhb			end = ULONG_MAX;
1160224069Sjhb		}
1161224069Sjhb#endif
1162224069Sjhb		error = pcib_host_res_decodes(&args->sc->sc_host_res, type,
1163224069Sjhb		    start, end, flags);
1164224069Sjhb		if (error)
1165224069Sjhb			panic("Failed to manage %d range (%#jx-%#jx): %d",
1166224069Sjhb			    type, (uintmax_t)start, (uintmax_t)end, error);
1167224069Sjhb		break;
1168224069Sjhb	case MPCT_EXTENTRY_CBASM:
1169224069Sjhb		cbasm = (cbasm_entry_ptr)entry;
1170224069Sjhb		if (cbasm->bus_id != args->bus)
1171224069Sjhb			break;
1172224069Sjhb		switch (cbasm->predefined_range) {
1173224069Sjhb		case CBASMENTRY_RANGE_ISA_IO:
1174224069Sjhb			flagp = &args->sc->sc_decodes_isa_io;
1175224069Sjhb			name = "ISA I/O";
1176224069Sjhb			break;
1177224069Sjhb		case CBASMENTRY_RANGE_VGA_IO:
1178224069Sjhb			flagp = &args->sc->sc_decodes_vga_io;
1179224069Sjhb			name = "VGA I/O";
1180224069Sjhb			break;
1181224069Sjhb		default:
1182224069Sjhb			printf(
1183224069Sjhb    "MPTable: Unknown compatiblity address space range for bus %u: %d\n",
1184224069Sjhb			    cbasm->bus_id, cbasm->predefined_range);
1185224069Sjhb			return;
1186224069Sjhb		}
1187224069Sjhb		if (*flagp != 0)
1188224069Sjhb			printf(
1189224069Sjhb		    "MPTable: Duplicate compatibility %s range for bus %u\n",
1190224069Sjhb			    name, cbasm->bus_id);
1191224069Sjhb		switch (cbasm->address_mod) {
1192224069Sjhb		case CBASMENTRY_ADDRESS_MOD_ADD:
1193224069Sjhb			*flagp = 1;
1194224069Sjhb			if (bootverbose)
1195224069Sjhb				device_printf(args->dev, "decoding %s ports\n",
1196224069Sjhb				    name);
1197224069Sjhb			break;
1198224069Sjhb		case CBASMENTRY_ADDRESS_MOD_SUBTRACT:
1199224069Sjhb			*flagp = -1;
1200224069Sjhb			if (bootverbose)
1201224069Sjhb				device_printf(args->dev,
1202224069Sjhb				    "not decoding %s ports\n", name);
1203224069Sjhb			break;
1204224069Sjhb		default:
1205224069Sjhb			printf(
1206224069Sjhb	    "MPTable: Unknown compatibility address space modifier: %u\n",
1207224069Sjhb			    cbasm->address_mod);
1208224069Sjhb			break;
1209224069Sjhb		}
1210224069Sjhb		break;
1211224069Sjhb	}
1212224069Sjhb}
1213224069Sjhb
1214224069Sjhbvoid
1215224069Sjhbmptable_pci_host_res_init(device_t pcib)
1216224069Sjhb{
1217224069Sjhb	struct host_res_args args;
1218224069Sjhb
1219224069Sjhb	KASSERT(pci0 != -1, ("do not know how to map PCI bus IDs"));
1220224069Sjhb	args.bus = pci_get_bus(pcib) + pci0;
1221224069Sjhb	args.dev = pcib;
1222224069Sjhb	args.sc = device_get_softc(pcib);
1223224069Sjhb	if (pcib_host_res_init(pcib, &args.sc->sc_host_res) != 0)
1224224069Sjhb		panic("failed to init hostb resources");
1225224069Sjhb	mptable_walk_extended_table(mptable_host_res_handler, &args);
1226224069Sjhb}
1227224069Sjhb#endif
1228