isa.c revision 16733
156893Sfenner/*-
256893Sfenner * Copyright (c) 1991 The Regents of the University of California.
356893Sfenner * All rights reserved.
4127668Sbms *
556893Sfenner * This code is derived from software contributed to Berkeley by
656893Sfenner * William Jolitz.
756893Sfenner *
856893Sfenner * Redistribution and use in source and binary forms, with or without
956893Sfenner * modification, are permitted provided that the following conditions
1056893Sfenner * are met:
1156893Sfenner * 1. Redistributions of source code must retain the above copyright
1256893Sfenner *    notice, this list of conditions and the following disclaimer.
1356893Sfenner * 2. Redistributions in binary form must reproduce the above copyright
1456893Sfenner *    notice, this list of conditions and the following disclaimer in the
1556893Sfenner *    documentation and/or other materials provided with the distribution.
16127668Sbms * 3. All advertising materials mentioning features or use of this software
1756893Sfenner *    must display the following acknowledgement:
1856893Sfenner *	This product includes software developed by the University of
1956893Sfenner *	California, Berkeley and its contributors.
2056893Sfenner * 4. Neither the name of the University nor the names of its contributors
2156893Sfenner *    may be used to endorse or promote products derived from this software
2256893Sfenner *    without specific prior written permission.
2356893Sfenner *
2456893Sfenner * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
2556893Sfenner * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
2656893Sfenner * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
2756893Sfenner * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
2856893Sfenner * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
2956893Sfenner * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
3056893Sfenner * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
3156893Sfenner * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
3256893Sfenner * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
3356893Sfenner * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
3456893Sfenner * SUCH DAMAGE.
3556893Sfenner *
3656893Sfenner *	from: @(#)isa.c	7.2 (Berkeley) 5/13/91
3756893Sfenner *	$Id: isa.c,v 1.70 1996/05/02 10:43:09 phk Exp $
3856893Sfenner */
3956893Sfenner
4056893Sfenner/*
4156893Sfenner * code to manage AT bus
42127668Sbms *
4356893Sfenner * 92/08/18  Frank P. MacLachlan (fpm@crash.cts.com):
4456893Sfenner * Fixed uninitialized variable problem and added code to deal
45127668Sbms * with DMA page boundaries in isa_dmarangecheck().  Fixed word
46190207Srpaulo * mode DMA count compution and reorganized DMA setup code in
4756893Sfenner * isa_dmastart()
4856893Sfenner */
4956893Sfenner
5056893Sfenner#include "opt_auto_eoi.h"
5156893Sfenner
5256893Sfenner#include <sys/param.h>
5356893Sfenner#include <sys/systm.h>
5456893Sfenner#include <sys/sysctl.h>
5556893Sfenner#include <sys/buf.h>
5656893Sfenner#include <sys/syslog.h>
5756893Sfenner#include <sys/malloc.h>
5856893Sfenner#include <machine/md_var.h>
5956893Sfenner#include <machine/segments.h>
6056893Sfenner#include <vm/vm.h>
6156893Sfenner#include <vm/vm_param.h>
6256893Sfenner#include <vm/pmap.h>
6356893Sfenner#include <i386/isa/isa_device.h>
6456893Sfenner#include <i386/isa/isa.h>
6556893Sfenner#include <i386/isa/icu.h>
6656893Sfenner#include <i386/isa/ic/i8237.h>
6756893Sfenner#include <sys/devconf.h>
6856893Sfenner#include "vector.h"
6956893Sfenner
7056893Sfenner/*
7156893Sfenner**  Register definitions for DMA controller 1 (channels 0..3):
7256893Sfenner*/
7356893Sfenner#define	DMA1_CHN(c)	(IO_DMA1 + 1*(2*(c)))	/* addr reg for channel c */
7456893Sfenner#define	DMA1_SMSK	(IO_DMA1 + 1*10)	/* single mask register */
7556893Sfenner#define	DMA1_MODE	(IO_DMA1 + 1*11)	/* mode register */
7656893Sfenner#define	DMA1_FFC	(IO_DMA1 + 1*12)	/* clear first/last FF */
7756893Sfenner
7856893Sfenner/*
7956893Sfenner**  Register definitions for DMA controller 2 (channels 4..7):
8056893Sfenner*/
8156893Sfenner#define	DMA2_CHN(c)	(IO_DMA2 + 2*(2*(c)))	/* addr reg for channel c */
8256893Sfenner#define	DMA2_SMSK	(IO_DMA2 + 2*10)	/* single mask register */
8356893Sfenner#define	DMA2_MODE	(IO_DMA2 + 2*11)	/* mode register */
8456893Sfenner#define	DMA2_FFC	(IO_DMA2 + 2*12)	/* clear first/last FF */
8556893Sfenner
8656893Sfenneru_long	*intr_countp[ICU_LEN];
8756893Sfennerinthand2_t *intr_handler[ICU_LEN];
8856893Sfenneru_int	intr_mask[ICU_LEN];
8956893Sfenneru_int*	intr_mptr[ICU_LEN];
9056893Sfennerint	intr_unit[ICU_LEN];
9156893Sfenner
9256893Sfennerextern struct kern_devconf kdc_cpu0;
9356893Sfenner
9456893Sfennerstruct kern_devconf kdc_isa0 = {
9556893Sfenner	0, 0, 0,		/* filled in by dev_attach */
9656893Sfenner	"isa", 0, { MDDT_BUS, 0 },
9756893Sfenner	0, 0, 0, BUS_EXTERNALLEN,
9856893Sfenner	&kdc_cpu0,		/* parent is the CPU */
9956893Sfenner	0,			/* no parentdata */
10056893Sfenner	DC_BUSY,		/* busses are always busy */
10156893Sfenner	"ISA bus",
10256893Sfenner	DC_CLS_BUS		/* class */
10356893Sfenner};
10456893Sfenner
10556893Sfennerstatic inthand_t *fastintr[ICU_LEN] = {
10656893Sfenner	&IDTVEC(fastintr0), &IDTVEC(fastintr1),
10756893Sfenner	&IDTVEC(fastintr2), &IDTVEC(fastintr3),
10856893Sfenner	&IDTVEC(fastintr4), &IDTVEC(fastintr5),
10956893Sfenner	&IDTVEC(fastintr6), &IDTVEC(fastintr7),
11056893Sfenner	&IDTVEC(fastintr8), &IDTVEC(fastintr9),
11156893Sfenner	&IDTVEC(fastintr10), &IDTVEC(fastintr11),
11256893Sfenner	&IDTVEC(fastintr12), &IDTVEC(fastintr13),
11356893Sfenner	&IDTVEC(fastintr14), &IDTVEC(fastintr15)
11456893Sfenner};
11556893Sfenner
11656893Sfennerstatic inthand_t *slowintr[ICU_LEN] = {
11756893Sfenner	&IDTVEC(intr0), &IDTVEC(intr1), &IDTVEC(intr2), &IDTVEC(intr3),
11856893Sfenner	&IDTVEC(intr4), &IDTVEC(intr5), &IDTVEC(intr6), &IDTVEC(intr7),
11956893Sfenner	&IDTVEC(intr8), &IDTVEC(intr9), &IDTVEC(intr10), &IDTVEC(intr11),
12056893Sfenner	&IDTVEC(intr12), &IDTVEC(intr13), &IDTVEC(intr14), &IDTVEC(intr15)
12156893Sfenner};
12256893Sfenner
12356893Sfennerstatic void config_isadev __P((struct isa_device *isdp, u_int *mp));
12456893Sfennerstatic void config_isadev_c __P((struct isa_device *isdp, u_int *mp,
12556893Sfenner				 int reconfig));
12656893Sfennerstatic void conflict __P((struct isa_device *dvp, struct isa_device *tmpdvp,
127127668Sbms			  int item, char const *whatnot, char const *reason,
12856893Sfenner			  char const *format));
12956893Sfennerstatic int haveseen __P((struct isa_device *dvp, struct isa_device *tmpdvp,
13056893Sfenner			 u_int checkbits));
13156893Sfennerstatic int isa_dmarangecheck __P((caddr_t va, u_int length, int chan));
13256893Sfennerstatic inthand2_t isa_strayintr;
13356893Sfennerstatic void register_imask __P((struct isa_device *dvp, u_int mask));
13456893Sfenner
135127668Sbms/*
13656893Sfenner * print a conflict message
13756893Sfenner */
13856893Sfennerstatic void
139127668Sbmsconflict(dvp, tmpdvp, item, whatnot, reason, format)
14056893Sfenner	struct isa_device	*dvp;
14156893Sfenner	struct isa_device	*tmpdvp;
14256893Sfenner	int			item;
14356893Sfenner	char const		*whatnot;
14456893Sfenner	char const		*reason;
14556893Sfenner	char const		*format;
14656893Sfenner{
14756893Sfenner	printf("%s%d not %sed due to %s conflict with %s%d at ",
14856893Sfenner		dvp->id_driver->name, dvp->id_unit, whatnot, reason,
14956893Sfenner		tmpdvp->id_driver->name, tmpdvp->id_unit);
15056893Sfenner	printf(format, item);
15156893Sfenner	printf("\n");
15256893Sfenner}
15356893Sfenner
15456893Sfenner/*
15556893Sfenner * Check to see if things are already in use, like IRQ's, I/O addresses
15656893Sfenner * and Memory addresses.
15756893Sfenner */
15875115Sfennerstatic int
15956893Sfennerhaveseen(dvp, tmpdvp, checkbits)
16056893Sfenner	struct isa_device *dvp;
16156893Sfenner	struct isa_device *tmpdvp;
16275115Sfenner	u_int	checkbits;
16375115Sfenner{
16456893Sfenner	/*
16556893Sfenner	 * Only check against devices that have already been found and are not
16656893Sfenner	 * unilaterally allowed to conflict anyway.
16756893Sfenner	 */
16856893Sfenner	if (tmpdvp->id_alive && !dvp->id_conflicts) {
16956893Sfenner		char const *whatnot;
17056893Sfenner
17156893Sfenner		whatnot = checkbits & CC_ATTACH ? "attach" : "prob";
17256893Sfenner		/*
17356893Sfenner		 * Check for I/O address conflict.  We can only check the
17456893Sfenner		 * starting address of the device against the range of the
17556893Sfenner		 * device that has already been probed since we do not
17656893Sfenner		 * know how many I/O addresses this device uses.
177127668Sbms		 */
17856893Sfenner		if (checkbits & CC_IOADDR && tmpdvp->id_alive != -1) {
17956893Sfenner			if ((dvp->id_iobase >= tmpdvp->id_iobase) &&
18056893Sfenner			    (dvp->id_iobase <=
18156893Sfenner				  (tmpdvp->id_iobase + tmpdvp->id_alive - 1))) {
18256893Sfenner				conflict(dvp, tmpdvp, dvp->id_iobase, whatnot,
18356893Sfenner					 "I/O address", "0x%x");
18456893Sfenner				return 1;
18556893Sfenner			}
18656893Sfenner		}
18756893Sfenner		/*
18856893Sfenner		 * Check for Memory address conflict.  We can check for
18956893Sfenner		 * range overlap, but it will not catch all cases since the
19056893Sfenner		 * driver may adjust the msize paramater during probe, for
19156893Sfenner		 * now we just check that the starting address does not
19256893Sfenner		 * fall within any allocated region.
19356893Sfenner		 * XXX could add a second check after the probe for overlap,
19456893Sfenner		 * since at that time we would know the full range.
19556893Sfenner		 * XXX KERNBASE is a hack, we should have vaddr in the table!
19656893Sfenner		 */
19756893Sfenner		if (checkbits & CC_MEMADDR && tmpdvp->id_maddr) {
19856893Sfenner			if ((KERNBASE + dvp->id_maddr >= tmpdvp->id_maddr) &&
19956893Sfenner			    (KERNBASE + dvp->id_maddr <=
20056893Sfenner			     (tmpdvp->id_maddr + tmpdvp->id_msize - 1))) {
20156893Sfenner				conflict(dvp, tmpdvp, (int)dvp->id_maddr,
20256893Sfenner					 whatnot, "maddr", "0x%x");
20356893Sfenner				return 1;
20456893Sfenner			}
20556893Sfenner		}
20656893Sfenner		/*
20756893Sfenner		 * Check for IRQ conflicts.
20856893Sfenner		 */
20956893Sfenner		if (checkbits & CC_IRQ && tmpdvp->id_irq) {
21056893Sfenner			if (tmpdvp->id_irq == dvp->id_irq) {
21156893Sfenner				conflict(dvp, tmpdvp, ffs(dvp->id_irq) - 1,
21256893Sfenner					 whatnot, "irq", "%d");
21356893Sfenner				return 1;
21456893Sfenner			}
21556893Sfenner		}
21656893Sfenner		/*
21756893Sfenner		 * Check for DRQ conflicts.
21856893Sfenner		 */
21975115Sfenner		if (checkbits & CC_DRQ && tmpdvp->id_drq != -1) {
22056893Sfenner			if (tmpdvp->id_drq == dvp->id_drq) {
22156893Sfenner				conflict(dvp, tmpdvp, dvp->id_drq, whatnot,
22256893Sfenner					 "drq", "%d");
22356893Sfenner				return 1;
22456893Sfenner			}
22556893Sfenner		}
22656893Sfenner	}
22756893Sfenner	return 0;
22856893Sfenner}
22956893Sfenner
23056893Sfenner/*
23156893Sfenner * Search through all the isa_devtab_* tables looking for anything that
23256893Sfenner * conflicts with the current device.
23356893Sfenner */
23456893Sfennerint
23556893Sfennerhaveseen_isadev(dvp, checkbits)
23656893Sfenner	struct isa_device *dvp;
23756893Sfenner	u_int	checkbits;
23856893Sfenner{
23956893Sfenner	struct isa_device *tmpdvp;
24056893Sfenner	int	status = 0;
24156893Sfenner
24256893Sfenner	for (tmpdvp = isa_devtab_tty; tmpdvp->id_driver; tmpdvp++) {
24356893Sfenner		status |= haveseen(dvp, tmpdvp, checkbits);
24456893Sfenner		if (status)
24556893Sfenner			return status;
24656893Sfenner	}
24756893Sfenner	for (tmpdvp = isa_devtab_bio; tmpdvp->id_driver; tmpdvp++) {
24856893Sfenner		status |= haveseen(dvp, tmpdvp, checkbits);
24956893Sfenner		if (status)
25056893Sfenner			return status;
25156893Sfenner	}
25256893Sfenner	for (tmpdvp = isa_devtab_net; tmpdvp->id_driver; tmpdvp++) {
25356893Sfenner		status |= haveseen(dvp, tmpdvp, checkbits);
25456893Sfenner		if (status)
25556893Sfenner			return status;
25656893Sfenner	}
25756893Sfenner	for (tmpdvp = isa_devtab_null; tmpdvp->id_driver; tmpdvp++) {
25856893Sfenner		status |= haveseen(dvp, tmpdvp, checkbits);
25975115Sfenner		if (status)
26056893Sfenner			return status;
26156893Sfenner	}
26256893Sfenner	return(status);
26356893Sfenner}
26456893Sfenner
26556893Sfenner/*
26656893Sfenner * Configure all ISA devices
26756893Sfenner */
26856893Sfennervoid
26956893Sfennerisa_configure() {
27056893Sfenner	struct isa_device *dvp;
27156893Sfenner
27256893Sfenner	dev_attach(&kdc_isa0);
27356893Sfenner
27456893Sfenner	splhigh();
27575115Sfenner	printf("Probing for devices on the ISA bus:\n");
27656893Sfenner	/* First probe all the sensitive probes */
27756893Sfenner	for (dvp = isa_devtab_tty; dvp->id_driver; dvp++)
27856893Sfenner		if (dvp->id_driver->sensitive_hw)
27956893Sfenner			config_isadev(dvp, &tty_imask);
28056893Sfenner	for (dvp = isa_devtab_bio; dvp->id_driver; dvp++)
28156893Sfenner		if (dvp->id_driver->sensitive_hw)
282			config_isadev(dvp, &bio_imask);
283	for (dvp = isa_devtab_net; dvp->id_driver; dvp++)
284		if (dvp->id_driver->sensitive_hw)
285			config_isadev(dvp, &net_imask);
286	for (dvp = isa_devtab_null; dvp->id_driver; dvp++)
287		if (dvp->id_driver->sensitive_hw)
288			config_isadev(dvp, (u_int *)NULL);
289
290	/* Then all the bad ones */
291	for (dvp = isa_devtab_tty; dvp->id_driver; dvp++)
292		if (!dvp->id_driver->sensitive_hw)
293			config_isadev(dvp, &tty_imask);
294	for (dvp = isa_devtab_bio; dvp->id_driver; dvp++)
295		if (!dvp->id_driver->sensitive_hw)
296			config_isadev(dvp, &bio_imask);
297	for (dvp = isa_devtab_net; dvp->id_driver; dvp++)
298		if (!dvp->id_driver->sensitive_hw)
299			config_isadev(dvp, &net_imask);
300	for (dvp = isa_devtab_null; dvp->id_driver; dvp++)
301		if (!dvp->id_driver->sensitive_hw)
302			config_isadev(dvp, (u_int *)NULL);
303
304	bio_imask |= SWI_CLOCK_MASK;
305	net_imask |= SWI_NET_MASK;
306	tty_imask |= SWI_TTY_MASK;
307
308/*
309 * XXX we should really add the tty device to net_imask when the line is
310 * switched to SLIPDISC, and then remove it when it is switched away from
311 * SLIPDISC.  No need to block out ALL ttys during a splimp when only one
312 * of them is running slip.
313 *
314 * XXX actually, blocking all ttys during a splimp doesn't matter so much
315 * with sio because the serial interrupt layer doesn't use tty_imask.  Only
316 * non-serial ttys suffer.  It's more stupid that ALL 'net's are blocked
317 * during spltty.
318 */
319#include "sl.h"
320#if NSL > 0
321	net_imask |= tty_imask;
322	tty_imask = net_imask;
323#endif
324
325	/* bio_imask |= tty_imask ;  can some tty devices use buffers? */
326
327	if (bootverbose)
328		printf("imasks: bio %x, tty %x, net %x\n",
329		       bio_imask, tty_imask, net_imask);
330
331	/*
332	 * Finish initializing intr_mask[].  Note that the partly
333	 * constructed masks aren't actually used since we're at splhigh.
334	 * For fully dynamic initialization, register_intr() and
335	 * unregister_intr() will have to adjust the masks for _all_
336	 * interrupts and for tty_imask, etc.
337	 */
338	for (dvp = isa_devtab_tty; dvp->id_driver; dvp++)
339		register_imask(dvp, tty_imask);
340	for (dvp = isa_devtab_bio; dvp->id_driver; dvp++)
341		register_imask(dvp, bio_imask);
342	for (dvp = isa_devtab_net; dvp->id_driver; dvp++)
343		register_imask(dvp, net_imask);
344	for (dvp = isa_devtab_null; dvp->id_driver; dvp++)
345		register_imask(dvp, SWI_CLOCK_MASK);
346	spl0();
347}
348
349/*
350 * Configure an ISA device.
351 */
352
353
354static void
355config_isadev(isdp, mp)
356     struct isa_device *isdp;
357     u_int *mp;
358{
359	config_isadev_c(isdp, mp, 0);
360}
361
362void
363reconfig_isadev(isdp, mp)
364	struct isa_device *isdp;
365	u_int *mp;
366{
367	config_isadev_c(isdp, mp, 1);
368}
369
370static void
371config_isadev_c(isdp, mp, reconfig)
372	struct isa_device *isdp;
373	u_int *mp;
374	int reconfig;
375{
376	u_int checkbits;
377	int id_alive;
378	int last_alive;
379	struct isa_driver *dp = isdp->id_driver;
380
381	if (!isdp->id_enabled) {
382		printf("%s%d: disabled, not probed.\n",
383			dp->name, isdp->id_unit);
384		return;
385	}
386	checkbits = CC_DRQ | CC_IOADDR | CC_MEMADDR;
387	if (!reconfig && haveseen_isadev(isdp, checkbits))
388		return;
389	if (!reconfig && isdp->id_maddr) {
390		isdp->id_maddr -= 0xa0000; /* XXX should be a define */
391		isdp->id_maddr += atdevbase;
392	}
393	if (reconfig) {
394		last_alive = isdp->id_alive;
395		isdp->id_reconfig = 1;
396	}
397	else {
398		last_alive = 0;
399		isdp->id_reconfig = 0;
400	}
401	id_alive = (*dp->probe)(isdp);
402	if (id_alive) {
403		/*
404		 * Only print the I/O address range if id_alive != -1
405		 * Right now this is a temporary fix just for the new
406		 * NPX code so that if it finds a 486 that can use trap
407		 * 16 it will not report I/O addresses.
408		 * Rod Grimes 04/26/94
409		 */
410		if (!isdp->id_reconfig) {
411			printf("%s%d", dp->name, isdp->id_unit);
412			if (id_alive != -1) {
413				printf(" at 0x%x", isdp->id_iobase);
414				if (isdp->id_iobase + id_alive - 1 !=
415				    isdp->id_iobase) {
416					printf("-0x%x",
417					       isdp->id_iobase + id_alive - 1);
418				}
419			}
420			if (isdp->id_irq)
421				printf(" irq %d", ffs(isdp->id_irq) - 1);
422			if (isdp->id_drq != -1)
423				printf(" drq %d", isdp->id_drq);
424			if (isdp->id_maddr)
425				printf(" maddr 0x%lx", kvtop(isdp->id_maddr));
426			if (isdp->id_msize)
427				printf(" msize %d", isdp->id_msize);
428			if (isdp->id_flags)
429				printf(" flags 0x%x", isdp->id_flags);
430			if (isdp->id_iobase && !(isdp->id_iobase & 0xf300)) {
431				printf(" on motherboard");
432			} else if (isdp->id_iobase >= 0x1000 &&
433				    !(isdp->id_iobase & 0x300)) {
434				printf (" on eisa slot %d",
435					isdp->id_iobase >> 12);
436			} else {
437				printf (" on isa");
438			}
439			printf("\n");
440			/*
441			 * Check for conflicts again.  The driver may have
442			 * changed *dvp.  We should weaken the early check
443			 * since the driver may have been able to change
444			 * *dvp to avoid conflicts if given a chance.  We
445			 * already skip the early check for IRQs and force
446			 * a check for IRQs in the next group of checks.
447			 */
448			checkbits |= CC_IRQ;
449			if (haveseen_isadev(isdp, checkbits))
450				return;
451			isdp->id_alive = id_alive;
452		}
453		(*dp->attach)(isdp);
454		if (isdp->id_irq) {
455			if (mp)
456				INTRMASK(*mp, isdp->id_irq);
457			register_intr(ffs(isdp->id_irq) - 1, isdp->id_id,
458				      isdp->id_ri_flags, isdp->id_intr,
459				      mp, isdp->id_unit);
460			INTREN(isdp->id_irq);
461		}
462	} else {
463		if (isdp->id_reconfig) {
464			(*dp->attach)(isdp); /* reconfiguration attach */
465		}
466		if (!last_alive) {
467			if (!isdp->id_reconfig) {
468				printf("%s%d not found",
469				       dp->name, isdp->id_unit);
470				if (isdp->id_iobase) {
471					printf(" at 0x%x", isdp->id_iobase);
472				}
473				printf("\n");
474			}
475		}
476		else {
477			/* This code has not been tested.... */
478			if (isdp->id_irq) {
479				INTRDIS(isdp->id_irq);
480				unregister_intr(ffs(isdp->id_irq) - 1,
481						isdp->id_intr);
482				if (mp)
483					INTRUNMASK(*mp, isdp->id_irq);
484			}
485		}
486	}
487}
488
489/*
490 * Provide ISA-specific device information to user programs using the
491 * hw.devconf interface.
492 */
493int
494isa_externalize(struct isa_device *id, struct sysctl_req *req)
495{
496	return (SYSCTL_OUT(req, id, sizeof *id));
497}
498
499/*
500 * This is used to forcibly reconfigure an ISA device.  It currently just
501 * returns an error 'cos you can't do that yet.  It is here to demonstrate
502 * what the `internalize' routine is supposed to do.
503 */
504int
505isa_internalize(struct isa_device *id, struct sysctl_req *req)
506{
507	struct isa_device myid;
508	int rv;
509
510	rv = SYSCTL_IN(req, &myid, sizeof *id);
511	if(rv)
512		return rv;
513
514	rv = EOPNOTSUPP;
515	/* code would go here to validate the configuration request */
516	/* code would go here to actually perform the reconfiguration */
517	return rv;
518}
519
520int
521isa_generic_externalize(struct kern_devconf *kdc, struct sysctl_req *req)
522{
523	return isa_externalize(kdc->kdc_isa, req);
524}
525
526/*
527 * Fill in default interrupt table (in case of spuruious interrupt
528 * during configuration of kernel, setup interrupt control unit
529 */
530void
531isa_defaultirq()
532{
533	int i;
534
535	/* icu vectors */
536	for (i = 0; i < ICU_LEN; i++)
537		unregister_intr(i, (inthand2_t *)NULL);
538
539	/* initialize 8259's */
540	outb(IO_ICU1, 0x11);		/* reset; program device, four bytes */
541	outb(IO_ICU1+1, NRSVIDT);	/* starting at this vector index */
542	outb(IO_ICU1+1, 1<<2);		/* slave on line 2 */
543#ifdef AUTO_EOI_1
544	outb(IO_ICU1+1, 2 | 1);		/* auto EOI, 8086 mode */
545#else
546	outb(IO_ICU1+1, 1);		/* 8086 mode */
547#endif
548	outb(IO_ICU1+1, 0xff);		/* leave interrupts masked */
549	outb(IO_ICU1, 0x0a);		/* default to IRR on read */
550	outb(IO_ICU1, 0xc0 | (3 - 1));	/* pri order 3-7, 0-2 (com2 first) */
551
552	outb(IO_ICU2, 0x11);		/* reset; program device, four bytes */
553	outb(IO_ICU2+1, NRSVIDT+8);	/* staring at this vector index */
554	outb(IO_ICU2+1,2);		/* my slave id is 2 */
555#ifdef AUTO_EOI_2
556	outb(IO_ICU2+1, 2 | 1);		/* auto EOI, 8086 mode */
557#else
558	outb(IO_ICU2+1,1);		/* 8086 mode */
559#endif
560	outb(IO_ICU2+1, 0xff);		/* leave interrupts masked */
561	outb(IO_ICU2, 0x0a);		/* default to IRR on read */
562}
563
564static caddr_t	dma_bouncebuf[8];
565static u_int	dma_bouncebufsize[8];
566static u_int8_t	dma_bounced = 0;
567static u_int8_t	dma_busy = 0;		/* Used in isa_dmastart() */
568static u_int8_t	dma_inuse = 0;		/* User for acquire/release */
569
570#define VALID_DMA_MASK (7)
571
572/* high byte of address is stored in this port for i-th dma channel */
573static short dmapageport[8] =
574	{ 0x87, 0x83, 0x81, 0x82, 0x8f, 0x8b, 0x89, 0x8a };
575
576/*
577 * Setup a DMA channel's bounce buffer.
578 */
579void
580isa_dmainit(chan, bouncebufsize)
581	int chan;
582	u_int bouncebufsize;
583{
584	void *buf;
585
586#ifdef DIAGNOSTIC
587	if (chan & ~VALID_DMA_MASK)
588		panic("isa_dmainit: channel out of range");
589
590	if (dma_bouncebuf[chan] != NULL)
591		panic("isa_dmainit: impossible request");
592#endif
593
594	dma_bouncebufsize[chan] = bouncebufsize;
595
596	/* Try malloc() first.  It works better if it works. */
597	buf = malloc(bouncebufsize, M_DEVBUF, M_NOWAIT);
598	if (buf != NULL) {
599		if (isa_dmarangecheck(buf, bouncebufsize, chan) == 0) {
600			dma_bouncebuf[chan] = buf;
601			return;
602		}
603		free(buf, M_DEVBUF);
604	}
605	buf = contigmalloc(bouncebufsize, M_DEVBUF, M_NOWAIT, 0ul, 0xfffffful,
606			   1ul, chan & 4 ? 0x20000ul : 0x10000ul);
607	if (buf == NULL)
608		printf("isa_dmainit(%d, %d) failed\n", chan, bouncebufsize);
609	else
610		dma_bouncebuf[chan] = buf;
611}
612
613/*
614 * Register a DMA channel's usage.  Usually called from a device driver
615 * in open() or during it's initialization.
616 */
617int
618isa_dma_acquire(chan)
619	int chan;
620{
621#ifdef DIAGNOSTIC
622	if (chan & ~VALID_DMA_MASK)
623		panic("isa_dma_acquire: channel out of range");
624#endif
625
626	if (dma_inuse & (1 << chan)) {
627		printf("isa_dma_acquire: channel %d already in use\n", chan);
628		return (EBUSY);
629	}
630	dma_inuse |= (1 << chan);
631
632	return (0);
633}
634
635/*
636 * Unregister a DMA channel's usage.  Usually called from a device driver
637 * during close() or during it's shutdown.
638 */
639void
640isa_dma_release(chan)
641	int chan;
642{
643#ifdef DIAGNOSTIC
644	if (chan & ~VALID_DMA_MASK)
645		panic("isa_dma_release: channel out of range");
646
647	if (dma_inuse & (1 << chan) == 0)
648		printf("isa_dma_release: channel %d not in use\n", chan);
649#endif
650
651	if (dma_busy & (1 << chan)) {
652		dma_busy &= ~(1 << chan);
653		/*
654		 * XXX We should also do "dma_bounced &= (1 << chan);"
655		 * because we are acting on behalf of isa_dmadone() which
656		 * was not called to end the last DMA operation.  This does
657		 * not matter now, but it may in the future.
658		 */
659	}
660
661	dma_inuse &= ~(1 << chan);
662}
663
664/*
665 * isa_dmacascade(): program 8237 DMA controller channel to accept
666 * external dma control by a board.
667 */
668void isa_dmacascade(chan)
669	int chan;
670{
671#ifdef DIAGNOSTIC
672	if (chan & ~VALID_DMA_MASK)
673		panic("isa_dmacascade: channel out of range");
674#endif
675
676	/* set dma channel mode, and set dma channel mode */
677	if ((chan & 4) == 0) {
678		outb(DMA1_MODE, DMA37MD_CASCADE | chan);
679		outb(DMA1_SMSK, chan);
680	} else {
681		outb(DMA2_MODE, DMA37MD_CASCADE | (chan & 3));
682		outb(DMA2_SMSK, chan & 3);
683	}
684}
685
686/*
687 * isa_dmastart(): program 8237 DMA controller channel, avoid page alignment
688 * problems by using a bounce buffer.
689 */
690void isa_dmastart(int flags, caddr_t addr, u_int nbytes, int chan)
691{
692	vm_offset_t phys;
693	int waport;
694	caddr_t newaddr;
695
696#ifdef DIAGNOSTIC
697	if (chan & ~VALID_DMA_MASK)
698		panic("isa_dmastart: channel out of range");
699
700	if ((chan < 4 && nbytes > (1<<16))
701	    || (chan >= 4 && (nbytes > (1<<17) || (u_int)addr & 1)))
702		panic("isa_dmastart: impossible request");
703
704	if (dma_inuse & (1 << chan) == 0)
705		printf("isa_dmastart: channel %d not acquired\n", chan);
706#endif
707
708	if (dma_busy & (1 << chan))
709		printf("isa_dmastart: channel %d busy\n", chan);
710
711	dma_busy |= (1 << chan);
712
713	if (isa_dmarangecheck(addr, nbytes, chan)) {
714		if (dma_bouncebuf[chan] == NULL
715		    || dma_bouncebufsize[chan] < nbytes)
716			panic("isa_dmastart: bad bounce buffer");
717		dma_bounced |= (1 << chan);
718		newaddr = dma_bouncebuf[chan];
719
720		/* copy bounce buffer on write */
721		if (!(flags & B_READ))
722			bcopy(addr, newaddr, nbytes);
723		addr = newaddr;
724	}
725
726	/* translate to physical */
727	phys = pmap_extract(pmap_kernel(), (vm_offset_t)addr);
728
729	if ((chan & 4) == 0) {
730		/*
731		 * Program one of DMA channels 0..3.  These are
732		 * byte mode channels.
733		 */
734		/* set dma channel mode, and reset address ff */
735
736		/* If B_RAW flag is set, then use autoinitialise mode */
737		if (flags & B_RAW) {
738		  if (flags & B_READ)
739			outb(DMA1_MODE, DMA37MD_AUTO|DMA37MD_WRITE|chan);
740		  else
741			outb(DMA1_MODE, DMA37MD_AUTO|DMA37MD_READ|chan);
742		}
743		else
744		if (flags & B_READ)
745			outb(DMA1_MODE, DMA37MD_SINGLE|DMA37MD_WRITE|chan);
746		else
747			outb(DMA1_MODE, DMA37MD_SINGLE|DMA37MD_READ|chan);
748		outb(DMA1_FFC, 0);
749
750		/* send start address */
751		waport =  DMA1_CHN(chan);
752		outb(waport, phys);
753		outb(waport, phys>>8);
754		outb(dmapageport[chan], phys>>16);
755
756		/* send count */
757		outb(waport + 1, --nbytes);
758		outb(waport + 1, nbytes>>8);
759
760		/* unmask channel */
761		outb(DMA1_SMSK, chan);
762	} else {
763		/*
764		 * Program one of DMA channels 4..7.  These are
765		 * word mode channels.
766		 */
767		/* set dma channel mode, and reset address ff */
768
769		/* If B_RAW flag is set, then use autoinitialise mode */
770		if (flags & B_RAW) {
771		  if (flags & B_READ)
772			outb(DMA2_MODE, DMA37MD_AUTO|DMA37MD_WRITE|(chan&3));
773		  else
774			outb(DMA2_MODE, DMA37MD_AUTO|DMA37MD_READ|(chan&3));
775		}
776		else
777		if (flags & B_READ)
778			outb(DMA2_MODE, DMA37MD_SINGLE|DMA37MD_WRITE|(chan&3));
779		else
780			outb(DMA2_MODE, DMA37MD_SINGLE|DMA37MD_READ|(chan&3));
781		outb(DMA2_FFC, 0);
782
783		/* send start address */
784		waport = DMA2_CHN(chan - 4);
785		outb(waport, phys>>1);
786		outb(waport, phys>>9);
787		outb(dmapageport[chan], phys>>16);
788
789		/* send count */
790		nbytes >>= 1;
791		outb(waport + 2, --nbytes);
792		outb(waport + 2, nbytes>>8);
793
794		/* unmask channel */
795		outb(DMA2_SMSK, chan & 3);
796	}
797}
798
799void isa_dmadone(int flags, caddr_t addr, int nbytes, int chan)
800{
801#ifdef DIAGNOSTIC
802	if (chan & ~VALID_DMA_MASK)
803		panic("isa_dmadone: channel out of range");
804
805	if (dma_inuse & (1 << chan) == 0)
806		printf("isa_dmadone: channel %d not acquired\n", chan);
807#endif
808
809#if 0
810	/*
811	 * XXX This should be checked, but drivers like ad1848 only call
812	 * isa_dmastart() once because they use Auto DMA mode.  If we
813	 * leave this in, drivers that do this will print this continuously.
814	 */
815	if (dma_busy & (1 << chan) == 0)
816		printf("isa_dmadone: channel %d not busy\n", chan);
817#endif
818
819	if (dma_bounced & (1 << chan)) {
820		/* copy bounce buffer on read */
821		if (flags & B_READ)
822			bcopy(dma_bouncebuf[chan], addr, nbytes);
823
824		dma_bounced &= ~(1 << chan);
825	}
826	dma_busy &= ~(1 << chan);
827}
828
829/*
830 * Check for problems with the address range of a DMA transfer
831 * (non-contiguous physical pages, outside of bus address space,
832 * crossing DMA page boundaries).
833 * Return true if special handling needed.
834 */
835
836static int
837isa_dmarangecheck(caddr_t va, u_int length, int chan) {
838	vm_offset_t phys, priorpage = 0, endva;
839	u_int dma_pgmsk = (chan & 4) ?  ~(128*1024-1) : ~(64*1024-1);
840
841	endva = (vm_offset_t)round_page(va + length);
842	for (; va < (caddr_t) endva ; va += PAGE_SIZE) {
843		phys = trunc_page(pmap_extract(pmap_kernel(), (vm_offset_t)va));
844#define ISARAM_END	RAM_END
845		if (phys == 0)
846			panic("isa_dmacheck: no physical page present");
847		if (phys >= ISARAM_END)
848			return (1);
849		if (priorpage) {
850			if (priorpage + PAGE_SIZE != phys)
851				return (1);
852			/* check if crossing a DMA page boundary */
853			if (((u_int)priorpage ^ (u_int)phys) & dma_pgmsk)
854				return (1);
855		}
856		priorpage = phys;
857	}
858	return (0);
859}
860
861#define NMI_PARITY (1 << 7)
862#define NMI_IOCHAN (1 << 6)
863#define ENMI_WATCHDOG (1 << 7)
864#define ENMI_BUSTIMER (1 << 6)
865#define ENMI_IOSTATUS (1 << 5)
866
867/*
868 * Handle a NMI, possibly a machine check.
869 * return true to panic system, false to ignore.
870 */
871int
872isa_nmi(cd)
873	int cd;
874{
875	int isa_port = inb(0x61);
876	int eisa_port = inb(0x461);
877	if(isa_port & NMI_PARITY) {
878		panic("RAM parity error, likely hardware failure.");
879	} else if(isa_port & NMI_IOCHAN) {
880		panic("I/O channel check, likely hardware failure.");
881	} else if(eisa_port & ENMI_WATCHDOG) {
882		panic("EISA watchdog timer expired, likely hardware failure.");
883	} else if(eisa_port & ENMI_BUSTIMER) {
884		panic("EISA bus timeout, likely hardware failure.");
885	} else if(eisa_port & ENMI_IOSTATUS) {
886		panic("EISA I/O port status error.");
887	} else {
888		printf("\nNMI ISA %x, EISA %x\n", isa_port, eisa_port);
889		return(0);
890	}
891}
892
893/*
894 * Caught a stray interrupt, notify
895 */
896static void
897isa_strayintr(d)
898	int d;
899{
900
901	/* DON'T BOTHER FOR NOW! */
902	/* for some reason, we get bursts of intr #7, even if not enabled! */
903	/*
904	 * Well the reason you got bursts of intr #7 is because someone
905	 * raised an interrupt line and dropped it before the 8259 could
906	 * prioritize it.  This is documented in the intel data book.  This
907	 * means you have BAD hardware!  I have changed this so that only
908	 * the first 5 get logged, then it quits logging them, and puts
909	 * out a special message. rgrimes 3/25/1993
910	 */
911	/*
912	 * XXX TODO print a different message for #7 if it is for a
913	 * glitch.  Glitches can be distinguished from real #7's by
914	 * testing that the in-service bit is _not_ set.  The test
915	 * must be done before sending an EOI so it can't be done if
916	 * we are using AUTO_EOI_1.
917	 */
918	if (intrcnt[NR_DEVICES + d] <= 5)
919		log(LOG_ERR, "stray irq %d\n", d);
920	if (intrcnt[NR_DEVICES + d] == 5)
921		log(LOG_CRIT,
922		    "too many stray irq %d's; not logging any more\n", d);
923}
924
925/*
926 * Find the highest priority enabled display device.  Since we can't
927 * distinguish display devices from ttys, depend on display devices
928 * being sensitive and before sensitive non-display devices (if any)
929 * in isa_devtab_tty.
930 *
931 * XXX we should add capability flags IAMDISPLAY and ISUPPORTCONSOLES.
932 */
933struct isa_device *
934find_display()
935{
936	struct isa_device *dvp;
937
938	for (dvp = isa_devtab_tty; dvp->id_driver != NULL; dvp++)
939		if (dvp->id_driver->sensitive_hw && dvp->id_enabled)
940			return (dvp);
941	return (NULL);
942}
943
944/*
945 * find an ISA device in a given isa_devtab_* table, given
946 * the table to search, the expected id_driver entry, and the unit number.
947 *
948 * this function is defined in isa_device.h, and this location is debatable;
949 * i put it there because it's useless w/o, and directly operates on
950 * the other stuff in that file.
951 *
952 */
953
954struct isa_device *find_isadev(table, driverp, unit)
955     struct isa_device *table;
956     struct isa_driver *driverp;
957     int unit;
958{
959  if (driverp == NULL) /* sanity check */
960    return NULL;
961
962  while ((table->id_driver != driverp) || (table->id_unit != unit)) {
963    if (table->id_driver == 0)
964      return NULL;
965
966    table++;
967  }
968
969  return table;
970}
971
972/*
973 * Return nonzero if a (masked) irq is pending for a given device.
974 */
975int
976isa_irq_pending(dvp)
977	struct isa_device *dvp;
978{
979	unsigned id_irq;
980
981	id_irq = dvp->id_irq;
982	if (id_irq & 0xff)
983		return (inb(IO_ICU1) & id_irq);
984	return (inb(IO_ICU2) & (id_irq >> 8));
985}
986
987int
988update_intr_masks(void)
989{
990	int intr, n=0;
991	u_int mask,*maskptr;
992
993	for (intr=0; intr < ICU_LEN; intr ++) {
994		if (intr==2) continue;
995		maskptr = intr_mptr[intr];
996		if (!maskptr) continue;
997		*maskptr |= 1 << intr;
998		mask = *maskptr;
999		if (mask != intr_mask[intr]) {
1000#if 0
1001			printf ("intr_mask[%2d] old=%08x new=%08x ptr=%p.\n",
1002				intr, intr_mask[intr], mask, maskptr);
1003#endif
1004			intr_mask[intr]=mask;
1005			n++;
1006		}
1007
1008	}
1009	return (n);
1010}
1011
1012int
1013register_intr(intr, device_id, flags, handler, maskptr, unit)
1014	int	intr;
1015	int	device_id;
1016	u_int	flags;
1017	inthand2_t *handler;
1018	u_int	*maskptr;
1019	int	unit;
1020{
1021	char	*cp;
1022	u_long	ef;
1023	int	id;
1024	u_int	mask = (maskptr ? *maskptr : 0);
1025
1026	if ((u_int)intr >= ICU_LEN || intr == 2
1027	    || (u_int)device_id >= NR_DEVICES)
1028		return (EINVAL);
1029	if (intr_handler[intr] != isa_strayintr)
1030		return (EBUSY);
1031	ef = read_eflags();
1032	disable_intr();
1033	intr_countp[intr] = &intrcnt[device_id];
1034	intr_handler[intr] = handler;
1035	intr_mptr[intr] = maskptr;
1036	intr_mask[intr] = mask | (1 << intr);
1037	intr_unit[intr] = unit;
1038	setidt(ICU_OFFSET + intr,
1039	       flags & RI_FAST ? fastintr[intr] : slowintr[intr],
1040	       SDT_SYS386IGT, SEL_KPL, GSEL(GCODE_SEL, SEL_KPL));
1041	write_eflags(ef);
1042	for (cp = intrnames, id = 0; id <= device_id; id++)
1043		while (*cp++ != '\0')
1044			;
1045	if (cp > eintrnames)
1046		return (0);
1047	if (intr < 10) {
1048		cp[-3] = intr + '0';
1049		cp[-2] = ' ';
1050	} else {
1051		cp[-3] = '1';
1052		cp[-2] = intr - 10 + '0';
1053	}
1054	return (0);
1055}
1056
1057static void
1058register_imask(dvp, mask)
1059	struct isa_device *dvp;
1060	u_int	mask;
1061{
1062	if (dvp->id_alive && dvp->id_irq) {
1063		int	intr;
1064
1065		intr = ffs(dvp->id_irq) - 1;
1066		intr_mask[intr] = mask | (1 <<intr);
1067	}
1068	(void) update_intr_masks();
1069}
1070
1071int
1072unregister_intr(intr, handler)
1073	int	intr;
1074	inthand2_t *handler;
1075{
1076	u_long	ef;
1077
1078	if ((u_int)intr >= ICU_LEN || handler != intr_handler[intr])
1079		return (EINVAL);
1080	ef = read_eflags();
1081	disable_intr();
1082	intr_countp[intr] = &intrcnt[NR_DEVICES + intr];
1083	intr_handler[intr] = isa_strayintr;
1084	intr_mptr[intr] = NULL;
1085	intr_mask[intr] = HWI_MASK | SWI_MASK;
1086	intr_unit[intr] = intr;
1087	setidt(ICU_OFFSET + intr, slowintr[intr], SDT_SYS386IGT, SEL_KPL,
1088	    GSEL(GCODE_SEL, SEL_KPL));
1089	write_eflags(ef);
1090	return (0);
1091}
1092