diff options
Diffstat (limited to 'arch/x86/kernel/mca_32.c')
-rw-r--r-- | arch/x86/kernel/mca_32.c | 476 |
1 files changed, 0 insertions, 476 deletions
diff --git a/arch/x86/kernel/mca_32.c b/arch/x86/kernel/mca_32.c deleted file mode 100644 index 7eb1e2b97827..000000000000 --- a/arch/x86/kernel/mca_32.c +++ /dev/null | |||
@@ -1,476 +0,0 @@ | |||
1 | /* | ||
2 | * Written by Martin Kolinek, February 1996 | ||
3 | * | ||
4 | * Changes: | ||
5 | * | ||
6 | * Chris Beauregard July 28th, 1996 | ||
7 | * - Fixed up integrated SCSI detection | ||
8 | * | ||
9 | * Chris Beauregard August 3rd, 1996 | ||
10 | * - Made mca_info local | ||
11 | * - Made integrated registers accessible through standard function calls | ||
12 | * - Added name field | ||
13 | * - More sanity checking | ||
14 | * | ||
15 | * Chris Beauregard August 9th, 1996 | ||
16 | * - Rewrote /proc/mca | ||
17 | * | ||
18 | * Chris Beauregard January 7th, 1997 | ||
19 | * - Added basic NMI-processing | ||
20 | * - Added more information to mca_info structure | ||
21 | * | ||
22 | * David Weinehall October 12th, 1998 | ||
23 | * - Made a lot of cleaning up in the source | ||
24 | * - Added use of save_flags / restore_flags | ||
25 | * - Added the 'driver_loaded' flag in MCA_adapter | ||
26 | * - Added an alternative implemention of ZP Gu's mca_find_unused_adapter | ||
27 | * | ||
28 | * David Weinehall March 24th, 1999 | ||
29 | * - Fixed the output of 'Driver Installed' in /proc/mca/pos | ||
30 | * - Made the Integrated Video & SCSI show up even if they have id 0000 | ||
31 | * | ||
32 | * Alexander Viro November 9th, 1999 | ||
33 | * - Switched to regular procfs methods | ||
34 | * | ||
35 | * Alfred Arnold & David Weinehall August 23rd, 2000 | ||
36 | * - Added support for Planar POS-registers | ||
37 | */ | ||
38 | |||
39 | #include <linux/module.h> | ||
40 | #include <linux/types.h> | ||
41 | #include <linux/errno.h> | ||
42 | #include <linux/kernel.h> | ||
43 | #include <linux/mca.h> | ||
44 | #include <linux/kprobes.h> | ||
45 | #include <linux/slab.h> | ||
46 | #include <asm/io.h> | ||
47 | #include <linux/proc_fs.h> | ||
48 | #include <linux/mman.h> | ||
49 | #include <linux/mm.h> | ||
50 | #include <linux/pagemap.h> | ||
51 | #include <linux/ioport.h> | ||
52 | #include <asm/uaccess.h> | ||
53 | #include <linux/init.h> | ||
54 | |||
55 | static unsigned char which_scsi; | ||
56 | |||
57 | int MCA_bus; | ||
58 | EXPORT_SYMBOL(MCA_bus); | ||
59 | |||
60 | /* | ||
61 | * Motherboard register spinlock. Untested on SMP at the moment, but | ||
62 | * are there any MCA SMP boxes? | ||
63 | * | ||
64 | * Yes - Alan | ||
65 | */ | ||
66 | static DEFINE_SPINLOCK(mca_lock); | ||
67 | |||
68 | /* Build the status info for the adapter */ | ||
69 | |||
70 | static void mca_configure_adapter_status(struct mca_device *mca_dev) | ||
71 | { | ||
72 | mca_dev->status = MCA_ADAPTER_NONE; | ||
73 | |||
74 | mca_dev->pos_id = mca_dev->pos[0] | ||
75 | + (mca_dev->pos[1] << 8); | ||
76 | |||
77 | if (!mca_dev->pos_id && mca_dev->slot < MCA_MAX_SLOT_NR) { | ||
78 | |||
79 | /* | ||
80 | * id = 0x0000 usually indicates hardware failure, | ||
81 | * however, ZP Gu (zpg@castle.net> reports that his 9556 | ||
82 | * has 0x0000 as id and everything still works. There | ||
83 | * also seem to be an adapter with id = 0x0000; the | ||
84 | * NCR Parallel Bus Memory Card. Until this is confirmed, | ||
85 | * however, this code will stay. | ||
86 | */ | ||
87 | |||
88 | mca_dev->status = MCA_ADAPTER_ERROR; | ||
89 | |||
90 | return; | ||
91 | } else if (mca_dev->pos_id != 0xffff) { | ||
92 | |||
93 | /* | ||
94 | * 0xffff usually indicates that there's no adapter, | ||
95 | * however, some integrated adapters may have 0xffff as | ||
96 | * their id and still be valid. Examples are on-board | ||
97 | * VGA of the 55sx, the integrated SCSI of the 56 & 57, | ||
98 | * and possibly also the 95 ULTIMEDIA. | ||
99 | */ | ||
100 | |||
101 | mca_dev->status = MCA_ADAPTER_NORMAL; | ||
102 | } | ||
103 | |||
104 | if ((mca_dev->pos_id == 0xffff || | ||
105 | mca_dev->pos_id == 0x0000) && mca_dev->slot >= MCA_MAX_SLOT_NR) { | ||
106 | int j; | ||
107 | |||
108 | for (j = 2; j < 8; j++) { | ||
109 | if (mca_dev->pos[j] != 0xff) { | ||
110 | mca_dev->status = MCA_ADAPTER_NORMAL; | ||
111 | break; | ||
112 | } | ||
113 | } | ||
114 | } | ||
115 | |||
116 | if (!(mca_dev->pos[2] & MCA_ENABLED)) { | ||
117 | |||
118 | /* enabled bit is in POS 2 */ | ||
119 | |||
120 | mca_dev->status = MCA_ADAPTER_DISABLED; | ||
121 | } | ||
122 | } /* mca_configure_adapter_status */ | ||
123 | |||
124 | /*--------------------------------------------------------------------*/ | ||
125 | |||
126 | static struct resource mca_standard_resources[] = { | ||
127 | { .start = 0x60, .end = 0x60, .name = "system control port B (MCA)" }, | ||
128 | { .start = 0x90, .end = 0x90, .name = "arbitration (MCA)" }, | ||
129 | { .start = 0x91, .end = 0x91, .name = "card Select Feedback (MCA)" }, | ||
130 | { .start = 0x92, .end = 0x92, .name = "system Control port A (MCA)" }, | ||
131 | { .start = 0x94, .end = 0x94, .name = "system board setup (MCA)" }, | ||
132 | { .start = 0x96, .end = 0x97, .name = "POS (MCA)" }, | ||
133 | { .start = 0x100, .end = 0x107, .name = "POS (MCA)" } | ||
134 | }; | ||
135 | |||
136 | #define MCA_STANDARD_RESOURCES ARRAY_SIZE(mca_standard_resources) | ||
137 | |||
138 | /* | ||
139 | * mca_read_and_store_pos - read the POS registers into a memory buffer | ||
140 | * @pos: a char pointer to 8 bytes, contains the POS register value on | ||
141 | * successful return | ||
142 | * | ||
143 | * Returns 1 if a card actually exists (i.e. the pos isn't | ||
144 | * all 0xff) or 0 otherwise | ||
145 | */ | ||
146 | static int mca_read_and_store_pos(unsigned char *pos) | ||
147 | { | ||
148 | int j; | ||
149 | int found = 0; | ||
150 | |||
151 | for (j = 0; j < 8; j++) { | ||
152 | pos[j] = inb_p(MCA_POS_REG(j)); | ||
153 | if (pos[j] != 0xff) { | ||
154 | /* 0xff all across means no device. 0x00 means | ||
155 | * something's broken, but a device is | ||
156 | * probably there. However, if you get 0x00 | ||
157 | * from a motherboard register it won't matter | ||
158 | * what we find. For the record, on the | ||
159 | * 57SLC, the integrated SCSI adapter has | ||
160 | * 0xffff for the adapter ID, but nonzero for | ||
161 | * other registers. */ | ||
162 | |||
163 | found = 1; | ||
164 | } | ||
165 | } | ||
166 | return found; | ||
167 | } | ||
168 | |||
169 | static unsigned char mca_pc_read_pos(struct mca_device *mca_dev, int reg) | ||
170 | { | ||
171 | unsigned char byte; | ||
172 | unsigned long flags; | ||
173 | |||
174 | if (reg < 0 || reg >= 8) | ||
175 | return 0; | ||
176 | |||
177 | spin_lock_irqsave(&mca_lock, flags); | ||
178 | if (mca_dev->pos_register) { | ||
179 | /* Disable adapter setup, enable motherboard setup */ | ||
180 | |||
181 | outb_p(0, MCA_ADAPTER_SETUP_REG); | ||
182 | outb_p(mca_dev->pos_register, MCA_MOTHERBOARD_SETUP_REG); | ||
183 | |||
184 | byte = inb_p(MCA_POS_REG(reg)); | ||
185 | outb_p(0xff, MCA_MOTHERBOARD_SETUP_REG); | ||
186 | } else { | ||
187 | |||
188 | /* Make sure motherboard setup is off */ | ||
189 | |||
190 | outb_p(0xff, MCA_MOTHERBOARD_SETUP_REG); | ||
191 | |||
192 | /* Read the appropriate register */ | ||
193 | |||
194 | outb_p(0x8|(mca_dev->slot & 0xf), MCA_ADAPTER_SETUP_REG); | ||
195 | byte = inb_p(MCA_POS_REG(reg)); | ||
196 | outb_p(0, MCA_ADAPTER_SETUP_REG); | ||
197 | } | ||
198 | spin_unlock_irqrestore(&mca_lock, flags); | ||
199 | |||
200 | mca_dev->pos[reg] = byte; | ||
201 | |||
202 | return byte; | ||
203 | } | ||
204 | |||
205 | static void mca_pc_write_pos(struct mca_device *mca_dev, int reg, | ||
206 | unsigned char byte) | ||
207 | { | ||
208 | unsigned long flags; | ||
209 | |||
210 | if (reg < 0 || reg >= 8) | ||
211 | return; | ||
212 | |||
213 | spin_lock_irqsave(&mca_lock, flags); | ||
214 | |||
215 | /* Make sure motherboard setup is off */ | ||
216 | |||
217 | outb_p(0xff, MCA_MOTHERBOARD_SETUP_REG); | ||
218 | |||
219 | /* Read in the appropriate register */ | ||
220 | |||
221 | outb_p(0x8|(mca_dev->slot&0xf), MCA_ADAPTER_SETUP_REG); | ||
222 | outb_p(byte, MCA_POS_REG(reg)); | ||
223 | outb_p(0, MCA_ADAPTER_SETUP_REG); | ||
224 | |||
225 | spin_unlock_irqrestore(&mca_lock, flags); | ||
226 | |||
227 | /* Update the global register list, while we have the byte */ | ||
228 | |||
229 | mca_dev->pos[reg] = byte; | ||
230 | |||
231 | } | ||
232 | |||
233 | /* for the primary MCA bus, we have identity transforms */ | ||
234 | static int mca_dummy_transform_irq(struct mca_device *mca_dev, int irq) | ||
235 | { | ||
236 | return irq; | ||
237 | } | ||
238 | |||
239 | static int mca_dummy_transform_ioport(struct mca_device *mca_dev, int port) | ||
240 | { | ||
241 | return port; | ||
242 | } | ||
243 | |||
244 | static void *mca_dummy_transform_memory(struct mca_device *mca_dev, void *mem) | ||
245 | { | ||
246 | return mem; | ||
247 | } | ||
248 | |||
249 | |||
250 | static int __init mca_init(void) | ||
251 | { | ||
252 | unsigned int i, j; | ||
253 | struct mca_device *mca_dev; | ||
254 | unsigned char pos[8]; | ||
255 | short mca_builtin_scsi_ports[] = {0xf7, 0xfd, 0x00}; | ||
256 | struct mca_bus *bus; | ||
257 | |||
258 | /* | ||
259 | * WARNING: Be careful when making changes here. Putting an adapter | ||
260 | * and the motherboard simultaneously into setup mode may result in | ||
261 | * damage to chips (according to The Indispensable PC Hardware Book | ||
262 | * by Hans-Peter Messmer). Also, we disable system interrupts (so | ||
263 | * that we are not disturbed in the middle of this). | ||
264 | */ | ||
265 | |||
266 | /* Make sure the MCA bus is present */ | ||
267 | |||
268 | if (mca_system_init()) { | ||
269 | printk(KERN_ERR "MCA bus system initialisation failed\n"); | ||
270 | return -ENODEV; | ||
271 | } | ||
272 | |||
273 | if (!MCA_bus) | ||
274 | return -ENODEV; | ||
275 | |||
276 | printk(KERN_INFO "Micro Channel bus detected.\n"); | ||
277 | |||
278 | /* All MCA systems have at least a primary bus */ | ||
279 | bus = mca_attach_bus(MCA_PRIMARY_BUS); | ||
280 | if (!bus) | ||
281 | goto out_nomem; | ||
282 | bus->default_dma_mask = 0xffffffffLL; | ||
283 | bus->f.mca_write_pos = mca_pc_write_pos; | ||
284 | bus->f.mca_read_pos = mca_pc_read_pos; | ||
285 | bus->f.mca_transform_irq = mca_dummy_transform_irq; | ||
286 | bus->f.mca_transform_ioport = mca_dummy_transform_ioport; | ||
287 | bus->f.mca_transform_memory = mca_dummy_transform_memory; | ||
288 | |||
289 | /* get the motherboard device */ | ||
290 | mca_dev = kzalloc(sizeof(struct mca_device), GFP_KERNEL); | ||
291 | if (unlikely(!mca_dev)) | ||
292 | goto out_nomem; | ||
293 | |||
294 | /* | ||
295 | * We do not expect many MCA interrupts during initialization, | ||
296 | * but let us be safe: | ||
297 | */ | ||
298 | spin_lock_irq(&mca_lock); | ||
299 | |||
300 | /* Make sure adapter setup is off */ | ||
301 | |||
302 | outb_p(0, MCA_ADAPTER_SETUP_REG); | ||
303 | |||
304 | /* Read motherboard POS registers */ | ||
305 | |||
306 | mca_dev->pos_register = 0x7f; | ||
307 | outb_p(mca_dev->pos_register, MCA_MOTHERBOARD_SETUP_REG); | ||
308 | mca_dev->name[0] = 0; | ||
309 | mca_read_and_store_pos(mca_dev->pos); | ||
310 | mca_configure_adapter_status(mca_dev); | ||
311 | /* fake POS and slot for a motherboard */ | ||
312 | mca_dev->pos_id = MCA_MOTHERBOARD_POS; | ||
313 | mca_dev->slot = MCA_MOTHERBOARD; | ||
314 | mca_register_device(MCA_PRIMARY_BUS, mca_dev); | ||
315 | |||
316 | mca_dev = kzalloc(sizeof(struct mca_device), GFP_ATOMIC); | ||
317 | if (unlikely(!mca_dev)) | ||
318 | goto out_unlock_nomem; | ||
319 | |||
320 | /* Put motherboard into video setup mode, read integrated video | ||
321 | * POS registers, and turn motherboard setup off. | ||
322 | */ | ||
323 | |||
324 | mca_dev->pos_register = 0xdf; | ||
325 | outb_p(mca_dev->pos_register, MCA_MOTHERBOARD_SETUP_REG); | ||
326 | mca_dev->name[0] = 0; | ||
327 | mca_read_and_store_pos(mca_dev->pos); | ||
328 | mca_configure_adapter_status(mca_dev); | ||
329 | /* fake POS and slot for the integrated video */ | ||
330 | mca_dev->pos_id = MCA_INTEGVIDEO_POS; | ||
331 | mca_dev->slot = MCA_INTEGVIDEO; | ||
332 | mca_register_device(MCA_PRIMARY_BUS, mca_dev); | ||
333 | |||
334 | /* | ||
335 | * Put motherboard into scsi setup mode, read integrated scsi | ||
336 | * POS registers, and turn motherboard setup off. | ||
337 | * | ||
338 | * It seems there are two possible SCSI registers. Martin says that | ||
339 | * for the 56,57, 0xf7 is the one, but fails on the 76. | ||
340 | * Alfredo (apena@vnet.ibm.com) says | ||
341 | * 0xfd works on his machine. We'll try both of them. I figure it's | ||
342 | * a good bet that only one could be valid at a time. This could | ||
343 | * screw up though if one is used for something else on the other | ||
344 | * machine. | ||
345 | */ | ||
346 | |||
347 | for (i = 0; (which_scsi = mca_builtin_scsi_ports[i]) != 0; i++) { | ||
348 | outb_p(which_scsi, MCA_MOTHERBOARD_SETUP_REG); | ||
349 | if (mca_read_and_store_pos(pos)) | ||
350 | break; | ||
351 | } | ||
352 | if (which_scsi) { | ||
353 | /* found a scsi card */ | ||
354 | mca_dev = kzalloc(sizeof(struct mca_device), GFP_ATOMIC); | ||
355 | if (unlikely(!mca_dev)) | ||
356 | goto out_unlock_nomem; | ||
357 | |||
358 | for (j = 0; j < 8; j++) | ||
359 | mca_dev->pos[j] = pos[j]; | ||
360 | |||
361 | mca_configure_adapter_status(mca_dev); | ||
362 | /* fake POS and slot for integrated SCSI controller */ | ||
363 | mca_dev->pos_id = MCA_INTEGSCSI_POS; | ||
364 | mca_dev->slot = MCA_INTEGSCSI; | ||
365 | mca_dev->pos_register = which_scsi; | ||
366 | mca_register_device(MCA_PRIMARY_BUS, mca_dev); | ||
367 | } | ||
368 | |||
369 | /* Turn off motherboard setup */ | ||
370 | |||
371 | outb_p(0xff, MCA_MOTHERBOARD_SETUP_REG); | ||
372 | |||
373 | /* | ||
374 | * Now loop over MCA slots: put each adapter into setup mode, and | ||
375 | * read its POS registers. Then put adapter setup off. | ||
376 | */ | ||
377 | |||
378 | for (i = 0; i < MCA_MAX_SLOT_NR; i++) { | ||
379 | outb_p(0x8|(i&0xf), MCA_ADAPTER_SETUP_REG); | ||
380 | if (!mca_read_and_store_pos(pos)) | ||
381 | continue; | ||
382 | |||
383 | mca_dev = kzalloc(sizeof(struct mca_device), GFP_ATOMIC); | ||
384 | if (unlikely(!mca_dev)) | ||
385 | goto out_unlock_nomem; | ||
386 | |||
387 | for (j = 0; j < 8; j++) | ||
388 | mca_dev->pos[j] = pos[j]; | ||
389 | |||
390 | mca_dev->driver_loaded = 0; | ||
391 | mca_dev->slot = i; | ||
392 | mca_dev->pos_register = 0; | ||
393 | mca_configure_adapter_status(mca_dev); | ||
394 | mca_register_device(MCA_PRIMARY_BUS, mca_dev); | ||
395 | } | ||
396 | outb_p(0, MCA_ADAPTER_SETUP_REG); | ||
397 | |||
398 | /* Enable interrupts and return memory start */ | ||
399 | spin_unlock_irq(&mca_lock); | ||
400 | |||
401 | for (i = 0; i < MCA_STANDARD_RESOURCES; i++) | ||
402 | request_resource(&ioport_resource, mca_standard_resources + i); | ||
403 | |||
404 | mca_do_proc_init(); | ||
405 | |||
406 | return 0; | ||
407 | |||
408 | out_unlock_nomem: | ||
409 | spin_unlock_irq(&mca_lock); | ||
410 | out_nomem: | ||
411 | printk(KERN_EMERG "Failed memory allocation in MCA setup!\n"); | ||
412 | return -ENOMEM; | ||
413 | } | ||
414 | |||
415 | subsys_initcall(mca_init); | ||
416 | |||
417 | /*--------------------------------------------------------------------*/ | ||
418 | |||
419 | static __kprobes void | ||
420 | mca_handle_nmi_device(struct mca_device *mca_dev, int check_flag) | ||
421 | { | ||
422 | int slot = mca_dev->slot; | ||
423 | |||
424 | if (slot == MCA_INTEGSCSI) { | ||
425 | printk(KERN_CRIT "NMI: caused by MCA integrated SCSI adapter (%s)\n", | ||
426 | mca_dev->name); | ||
427 | } else if (slot == MCA_INTEGVIDEO) { | ||
428 | printk(KERN_CRIT "NMI: caused by MCA integrated video adapter (%s)\n", | ||
429 | mca_dev->name); | ||
430 | } else if (slot == MCA_MOTHERBOARD) { | ||
431 | printk(KERN_CRIT "NMI: caused by motherboard (%s)\n", | ||
432 | mca_dev->name); | ||
433 | } | ||
434 | |||
435 | /* More info available in POS 6 and 7? */ | ||
436 | |||
437 | if (check_flag) { | ||
438 | unsigned char pos6, pos7; | ||
439 | |||
440 | pos6 = mca_device_read_pos(mca_dev, 6); | ||
441 | pos7 = mca_device_read_pos(mca_dev, 7); | ||
442 | |||
443 | printk(KERN_CRIT "NMI: POS 6 = 0x%x, POS 7 = 0x%x\n", pos6, pos7); | ||
444 | } | ||
445 | |||
446 | } /* mca_handle_nmi_slot */ | ||
447 | |||
448 | /*--------------------------------------------------------------------*/ | ||
449 | |||
450 | static int __kprobes mca_handle_nmi_callback(struct device *dev, void *data) | ||
451 | { | ||
452 | struct mca_device *mca_dev = to_mca_device(dev); | ||
453 | unsigned char pos5; | ||
454 | |||
455 | pos5 = mca_device_read_pos(mca_dev, 5); | ||
456 | |||
457 | if (!(pos5 & 0x80)) { | ||
458 | /* | ||
459 | * Bit 7 of POS 5 is reset when this adapter has a hardware | ||
460 | * error. Bit 7 it reset if there's error information | ||
461 | * available in POS 6 and 7. | ||
462 | */ | ||
463 | mca_handle_nmi_device(mca_dev, !(pos5 & 0x40)); | ||
464 | return 1; | ||
465 | } | ||
466 | return 0; | ||
467 | } | ||
468 | |||
469 | void __kprobes mca_handle_nmi(void) | ||
470 | { | ||
471 | /* | ||
472 | * First try - scan the various adapters and see if a specific | ||
473 | * adapter was responsible for the error. | ||
474 | */ | ||
475 | bus_for_each_dev(&mca_bus_type, NULL, NULL, mca_handle_nmi_callback); | ||
476 | } | ||