Linux Audio

Check our new training course

Loading...
Note: File does not exist in v5.4.
  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/system.h>
 47#include <asm/io.h>
 48#include <linux/proc_fs.h>
 49#include <linux/mman.h>
 50#include <linux/mm.h>
 51#include <linux/pagemap.h>
 52#include <linux/ioport.h>
 53#include <asm/uaccess.h>
 54#include <linux/init.h>
 55
 56static unsigned char which_scsi;
 57
 58int MCA_bus;
 59EXPORT_SYMBOL(MCA_bus);
 60
 61/*
 62 * Motherboard register spinlock. Untested on SMP at the moment, but
 63 * are there any MCA SMP boxes?
 64 *
 65 * Yes - Alan
 66 */
 67static DEFINE_SPINLOCK(mca_lock);
 68
 69/* Build the status info for the adapter */
 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		 * id = 0x0000 usually indicates hardware failure,
 82		 * however, ZP Gu (zpg@castle.net> reports that his 9556
 83		 * has 0x0000 as id and everything still works. There
 84		 * also seem to be an adapter with id = 0x0000; the
 85		 * NCR Parallel Bus Memory Card. Until this is confirmed,
 86		 * however, this code will stay.
 87		 */
 88
 89		mca_dev->status = MCA_ADAPTER_ERROR;
 90
 91		return;
 92	} else if (mca_dev->pos_id != 0xffff) {
 93
 94		/*
 95		 * 0xffff usually indicates that there's no adapter,
 96		 * however, some integrated adapters may have 0xffff as
 97		 * their id and still be valid. Examples are on-board
 98		 * VGA of the 55sx, the integrated SCSI of the 56 & 57,
 99		 * and possibly also the 95 ULTIMEDIA.
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		/* enabled bit is in POS 2 */
120
121		mca_dev->status = MCA_ADAPTER_DISABLED;
122	}
123} /* mca_configure_adapter_status */
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 *	mca_read_and_store_pos - read the POS registers into a memory buffer
141 *      @pos: a char pointer to 8 bytes, contains the POS register value on
142 *            successful return
143 *
144 *	Returns 1 if a card actually exists (i.e. the pos isn't
145 *	all 0xff) or 0 otherwise
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			/* 0xff all across means no device. 0x00 means
156			 * something's broken, but a device is
157			 * probably there.  However, if you get 0x00
158			 * from a motherboard register it won't matter
159			 * what we find.  For the record, on the
160			 * 57SLC, the integrated SCSI adapter has
161			 * 0xffff for the adapter ID, but nonzero for
162			 * other registers.  */
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		/* Disable adapter setup, enable motherboard setup */
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		/* Make sure motherboard setup is off */
190
191		outb_p(0xff, MCA_MOTHERBOARD_SETUP_REG);
192
193		/* Read the appropriate register */
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	/* Make sure motherboard setup is off */
217
218	outb_p(0xff, MCA_MOTHERBOARD_SETUP_REG);
219
220	/* Read in the appropriate register */
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	/* Update the global register list, while we have the byte */
229
230	mca_dev->pos[reg] = byte;
231
232}
233
234/* for the primary MCA bus, we have identity transforms */
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	 * WARNING: Be careful when making changes here. Putting an adapter
261	 * and the motherboard simultaneously into setup mode may result in
262	 * damage to chips (according to The Indispensable PC Hardware Book
263	 * by Hans-Peter Messmer). Also, we disable system interrupts (so
264	 * that we are not disturbed in the middle of this).
265	 */
266
267	/* Make sure the MCA bus is present */
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	/* All MCA systems have at least a primary bus */
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	/* get the motherboard device */
291	mca_dev = kzalloc(sizeof(struct mca_device), GFP_KERNEL);
292	if (unlikely(!mca_dev))
293		goto out_nomem;
294
295	/*
296	 * We do not expect many MCA interrupts during initialization,
297	 * but let us be safe:
298	 */
299	spin_lock_irq(&mca_lock);
300
301	/* Make sure adapter setup is off */
302
303	outb_p(0, MCA_ADAPTER_SETUP_REG);
304
305	/* Read motherboard POS registers */
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	/* fake POS and slot for a motherboard */
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	/* Put motherboard into video setup mode, read integrated video
322	 * POS registers, and turn motherboard setup off.
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	/* fake POS and slot for the integrated video */
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	 * Put motherboard into scsi setup mode, read integrated scsi
337	 * POS registers, and turn motherboard setup off.
338	 *
339	 * It seems there are two possible SCSI registers. Martin says that
340	 * for the 56,57, 0xf7 is the one, but fails on the 76.
341	 * Alfredo (apena@vnet.ibm.com) says
342	 * 0xfd works on his machine. We'll try both of them. I figure it's
343	 * a good bet that only one could be valid at a time. This could
344	 * screw up though if one is used for something else on the other
345	 * machine.
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		/* found a scsi card */
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		/* fake POS and slot for integrated SCSI controller */
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	/* Turn off motherboard setup */
371
372	outb_p(0xff, MCA_MOTHERBOARD_SETUP_REG);
373
374	/*
375	 * Now loop over MCA slots: put each adapter into setup mode, and
376	 * read its POS registers. Then put adapter setup off.
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	/* Enable interrupts and return memory start */
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	/* More info available in POS 6 and 7? */
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} /* mca_handle_nmi_slot */
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		 *  Bit 7 of POS 5 is reset when this adapter has a hardware
461		 * error. Bit 7 it reset if there's error information
462		 * available in POS 6 and 7.
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	 *  First try - scan the various adapters and see if a specific
474	 * adapter was responsible for the error.
475	 */
476	bus_for_each_dev(&mca_bus_type, NULL, NULL, mca_handle_nmi_callback);
477}