1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
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 <asm/system.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#include <asm/arch_hooks.h>
55
56static unsigned char which_scsi;
57
58int MCA_bus;
59EXPORT_SYMBOL(MCA_bus);
60
61
62
63
64
65
66
67static DEFINE_SPINLOCK(mca_lock);
68
69
70
71static void mca_configure_adapter_status(struct mca_device *mca_dev)
72{
73 mca_dev->status = MCA_ADAPTER_NONE;
74
75 mca_dev->pos_id = mca_dev->pos[0]
76 + (mca_dev->pos[1] << 8);
77
78 if (!mca_dev->pos_id && mca_dev->slot < MCA_MAX_SLOT_NR) {
79
80
81
82
83
84
85
86
87
88
89 mca_dev->status = MCA_ADAPTER_ERROR;
90
91 return;
92 } else if (mca_dev->pos_id != 0xffff) {
93
94
95
96
97
98
99
100
101
102 mca_dev->status = MCA_ADAPTER_NORMAL;
103 }
104
105 if ((mca_dev->pos_id == 0xffff ||
106 mca_dev->pos_id == 0x0000) && mca_dev->slot >= MCA_MAX_SLOT_NR) {
107 int j;
108
109 for (j = 2; j < 8; j++) {
110 if (mca_dev->pos[j] != 0xff) {
111 mca_dev->status = MCA_ADAPTER_NORMAL;
112 break;
113 }
114 }
115 }
116
117 if (!(mca_dev->pos[2] & MCA_ENABLED)) {
118
119
120
121 mca_dev->status = MCA_ADAPTER_DISABLED;
122 }
123}
124
125
126
127static struct resource mca_standard_resources[] = {
128 { .start = 0x60, .end = 0x60, .name = "system control port B (MCA)" },
129 { .start = 0x90, .end = 0x90, .name = "arbitration (MCA)" },
130 { .start = 0x91, .end = 0x91, .name = "card Select Feedback (MCA)" },
131 { .start = 0x92, .end = 0x92, .name = "system Control port A (MCA)" },
132 { .start = 0x94, .end = 0x94, .name = "system board setup (MCA)" },
133 { .start = 0x96, .end = 0x97, .name = "POS (MCA)" },
134 { .start = 0x100, .end = 0x107, .name = "POS (MCA)" }
135};
136
137#define MCA_STANDARD_RESOURCES ARRAY_SIZE(mca_standard_resources)
138
139
140
141
142
143
144
145
146
147static int mca_read_and_store_pos(unsigned char *pos)
148{
149 int j;
150 int found = 0;
151
152 for (j = 0; j < 8; j++) {
153 pos[j] = inb_p(MCA_POS_REG(j));
154 if (pos[j] != 0xff) {
155
156
157
158
159
160
161
162
163
164 found = 1;
165 }
166 }
167 return found;
168}
169
170static unsigned char mca_pc_read_pos(struct mca_device *mca_dev, int reg)
171{
172 unsigned char byte;
173 unsigned long flags;
174
175 if (reg < 0 || reg >= 8)
176 return 0;
177
178 spin_lock_irqsave(&mca_lock, flags);
179 if (mca_dev->pos_register) {
180
181
182 outb_p(0, MCA_ADAPTER_SETUP_REG);
183 outb_p(mca_dev->pos_register, MCA_MOTHERBOARD_SETUP_REG);
184
185 byte = inb_p(MCA_POS_REG(reg));
186 outb_p(0xff, MCA_MOTHERBOARD_SETUP_REG);
187 } else {
188
189
190
191 outb_p(0xff, MCA_MOTHERBOARD_SETUP_REG);
192
193
194
195 outb_p(0x8|(mca_dev->slot & 0xf), MCA_ADAPTER_SETUP_REG);
196 byte = inb_p(MCA_POS_REG(reg));
197 outb_p(0, MCA_ADAPTER_SETUP_REG);
198 }
199 spin_unlock_irqrestore(&mca_lock, flags);
200
201 mca_dev->pos[reg] = byte;
202
203 return byte;
204}
205
206static void mca_pc_write_pos(struct mca_device *mca_dev, int reg,
207 unsigned char byte)
208{
209 unsigned long flags;
210
211 if (reg < 0 || reg >= 8)
212 return;
213
214 spin_lock_irqsave(&mca_lock, flags);
215
216
217
218 outb_p(0xff, MCA_MOTHERBOARD_SETUP_REG);
219
220
221
222 outb_p(0x8|(mca_dev->slot&0xf), MCA_ADAPTER_SETUP_REG);
223 outb_p(byte, MCA_POS_REG(reg));
224 outb_p(0, MCA_ADAPTER_SETUP_REG);
225
226 spin_unlock_irqrestore(&mca_lock, flags);
227
228
229
230 mca_dev->pos[reg] = byte;
231
232}
233
234
235static int mca_dummy_transform_irq(struct mca_device *mca_dev, int irq)
236{
237 return irq;
238}
239
240static int mca_dummy_transform_ioport(struct mca_device *mca_dev, int port)
241{
242 return port;
243}
244
245static void *mca_dummy_transform_memory(struct mca_device *mca_dev, void *mem)
246{
247 return mem;
248}
249
250
251static int __init mca_init(void)
252{
253 unsigned int i, j;
254 struct mca_device *mca_dev;
255 unsigned char pos[8];
256 short mca_builtin_scsi_ports[] = {0xf7, 0xfd, 0x00};
257 struct mca_bus *bus;
258
259
260
261
262
263
264
265
266
267
268
269 if (mca_system_init()) {
270 printk(KERN_ERR "MCA bus system initialisation failed\n");
271 return -ENODEV;
272 }
273
274 if (!MCA_bus)
275 return -ENODEV;
276
277 printk(KERN_INFO "Micro Channel bus detected.\n");
278
279
280 bus = mca_attach_bus(MCA_PRIMARY_BUS);
281 if (!bus)
282 goto out_nomem;
283 bus->default_dma_mask = 0xffffffffLL;
284 bus->f.mca_write_pos = mca_pc_write_pos;
285 bus->f.mca_read_pos = mca_pc_read_pos;
286 bus->f.mca_transform_irq = mca_dummy_transform_irq;
287 bus->f.mca_transform_ioport = mca_dummy_transform_ioport;
288 bus->f.mca_transform_memory = mca_dummy_transform_memory;
289
290
291 mca_dev = kzalloc(sizeof(struct mca_device), GFP_KERNEL);
292 if (unlikely(!mca_dev))
293 goto out_nomem;
294
295
296
297
298
299 spin_lock_irq(&mca_lock);
300
301
302
303 outb_p(0, MCA_ADAPTER_SETUP_REG);
304
305
306
307 mca_dev->pos_register = 0x7f;
308 outb_p(mca_dev->pos_register, MCA_MOTHERBOARD_SETUP_REG);
309 mca_dev->name[0] = 0;
310 mca_read_and_store_pos(mca_dev->pos);
311 mca_configure_adapter_status(mca_dev);
312
313 mca_dev->pos_id = MCA_MOTHERBOARD_POS;
314 mca_dev->slot = MCA_MOTHERBOARD;
315 mca_register_device(MCA_PRIMARY_BUS, mca_dev);
316
317 mca_dev = kzalloc(sizeof(struct mca_device), GFP_ATOMIC);
318 if (unlikely(!mca_dev))
319 goto out_unlock_nomem;
320
321
322
323
324
325 mca_dev->pos_register = 0xdf;
326 outb_p(mca_dev->pos_register, MCA_MOTHERBOARD_SETUP_REG);
327 mca_dev->name[0] = 0;
328 mca_read_and_store_pos(mca_dev->pos);
329 mca_configure_adapter_status(mca_dev);
330
331 mca_dev->pos_id = MCA_INTEGVIDEO_POS;
332 mca_dev->slot = MCA_INTEGVIDEO;
333 mca_register_device(MCA_PRIMARY_BUS, mca_dev);
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348 for (i = 0; (which_scsi = mca_builtin_scsi_ports[i]) != 0; i++) {
349 outb_p(which_scsi, MCA_MOTHERBOARD_SETUP_REG);
350 if (mca_read_and_store_pos(pos))
351 break;
352 }
353 if (which_scsi) {
354
355 mca_dev = kzalloc(sizeof(struct mca_device), GFP_ATOMIC);
356 if (unlikely(!mca_dev))
357 goto out_unlock_nomem;
358
359 for (j = 0; j < 8; j++)
360 mca_dev->pos[j] = pos[j];
361
362 mca_configure_adapter_status(mca_dev);
363
364 mca_dev->pos_id = MCA_INTEGSCSI_POS;
365 mca_dev->slot = MCA_INTEGSCSI;
366 mca_dev->pos_register = which_scsi;
367 mca_register_device(MCA_PRIMARY_BUS, mca_dev);
368 }
369
370
371
372 outb_p(0xff, MCA_MOTHERBOARD_SETUP_REG);
373
374
375
376
377
378
379 for (i = 0; i < MCA_MAX_SLOT_NR; i++) {
380 outb_p(0x8|(i&0xf), MCA_ADAPTER_SETUP_REG);
381 if (!mca_read_and_store_pos(pos))
382 continue;
383
384 mca_dev = kzalloc(sizeof(struct mca_device), GFP_ATOMIC);
385 if (unlikely(!mca_dev))
386 goto out_unlock_nomem;
387
388 for (j = 0; j < 8; j++)
389 mca_dev->pos[j] = pos[j];
390
391 mca_dev->driver_loaded = 0;
392 mca_dev->slot = i;
393 mca_dev->pos_register = 0;
394 mca_configure_adapter_status(mca_dev);
395 mca_register_device(MCA_PRIMARY_BUS, mca_dev);
396 }
397 outb_p(0, MCA_ADAPTER_SETUP_REG);
398
399
400 spin_unlock_irq(&mca_lock);
401
402 for (i = 0; i < MCA_STANDARD_RESOURCES; i++)
403 request_resource(&ioport_resource, mca_standard_resources + i);
404
405 mca_do_proc_init();
406
407 return 0;
408
409 out_unlock_nomem:
410 spin_unlock_irq(&mca_lock);
411 out_nomem:
412 printk(KERN_EMERG "Failed memory allocation in MCA setup!\n");
413 return -ENOMEM;
414}
415
416subsys_initcall(mca_init);
417
418
419
420static __kprobes void
421mca_handle_nmi_device(struct mca_device *mca_dev, int check_flag)
422{
423 int slot = mca_dev->slot;
424
425 if (slot == MCA_INTEGSCSI) {
426 printk(KERN_CRIT "NMI: caused by MCA integrated SCSI adapter (%s)\n",
427 mca_dev->name);
428 } else if (slot == MCA_INTEGVIDEO) {
429 printk(KERN_CRIT "NMI: caused by MCA integrated video adapter (%s)\n",
430 mca_dev->name);
431 } else if (slot == MCA_MOTHERBOARD) {
432 printk(KERN_CRIT "NMI: caused by motherboard (%s)\n",
433 mca_dev->name);
434 }
435
436
437
438 if (check_flag) {
439 unsigned char pos6, pos7;
440
441 pos6 = mca_device_read_pos(mca_dev, 6);
442 pos7 = mca_device_read_pos(mca_dev, 7);
443
444 printk(KERN_CRIT "NMI: POS 6 = 0x%x, POS 7 = 0x%x\n", pos6, pos7);
445 }
446
447}
448
449
450
451static int __kprobes mca_handle_nmi_callback(struct device *dev, void *data)
452{
453 struct mca_device *mca_dev = to_mca_device(dev);
454 unsigned char pos5;
455
456 pos5 = mca_device_read_pos(mca_dev, 5);
457
458 if (!(pos5 & 0x80)) {
459
460
461
462
463
464 mca_handle_nmi_device(mca_dev, !(pos5 & 0x40));
465 return 1;
466 }
467 return 0;
468}
469
470void __kprobes mca_handle_nmi(void)
471{
472
473
474
475
476 bus_for_each_dev(&mca_bus_type, NULL, NULL, mca_handle_nmi_callback);
477
478 mca_nmi_hook();
479}
480