]> git.ipfire.org Git - people/pmueller/ipfire-2.x.git/blob - src/hwinfo/src/smp/smp.c
Kleiner netter neuer Versuch.
[people/pmueller/ipfire-2.x.git] / src / hwinfo / src / smp / smp.c
1 /*
2 [_Anarchy_(alan@lightning.swansea.uk.linux.org)] you should do one check
3 though - if the board seems to be SMP and the CPU in /proc/cpuinfo is non
4 intel dont install an SMP kernel - thats a dual pentium board with a cyrix
5 or similar single cpu in it
6 */
7
8
9 #include <stdio.h>
10 #include <stdlib.h>
11 #include <unistd.h>
12 #include <fcntl.h>
13 #include <sys/mman.h>
14 #include <string.h>
15 #include <errno.h>
16
17 #ifdef __i386__
18 #define SMP_MAGIC_IDENT (('_'<<24)|('P'<<16)|('M'<<8)|'_')
19
20 struct intel_mp_floating
21 {
22 char mpf_signature[4]; /* "_MP_" */
23 unsigned long mpf_physptr; /* Configuration table address */
24 unsigned char mpf_length; /* Our length (paragraphs) */
25 unsigned char mpf_specification;/* Specification version */
26 unsigned char mpf_checksum; /* Checksum (makes sum 0) */
27 unsigned char mpf_feature1; /* Standard or configuration ? */
28 unsigned char mpf_feature2; /* Bit7 set for IMCR|PIC */
29 unsigned char mpf_feature3; /* Unused (0) */
30 unsigned char mpf_feature4; /* Unused (0) */
31 unsigned char mpf_feature5; /* Unused (0) */
32 };
33
34 struct mp_config_table
35 {
36 char mpc_signature[4];
37 #define MPC_SIGNATURE "PCMP"
38 unsigned short mpc_length; /* Size of table */
39 char mpc_spec; /* 0x01 */
40 char mpc_checksum;
41 char mpc_oem[8];
42 char mpc_productid[12];
43 unsigned long mpc_oemptr; /* 0 if not present */
44 unsigned short mpc_oemsize; /* 0 if not present */
45 unsigned short mpc_oemcount;
46 unsigned long mpc_lapic; /* APIC address */
47 unsigned long reserved;
48 };
49
50 /* Followed by entries */
51
52 #define MP_PROCESSOR 0
53 #define MP_BUS 1
54 #define MP_IOAPIC 2
55 #define MP_INTSRC 3
56 #define MP_LINTSRC 4
57
58 struct mpc_config_processor
59 {
60 unsigned char mpc_type;
61 unsigned char mpc_apicid; /* Local APIC number */
62 unsigned char mpc_apicver; /* Its versions */
63 unsigned char mpc_cpuflag;
64 #define CPU_ENABLED 1 /* Processor is available */
65 #define CPU_BOOTPROCESSOR 2 /* Processor is the BP */
66 unsigned long mpc_cpufeature;
67 #define CPU_STEPPING_MASK 0x0F
68 #define CPU_MODEL_MASK 0xF0
69 #define CPU_FAMILY_MASK 0xF00
70 unsigned long mpc_featureflag; /* CPUID feature value */
71 unsigned long mpc_reserved[2];
72 };
73
74 struct mpc_config_bus
75 {
76 unsigned char mpc_type;
77 unsigned char mpc_busid;
78 unsigned char mpc_bustype[6] __attribute((packed));
79 };
80
81 #define BUSTYPE_EISA "EISA"
82 #define BUSTYPE_ISA "ISA"
83 #define BUSTYPE_INTERN "INTERN" /* Internal BUS */
84 #define BUSTYPE_MCA "MCA"
85 #define BUSTYPE_VL "VL" /* Local bus */
86 #define BUSTYPE_PCI "PCI"
87 #define BUSTYPE_PCMCIA "PCMCIA"
88
89 /* We don't understand the others */
90
91 struct mpc_config_ioapic
92 {
93 unsigned char mpc_type;
94 unsigned char mpc_apicid;
95 unsigned char mpc_apicver;
96 unsigned char mpc_flags;
97 #define MPC_APIC_USABLE 0x01
98 unsigned long mpc_apicaddr;
99 };
100
101 struct mpc_config_intsrc
102 {
103 unsigned char mpc_type;
104 unsigned char mpc_irqtype;
105 unsigned short mpc_irqflag;
106 unsigned char mpc_srcbus;
107 unsigned char mpc_srcbusirq;
108 unsigned char mpc_dstapic;
109 unsigned char mpc_dstirq;
110 };
111
112 #define MP_INT_VECTORED 0
113 #define MP_INT_NMI 1
114 #define MP_INT_SMI 2
115 #define MP_INT_EXTINT 3
116
117 #define MP_IRQDIR_DEFAULT 0
118 #define MP_IRQDIR_HIGH 1
119 #define MP_IRQDIR_LOW 3
120
121
122 struct mpc_config_intlocal
123 {
124 unsigned char mpc_type;
125 unsigned char mpc_irqtype;
126 unsigned short mpc_irqflag;
127 unsigned char mpc_srcbusid;
128 unsigned char mpc_srcbusirq;
129 unsigned char mpc_destapic;
130 #define MP_APIC_ALL 0xFF
131 unsigned char mpc_destapiclint;
132 };
133
134
135 /*
136 * Default configurations
137 *
138 * 1 2 CPU ISA 82489DX
139 * 2 2 CPU EISA 82489DX no IRQ 8 or timer chaining
140 * 3 2 CPU EISA 82489DX
141 * 4 2 CPU MCA 82489DX
142 * 5 2 CPU ISA+PCI
143 * 6 2 CPU EISA+PCI
144 * 7 2 CPU MCA+PCI
145 */
146
147
148 static int smp_found_config=0;
149
150 /*
151 * Checksum an MP configuration block.
152 */
153
154 static int mpf_checksum(unsigned char *mp, int len)
155 {
156 int sum=0;
157 while(len--)
158 sum+=*mp++;
159 return sum&0xFF;
160 }
161
162 static int do_smp_scan_config(unsigned long *bp, unsigned long length)
163 {
164 struct intel_mp_floating *mpf;
165
166 /*
167 if (sizeof(*mpf)!=16)
168 logMessage("Error: MPF size\n");
169 */
170
171 while (length>0)
172 {
173 if (*bp==SMP_MAGIC_IDENT)
174 {
175 mpf=(struct intel_mp_floating *)bp;
176 if (mpf->mpf_length==1 &&
177 !mpf_checksum((unsigned char *)bp,16) &&
178 (mpf->mpf_specification == 1
179 || mpf->mpf_specification == 4) )
180 {
181 /*logMessage("Intel MultiProcessor Specification v1.%d\n", mpf->mpf_specification);
182 if (mpf->mpf_feature2&(1<<7))
183 logMessage(" IMCR and PIC compatibility mode.\n");
184 else
185 logMessage(" Virtual Wire compatibility mode.\n");
186 */
187 smp_found_config=1;
188 return 1;
189 }
190 }
191 bp+=4;
192 length-=16;
193 }
194
195 return 0;
196 }
197
198 static int smp_scan_config(int mem_fd, unsigned long base,
199 unsigned long length)
200 {
201 void *p;
202 int o;
203
204 o=base&0xFFF;
205 base-=o;
206 length+=o;
207
208 p=mmap(0, (length+4095)&0xFFFFF000, PROT_READ, MAP_SHARED,
209 mem_fd, (base&0xFFFF0000));
210 if(p==MAP_FAILED)
211 {
212 /*logMessage("SMP Probe error: mmap: %s", strerror(errno));*/
213 return 1;
214 }
215 do_smp_scan_config(p+o, length-o);
216 munmap(p, (length+4095)&0xFFFFF000);
217 return 0;
218 }
219
220 static int intelDetectSMP(void)
221 {
222 int mem_fd;
223
224 mem_fd=open("/dev/mem", O_RDONLY);
225
226 if(mem_fd==-1)
227 {
228 /*logMessage("Error detecting SMP: /dev/mem: %s", strerror(errno));*/
229 }
230
231 /*
232 * FIXME: Linux assumes you have 640K of base ram..
233 * this continues the error...
234 *
235 * 1) Scan the bottom 1K for a signature
236 * 2) Scan the top 1K of base RAM
237 * 3) Scan the 64K of bios
238 */
239 if (!smp_scan_config(mem_fd, 0x0, 0x400) &&
240 !smp_scan_config(mem_fd, 639*0x400,0x400) &&
241 !smp_scan_config(mem_fd, 0xF0000,0x10000)) {
242 #if 0
243
244 /*
245 * If it is an SMP machine we should know now, unless the
246 * configuration is in an EISA/MCA bus machine with an
247 * extended bios data area.
248 *
249 * there is a real-mode segmented pointer pointing to the
250 * 4K EBDA area at 0x40E, calculate and scan it here.
251 *
252 * NOTE! There are Linux loaders that will corrupt the EBDA
253 * area, and as such this kind of SMP config may be less
254 * trustworthy, simply because the SMP table may have been
255 * stomped on during early boot. These loaders are buggy and
256 * should be fixed.
257 */
258 unsigned int address;
259
260 address = *(unsigned short *)phys_to_virt(0x40E);
261 address<<=4;
262 smp_scan_config(mem_fd, address, 0x1000);
263 if (smp_found_config)
264 /*logMessage("WARNING: MP table in the EBDA can be UNSAFE, contact linux-smp@vger.rutgers.edu if you experience SMP problems!\n");*/
265 #endif
266 }
267 /*
268 if(smp_found_config)
269 logMessage("Detected SMP capable motherboard\n");
270 else
271 logMessage("Detected non SMP capable motherboard\n");
272 */
273 return smp_found_config;
274 }
275
276 int detectSMP(void)
277 {
278 static int isSMP = -1;
279
280 if (isSMP != -1)
281 return isSMP;
282
283 return isSMP = intelDetectSMP();
284 }
285
286 #endif /* __i386__ */