1/*-
2 * Copyright (c) 1999 Matthew N. Dodd <winter@jurai.net>
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 *    notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 *    notice, this list of conditions and the following disclaimer in the
12 *    documentation and/or other materials provided with the distribution.
13 *
14 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17 * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24 * SUCH DAMAGE.
25 */
26
27#include <sys/cdefs.h>
28__FBSDID("$FreeBSD$");
29
30#include <sys/param.h>
31#include <sys/systm.h>
32#include <sys/kernel.h>
33#include <vm/vm.h>
34#include <vm/vm_param.h>
35#include <vm/pmap.h>
36#include <machine/pmap.h>
37#include <machine/md_var.h>
38#include <machine/vm86.h>
39#include <machine/pc/bios.h>
40#include <machine/cpufunc.h>
41
42#include <dev/mca/mca_busreg.h>
43#include <i386/bios/mca_machdep.h>
44
45/* Global MCA bus flag */
46int MCA_system = 0;
47
48/* System Configuration Block */
49struct sys_config {
50	u_int16_t	count;
51	u_int8_t	model;
52	u_int8_t	submodel;
53	u_int8_t	bios_rev;
54	u_int8_t	feature;
55#define FEATURE_MCAISA	0x01	/* Machine contains both MCA and ISA bus*/
56#define FEATURE_MCABUS	0x02	/* MicroChannel Architecture		*/
57#define FEATURE_EBDA	0x04	/* Extended BIOS data area allocated	*/
58#define FEATURE_WAITEV	0x08	/* Wait for external event is supported	*/
59#define FEATURE_KBDINT	0x10	/* Keyboard intercept called by Int 09h	*/
60#define FEATURE_RTC	0x20	/* Real-time clock present		*/
61#define FEATURE_IC2	0x40	/* Second interrupt chip present	*/
62#define FEATURE_DMA3	0x80	/* DMA channel 3 used by hard disk BIOS	*/
63	u_int8_t	pad[3];
64} __packed;
65
66/* Function Prototypes */
67static void bios_mcabus_present	(void *);
68SYSINIT(mca_present, SI_SUB_CPU, SI_ORDER_ANY, bios_mcabus_present, NULL);
69
70/* Functions */
71static void
72bios_mcabus_present(void * dummy)
73{
74	struct vm86frame	vmf;
75	struct sys_config *	scp;
76	vm_offset_t		paddr;
77
78	bzero(&vmf, sizeof(struct vm86frame));
79
80	vmf.vmf_ah = 0xc0;
81	if (vm86_intcall(0x15, &vmf)) {
82		if (bootverbose) {
83			printf("BIOS SDT: INT call failed.\n");
84		}
85		return;
86	}
87
88	if ((vmf.vmf_ah != 0) && (vmf.vmf_flags & 0x01)) {
89		if (bootverbose) {
90			printf("BIOS SDT: Not supported.  Not PS/2?\n");
91			printf("BIOS SDT: AH 0x%02x, Flags 0x%04x\n",
92				vmf.vmf_ah, vmf.vmf_flags);
93		}
94		return;
95	}
96
97	paddr = vmf.vmf_es;
98	paddr = (paddr << 4) + vmf.vmf_bx;
99	scp = (struct sys_config *)BIOS_PADDRTOVADDR(paddr);
100
101	if (bootverbose) {
102		printf("BIOS SDT: model 0x%02x, submodel 0x%02x, bios_rev 0x%02x\n",
103			scp->model, scp->submodel, scp->bios_rev);
104		printf("BIOS SDT: features 0x%b\n", scp->feature,
105			"\20"
106			"\01MCA+ISA"
107			"\02MCA"
108			"\03EBDA"
109			"\04WAITEV"
110			"\05KBDINT"
111			"\06RTC"
112			"\07IC2"
113			"\08DMA3"
114			"\n");
115	}
116
117	MCA_system = ((scp->feature & FEATURE_MCABUS) ? 1 : 0);
118
119	if (MCA_system)
120		printf("MicroChannel Architecture System detected.\n");
121
122	return;
123}
124
125int
126mca_bus_nmi (void)
127{
128	int	slot;
129	int	retval = 0;
130	int	pos5 = 0;
131
132	/* Disable motherboard setup */
133	outb(MCA_MB_SETUP_REG, MCA_MB_SETUP_DIS);
134
135	/* For each slot */
136	for (slot = 0; slot < MCA_MAX_SLOTS; slot++) {
137
138		/* Select the slot */
139		outb(MCA_ADAP_SETUP_REG, slot | MCA_ADAP_SET);
140		pos5 = inb(MCA_POS_REG(MCA_POS5));
141
142		/* If Adapter Check is low */
143		if ((pos5 & MCA_POS5_CHCK) == 0) {
144			retval++;
145
146			/* If Adapter Check Status is available */
147			if ((pos5 & MCA_POS5_CHCK_STAT) == 0) {
148				printf("MCA NMI: slot %d, POS6=0x%02x, POS7=0x%02x\n",
149					slot+1,
150					inb( MCA_POS_REG(MCA_POS6) ),
151					inb( MCA_POS_REG(MCA_POS7) ));
152			} else {
153				printf("MCA NMI: slot %d\n", slot+1);
154			}
155		}
156		/* Disable adapter setup */
157		outb(MCA_ADAP_SETUP_REG, MCA_ADAP_SETUP_DIS);
158	}
159
160	return (retval);
161}
162