isa.c revision 26513
157416Smarkm/*- 257416Smarkm * Copyright (c) 1991 The Regents of the University of California. 357416Smarkm * All rights reserved. 457416Smarkm * 557416Smarkm * This code is derived from software contributed to Berkeley by 657416Smarkm * William Jolitz. 757416Smarkm * 857416Smarkm * Redistribution and use in source and binary forms, with or without 957416Smarkm * modification, are permitted provided that the following conditions 1057416Smarkm * are met: 1157416Smarkm * 1. Redistributions of source code must retain the above copyright 1257416Smarkm * notice, this list of conditions and the following disclaimer. 1357416Smarkm * 2. Redistributions in binary form must reproduce the above copyright 1457416Smarkm * notice, this list of conditions and the following disclaimer in the 1557416Smarkm * documentation and/or other materials provided with the distribution. 1657416Smarkm * 3. All advertising materials mentioning features or use of this software 1757416Smarkm * must display the following acknowledgement: 1857416Smarkm * This product includes software developed by the University of 1957416Smarkm * California, Berkeley and its contributors. 2057416Smarkm * 4. Neither the name of the University nor the names of its contributors 2157416Smarkm * may be used to endorse or promote products derived from this software 2257416Smarkm * without specific prior written permission. 2357416Smarkm * 2457416Smarkm * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 2557416Smarkm * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 2657416Smarkm * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 2757416Smarkm * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 2857416Smarkm * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 2957416Smarkm * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 3057416Smarkm * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 3157416Smarkm * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 3257416Smarkm * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 3357416Smarkm * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 3457416Smarkm * SUCH DAMAGE. 3557416Smarkm * 36233294Sstas * from: @(#)isa.c 7.2 (Berkeley) 5/13/91 3757416Smarkm * $Id: isa.c,v 1.91 1997/06/08 17:14:42 ache Exp $ 3857416Smarkm */ 3957416Smarkm 4057416Smarkm/* 4157416Smarkm * code to manage AT bus 4257416Smarkm * 4357416Smarkm * 92/08/18 Frank P. MacLachlan (fpm@crash.cts.com): 4457416Smarkm * Fixed uninitialized variable problem and added code to deal 4557416Smarkm * with DMA page boundaries in isa_dmarangecheck(). Fixed word 4657416Smarkm * mode DMA count compution and reorganized DMA setup code in 4757416Smarkm * isa_dmastart() 4857416Smarkm */ 4957416Smarkm 5057416Smarkm#include <sys/param.h> 5157416Smarkm#include <sys/systm.h> 5257416Smarkm#include <sys/buf.h> 5357416Smarkm#include <sys/syslog.h> 5457416Smarkm#include <sys/malloc.h> 5557416Smarkm#include <machine/ipl.h> 5657416Smarkm#include <machine/md_var.h> 5757416Smarkm#include <machine/segments.h> 5857416Smarkm#if defined(APIC_IO) 5957416Smarkm#include <machine/smp.h> 6057416Smarkm#include <machine/apic.h> 6157416Smarkm#endif /* APIC_IO */ 6257416Smarkm#include <vm/vm.h> 6357416Smarkm#include <vm/vm_param.h> 6457416Smarkm#include <vm/pmap.h> 6557416Smarkm#include <i386/isa/isa_device.h> 6657416Smarkm#include <i386/isa/intr_machdep.h> 6757416Smarkm#include <i386/isa/isa.h> 6857416Smarkm#include <i386/isa/icu.h> 6957416Smarkm#include <i386/isa/ic/i8237.h> 7057416Smarkm#include "vector.h" 7157416Smarkm 7257416Smarkm#include <sys/interrupt.h> 7357416Smarkm 7457416Smarkm/* 7557416Smarkm** Register definitions for DMA controller 1 (channels 0..3): 7657416Smarkm*/ 7757416Smarkm#define DMA1_CHN(c) (IO_DMA1 + 1*(2*(c))) /* addr reg for channel c */ 7857416Smarkm#define DMA1_SMSK (IO_DMA1 + 1*10) /* single mask register */ 7957416Smarkm#define DMA1_MODE (IO_DMA1 + 1*11) /* mode register */ 8057416Smarkm#define DMA1_FFC (IO_DMA1 + 1*12) /* clear first/last FF */ 8157416Smarkm 8257416Smarkm/* 8357416Smarkm** Register definitions for DMA controller 2 (channels 4..7): 8457416Smarkm*/ 8557416Smarkm#define DMA2_CHN(c) (IO_DMA2 + 2*(2*(c))) /* addr reg for channel c */ 8657416Smarkm#define DMA2_SMSK (IO_DMA2 + 2*10) /* single mask register */ 8757416Smarkm#define DMA2_MODE (IO_DMA2 + 2*11) /* mode register */ 8857416Smarkm#define DMA2_FFC (IO_DMA2 + 2*12) /* clear first/last FF */ 8957416Smarkm 9057416Smarkmstatic void config_isadev __P((struct isa_device *isdp, u_int *mp)); 9157416Smarkmstatic void config_isadev_c __P((struct isa_device *isdp, u_int *mp, 9257416Smarkm int reconfig)); 9357416Smarkmstatic void conflict __P((struct isa_device *dvp, struct isa_device *tmpdvp, 9457416Smarkm int item, char const *whatnot, char const *reason, 9557416Smarkm char const *format)); 9657416Smarkmstatic int haveseen __P((struct isa_device *dvp, struct isa_device *tmpdvp, 9757416Smarkm u_int checkbits)); 9857416Smarkmstatic int isa_dmarangecheck __P((caddr_t va, u_int length, int chan)); 9957416Smarkm 10057416Smarkm/* 10157416Smarkm * print a conflict message 10257416Smarkm */ 10357416Smarkmstatic void 10457416Smarkmconflict(dvp, tmpdvp, item, whatnot, reason, format) 10557416Smarkm struct isa_device *dvp; 10657416Smarkm struct isa_device *tmpdvp; 10757416Smarkm int item; 10857416Smarkm char const *whatnot; 10957416Smarkm char const *reason; 11057416Smarkm char const *format; 11157416Smarkm{ 11257416Smarkm printf("%s%d not %sed due to %s conflict with %s%d at ", 11357416Smarkm dvp->id_driver->name, dvp->id_unit, whatnot, reason, 11457416Smarkm tmpdvp->id_driver->name, tmpdvp->id_unit); 11557416Smarkm printf(format, item); 11657416Smarkm printf("\n"); 11757416Smarkm} 11857416Smarkm 11957416Smarkm/* 12057416Smarkm * Check to see if things are already in use, like IRQ's, I/O addresses 12157416Smarkm * and Memory addresses. 12257416Smarkm */ 12357416Smarkmstatic int 12457416Smarkmhaveseen(dvp, tmpdvp, checkbits) 12557416Smarkm struct isa_device *dvp; 12657416Smarkm struct isa_device *tmpdvp; 12757416Smarkm u_int checkbits; 12857416Smarkm{ 12957416Smarkm /* 13057416Smarkm * Only check against devices that have already been found and are not 13157416Smarkm * unilaterally allowed to conflict anyway. 13257416Smarkm */ 13357416Smarkm if (tmpdvp->id_alive && !dvp->id_conflicts) { 13457416Smarkm char const *whatnot; 13557416Smarkm 13657416Smarkm whatnot = checkbits & CC_ATTACH ? "attach" : "prob"; 13757416Smarkm /* 13857416Smarkm * Check for I/O address conflict. We can only check the 13957416Smarkm * starting address of the device against the range of the 14057416Smarkm * device that has already been probed since we do not 14157416Smarkm * know how many I/O addresses this device uses. 14257416Smarkm */ 14357416Smarkm if (checkbits & CC_IOADDR && tmpdvp->id_alive != -1) { 14457416Smarkm if ((dvp->id_iobase >= tmpdvp->id_iobase) && 14557416Smarkm (dvp->id_iobase <= 14657416Smarkm (tmpdvp->id_iobase + tmpdvp->id_alive - 1))) { 14757416Smarkm conflict(dvp, tmpdvp, dvp->id_iobase, whatnot, 14857416Smarkm "I/O address", "0x%x"); 14957416Smarkm return 1; 15057416Smarkm } 15157416Smarkm } 15257416Smarkm /* 15357416Smarkm * Check for Memory address conflict. We can check for 15457416Smarkm * range overlap, but it will not catch all cases since the 15557416Smarkm * driver may adjust the msize paramater during probe, for 15657416Smarkm * now we just check that the starting address does not 15757416Smarkm * fall within any allocated region. 15857416Smarkm * XXX could add a second check after the probe for overlap, 15957416Smarkm * since at that time we would know the full range. 16057416Smarkm * XXX KERNBASE is a hack, we should have vaddr in the table! 16157416Smarkm */ 16257416Smarkm if (checkbits & CC_MEMADDR && tmpdvp->id_maddr) { 163102644Snectar if ((KERNBASE + dvp->id_maddr >= tmpdvp->id_maddr) && 16457416Smarkm (KERNBASE + dvp->id_maddr <= 16557416Smarkm (tmpdvp->id_maddr + tmpdvp->id_msize - 1))) { 16657416Smarkm conflict(dvp, tmpdvp, (int)dvp->id_maddr, 16757416Smarkm whatnot, "maddr", "0x%x"); 16857416Smarkm return 1; 16957416Smarkm } 17057416Smarkm } 17157416Smarkm /* 17257416Smarkm * Check for IRQ conflicts. 17357416Smarkm */ 17457416Smarkm if (checkbits & CC_IRQ && tmpdvp->id_irq) { 17557416Smarkm if (tmpdvp->id_irq == dvp->id_irq) { 17657416Smarkm conflict(dvp, tmpdvp, ffs(dvp->id_irq) - 1, 17757416Smarkm whatnot, "irq", "%d"); 17857416Smarkm return 1; 17957416Smarkm } 18057416Smarkm } 18157416Smarkm /* 18257416Smarkm * Check for DRQ conflicts. 18357416Smarkm */ 18457416Smarkm if (checkbits & CC_DRQ && tmpdvp->id_drq != -1) { 18557416Smarkm if (tmpdvp->id_drq == dvp->id_drq) { 18657416Smarkm conflict(dvp, tmpdvp, dvp->id_drq, whatnot, 18757416Smarkm "drq", "%d"); 18857416Smarkm return 1; 18957416Smarkm } 19057416Smarkm } 19157416Smarkm } 19257416Smarkm return 0; 19357416Smarkm} 19457416Smarkm 19557416Smarkm#ifdef RESOURCE_CHECK 19657416Smarkm#include <sys/drvresource.h> 19757416Smarkm 19857416Smarkmstatic int 19957416Smarkmcheckone (struct isa_device *dvp, int type, addr_t low, addr_t high, 20057416Smarkm char *resname, char *resfmt, int attaching) 20157416Smarkm{ 20257416Smarkm int result = 0; 20357416Smarkm if (bootverbose) { 20457416Smarkm if (low == high) 20557416Smarkm printf("\tcheck %s: 0x%x\n", resname, low); 20657416Smarkm else 20757416Smarkm printf("\tcheck %s: 0x%x to 0x%x\n", 20857416Smarkm resname, low, high); 20957416Smarkm } 21057416Smarkm if (resource_check(type, RESF_NONE, low, high) != NULL) { 21157416Smarkm char *whatnot = attaching ? "attach" : "prob"; 21257416Smarkm static struct isa_device dummydev; 21357416Smarkm static struct isa_driver dummydrv; 21457416Smarkm struct isa_device *tmpdvp = &dummydev; 21557416Smarkm 21657416Smarkm dummydev.id_driver = &dummydrv; 21757416Smarkm dummydev.id_unit = 0; 21857416Smarkm dummydrv.name = "pci"; 21957416Smarkm conflict(dvp, tmpdvp, low, whatnot, resname, resfmt); 22057416Smarkm result = 1; 22157416Smarkm } else if (attaching) { 22257416Smarkm if (low == high) 22357416Smarkm printf("\tregister %s: 0x%x\n", resname, low); 22457416Smarkm else 22557416Smarkm printf("\tregister %s: 0x%x to 0x%x\n", 22657416Smarkm resname, low, high); 22757416Smarkm resource_claim(dvp, type, RESF_NONE, low, high); 22857416Smarkm } 22957416Smarkm return (result); 23057416Smarkm} 23157416Smarkm 23257416Smarkmstatic int 23357416Smarkmcheck_pciconflict(struct isa_device *dvp, int checkbits) 23457416Smarkm{ 23557416Smarkm int result = 0; 23657416Smarkm int attaching = (checkbits & CC_ATTACH) != 0; 23757416Smarkm 23857416Smarkm if (checkbits & CC_MEMADDR) { 23957416Smarkm long maddr = dvp->id_maddr; 24057416Smarkm long msize = dvp->id_msize; 24157416Smarkm if (msize > 0) { 24257416Smarkm if (checkone(dvp, REST_MEM, maddr, maddr + msize - 1, 24357416Smarkm "maddr", "0x%x", attaching) != 0) { 24457416Smarkm result = 1; 24557416Smarkm attaching = 0; 24657416Smarkm } 24757416Smarkm } 24857416Smarkm } 24957416Smarkm if (checkbits & CC_IOADDR) { 25057416Smarkm unsigned iobase = dvp->id_iobase; 25157416Smarkm unsigned iosize = dvp->id_alive; 25257416Smarkm if (iosize == -1) 25357416Smarkm iosize = 1; /* XXX can't do much about this ... */ 25457416Smarkm if (iosize > 0) { 25557416Smarkm if (checkone(dvp, REST_PORT, iobase, iobase + iosize -1, 25657416Smarkm "I/O address", "0x%x", attaching) != 0) { 25757416Smarkm result = 1; 25857416Smarkm attaching = 0; 25957416Smarkm } 26057416Smarkm } 26157416Smarkm } 26257416Smarkm if (checkbits & CC_IRQ) { 26357416Smarkm int irq = ffs(dvp->id_irq) - 1; 26457416Smarkm if (irq >= 0) { 26557416Smarkm if (checkone(dvp, REST_INT, irq, irq, 26657416Smarkm "irq", "%d", attaching) != 0) { 26757416Smarkm result = 1; 26857416Smarkm attaching = 0; 26957416Smarkm } 27057416Smarkm } 27157416Smarkm } 27257416Smarkm if (checkbits & CC_DRQ) { 27357416Smarkm int drq = dvp->id_drq; 27457416Smarkm if (drq >= 0) { 27557416Smarkm if (checkone(dvp, REST_DMA, drq, drq, 27657416Smarkm "drq", "%d", attaching) != 0) { 27757416Smarkm result = 1; 27857416Smarkm attaching = 0; 27957416Smarkm } 28057416Smarkm } 28157416Smarkm } 28257416Smarkm if (result != 0) 28357416Smarkm resource_free (dvp); 28457416Smarkm return (result); 28557416Smarkm} 28657416Smarkm#endif /* RESOURCE_CHECK */ 28757416Smarkm 28857416Smarkm/* 28957416Smarkm * Search through all the isa_devtab_* tables looking for anything that 29057416Smarkm * conflicts with the current device. 29157416Smarkm */ 29257416Smarkmint 29357416Smarkmhaveseen_isadev(dvp, checkbits) 29457416Smarkm struct isa_device *dvp; 29557416Smarkm u_int checkbits; 29657416Smarkm{ 29757416Smarkm struct isa_device *tmpdvp; 29857416Smarkm int status = 0; 29957416Smarkm 30057416Smarkm for (tmpdvp = isa_devtab_tty; tmpdvp->id_driver; tmpdvp++) { 30157416Smarkm status |= haveseen(dvp, tmpdvp, checkbits); 30257416Smarkm if (status) 30357416Smarkm return status; 30457416Smarkm } 30557416Smarkm for (tmpdvp = isa_devtab_bio; tmpdvp->id_driver; tmpdvp++) { 30657416Smarkm status |= haveseen(dvp, tmpdvp, checkbits); 30757416Smarkm if (status) 30857416Smarkm return status; 30957416Smarkm } 31057416Smarkm for (tmpdvp = isa_devtab_net; tmpdvp->id_driver; tmpdvp++) { 31157416Smarkm status |= haveseen(dvp, tmpdvp, checkbits); 31257416Smarkm if (status) 31357416Smarkm return status; 31457416Smarkm } 31557416Smarkm for (tmpdvp = isa_devtab_null; tmpdvp->id_driver; tmpdvp++) { 31657416Smarkm status |= haveseen(dvp, tmpdvp, checkbits); 31757416Smarkm if (status) 31857416Smarkm return status; 31957416Smarkm } 32057416Smarkm#ifdef RESOURCE_CHECK 32157416Smarkm if (!dvp->id_conflicts) { 32257416Smarkm status = check_pciconflict(dvp, checkbits); 32357416Smarkm } else if (bootverbose) 32457416Smarkm printf("\tnot checking for resource conflicts ...\n"); 32557416Smarkm } 32657416Smarkm#endif /* RESOURCE_CHECK */ 32757416Smarkm return(status); 32857416Smarkm} 32957416Smarkm 33057416Smarkm/* 33157416Smarkm * Configure all ISA devices 33257416Smarkm */ 33357416Smarkmvoid 33457416Smarkmisa_configure() { 33557416Smarkm struct isa_device *dvp; 33657416Smarkm 33757416Smarkm splhigh(); 33857416Smarkm printf("Probing for devices on the ISA bus:\n"); 33957416Smarkm /* First probe all the sensitive probes */ 34057416Smarkm for (dvp = isa_devtab_tty; dvp->id_driver; dvp++) 34157416Smarkm if (dvp->id_driver->sensitive_hw) 34257416Smarkm config_isadev(dvp, &tty_imask); 34357416Smarkm for (dvp = isa_devtab_bio; dvp->id_driver; dvp++) 34457416Smarkm if (dvp->id_driver->sensitive_hw) 34557416Smarkm config_isadev(dvp, &bio_imask); 34657416Smarkm for (dvp = isa_devtab_net; dvp->id_driver; dvp++) 34757416Smarkm if (dvp->id_driver->sensitive_hw) 34857416Smarkm config_isadev(dvp, &net_imask); 34957416Smarkm for (dvp = isa_devtab_null; dvp->id_driver; dvp++) 35057416Smarkm if (dvp->id_driver->sensitive_hw) 35157416Smarkm config_isadev(dvp, (u_int *)NULL); 35257416Smarkm 35357416Smarkm /* Then all the bad ones */ 35457416Smarkm for (dvp = isa_devtab_tty; dvp->id_driver; dvp++) 35557416Smarkm if (!dvp->id_driver->sensitive_hw) 35657416Smarkm config_isadev(dvp, &tty_imask); 35757416Smarkm for (dvp = isa_devtab_bio; dvp->id_driver; dvp++) 35857416Smarkm if (!dvp->id_driver->sensitive_hw) 35957416Smarkm config_isadev(dvp, &bio_imask); 36057416Smarkm for (dvp = isa_devtab_net; dvp->id_driver; dvp++) 36157416Smarkm if (!dvp->id_driver->sensitive_hw) 36257416Smarkm config_isadev(dvp, &net_imask); 36357416Smarkm for (dvp = isa_devtab_null; dvp->id_driver; dvp++) 36457416Smarkm if (!dvp->id_driver->sensitive_hw) 36557416Smarkm config_isadev(dvp, (u_int *)NULL); 36657416Smarkm 36757416Smarkm bio_imask |= SWI_CLOCK_MASK; 36857416Smarkm net_imask |= SWI_NET_MASK; 36957416Smarkm tty_imask |= SWI_TTY_MASK; 37057416Smarkm 37157416Smarkm/* 37257416Smarkm * XXX we should really add the tty device to net_imask when the line is 37357416Smarkm * switched to SLIPDISC, and then remove it when it is switched away from 37457416Smarkm * SLIPDISC. No need to block out ALL ttys during a splimp when only one 37557416Smarkm * of them is running slip. 37657416Smarkm * 37757416Smarkm * XXX actually, blocking all ttys during a splimp doesn't matter so much 37857416Smarkm * with sio because the serial interrupt layer doesn't use tty_imask. Only 37957416Smarkm * non-serial ttys suffer. It's more stupid that ALL 'net's are blocked 38057416Smarkm * during spltty. 38157416Smarkm */ 38257416Smarkm#include "sl.h" 38357416Smarkm#if NSL > 0 38457416Smarkm net_imask |= tty_imask; 38557416Smarkm tty_imask = net_imask; 38657416Smarkm#endif 38757416Smarkm 38857416Smarkm /* bio_imask |= tty_imask ; can some tty devices use buffers? */ 38957416Smarkm 39057416Smarkm if (bootverbose) 39157416Smarkm printf("imasks: bio %x, tty %x, net %x\n", 39257416Smarkm bio_imask, tty_imask, net_imask); 39357416Smarkm 39457416Smarkm /* 39557416Smarkm * Finish initializing intr_mask[]. Note that the partly 39657416Smarkm * constructed masks aren't actually used since we're at splhigh. 39757416Smarkm * For fully dynamic initialization, register_intr() and 39857416Smarkm * icu_unset() will have to adjust the masks for _all_ 39957416Smarkm * interrupts and for tty_imask, etc. 40057416Smarkm */ 40157416Smarkm for (dvp = isa_devtab_tty; dvp->id_driver; dvp++) 40257416Smarkm register_imask(dvp, tty_imask); 40357416Smarkm for (dvp = isa_devtab_bio; dvp->id_driver; dvp++) 40457416Smarkm register_imask(dvp, bio_imask); 40557416Smarkm for (dvp = isa_devtab_net; dvp->id_driver; dvp++) 406233294Sstas register_imask(dvp, net_imask); 407233294Sstas for (dvp = isa_devtab_null; dvp->id_driver; dvp++) 40857416Smarkm register_imask(dvp, SWI_CLOCK_MASK); 409233294Sstas spl0(); 41057416Smarkm} 411178825Sdfr 41257416Smarkm/* 41357416Smarkm * Configure an ISA device. 41457416Smarkm */ 41557416Smarkm 41657416Smarkm 41757416Smarkmstatic void 41857416Smarkmconfig_isadev(isdp, mp) 41957416Smarkm struct isa_device *isdp; 42057416Smarkm u_int *mp; 42157416Smarkm{ 42257416Smarkm config_isadev_c(isdp, mp, 0); 42357416Smarkm} 42457416Smarkm 42557416Smarkmvoid 42657416Smarkmreconfig_isadev(isdp, mp) 42757416Smarkm struct isa_device *isdp; 42857416Smarkm u_int *mp; 42957416Smarkm{ 43057416Smarkm config_isadev_c(isdp, mp, 1); 43157416Smarkm} 43257416Smarkm 43357416Smarkmstatic void 43457416Smarkmconfig_isadev_c(isdp, mp, reconfig) 43557416Smarkm struct isa_device *isdp; 43657416Smarkm u_int *mp; 43757416Smarkm int reconfig; 43857416Smarkm{ 43957416Smarkm u_int checkbits; 44057416Smarkm int id_alive; 44157416Smarkm int last_alive; 44257416Smarkm struct isa_driver *dp = isdp->id_driver; 44357416Smarkm 44457416Smarkm if (!isdp->id_enabled) { 44557416Smarkm printf("%s%d: disabled, not probed.\n", 44657416Smarkm dp->name, isdp->id_unit); 44757416Smarkm return; 44857416Smarkm } 44957416Smarkm checkbits = CC_DRQ | CC_IOADDR | CC_MEMADDR; 45057416Smarkm if (!reconfig && haveseen_isadev(isdp, checkbits)) 45157416Smarkm return; 45257416Smarkm if (!reconfig && isdp->id_maddr) { 45357416Smarkm isdp->id_maddr -= ISA_HOLE_START; 45457416Smarkm isdp->id_maddr += atdevbase; 45557416Smarkm } 45657416Smarkm if (reconfig) { 45757416Smarkm last_alive = isdp->id_alive; 45857416Smarkm isdp->id_reconfig = 1; 45957416Smarkm } 46057416Smarkm else { 46157416Smarkm last_alive = 0; 46257416Smarkm isdp->id_reconfig = 0; 46357416Smarkm } 46457416Smarkm id_alive = (*dp->probe)(isdp); 46557416Smarkm if (id_alive) { 46657416Smarkm /* 46757416Smarkm * Only print the I/O address range if id_alive != -1 46857416Smarkm * Right now this is a temporary fix just for the new 46957416Smarkm * NPX code so that if it finds a 486 that can use trap 47057416Smarkm * 16 it will not report I/O addresses. 47157416Smarkm * Rod Grimes 04/26/94 47257416Smarkm */ 47357416Smarkm if (!isdp->id_reconfig) { 47457416Smarkm printf("%s%d", dp->name, isdp->id_unit); 47557416Smarkm if (id_alive != -1) { 47657416Smarkm if (isdp->id_iobase == -1) 47757416Smarkm printf(" at ?"); 47857416Smarkm else { 47957416Smarkm printf(" at 0x%x", isdp->id_iobase); 48057416Smarkm if (isdp->id_iobase + id_alive - 1 != 48157416Smarkm isdp->id_iobase) { 48257416Smarkm printf("-0x%x", 48357416Smarkm isdp->id_iobase + id_alive - 1); 48457416Smarkm } 48557416Smarkm } 48657416Smarkm } 487 if (isdp->id_irq) 488 printf(" irq %d", ffs(isdp->id_irq) - 1); 489 if (isdp->id_drq != -1) 490 printf(" drq %d", isdp->id_drq); 491 if (isdp->id_maddr) 492 printf(" maddr 0x%lx", kvtop(isdp->id_maddr)); 493 if (isdp->id_msize) 494 printf(" msize %d", isdp->id_msize); 495 if (isdp->id_flags) 496 printf(" flags 0x%x", isdp->id_flags); 497 if (isdp->id_iobase && !(isdp->id_iobase & 0xf300)) { 498 printf(" on motherboard"); 499 } else if (isdp->id_iobase >= 0x1000 && 500 !(isdp->id_iobase & 0x300)) { 501 printf (" on eisa slot %d", 502 isdp->id_iobase >> 12); 503 } else { 504 printf (" on isa"); 505 } 506 printf("\n"); 507 /* 508 * Check for conflicts again. The driver may have 509 * changed *dvp. We should weaken the early check 510 * since the driver may have been able to change 511 * *dvp to avoid conflicts if given a chance. We 512 * already skip the early check for IRQs and force 513 * a check for IRQs in the next group of checks. 514 */ 515 checkbits |= CC_IRQ; 516 if (haveseen_isadev(isdp, checkbits)) { 517 return; 518 } 519 isdp->id_alive = id_alive; 520 } 521 (*dp->attach)(isdp); 522 if (isdp->id_irq) { 523#if defined(APIC_IO) 524 /* 525 * Some motherboards use upper IRQs for traditional 526 * ISA INTerrupt sources. In particular we have 527 * seen the secondary IDE connected to IRQ20. 528 * This code detects and fixes this situation. 529 */ 530 u_int apic_mask; 531 int rirq; 532 533 apic_mask = get_isa_apic_mask(isdp->id_irq); 534 if (apic_mask != isdp->id_irq) { 535 rirq = ffs(isdp->id_irq) - 1; 536 isdp->id_irq = apic_mask; 537 undirect_isa_irq(rirq); /* free for ISA */ 538 } 539#endif /* APIC_IO */ 540 if (!isdp->id_conflicts 541 || (!intr_registered(ffs(isdp->id_irq) - 1) 542 && isdp->id_intr != NULL)) 543 register_intr(ffs(isdp->id_irq) - 1, 544 isdp->id_id, 545 isdp->id_ri_flags, 546 isdp->id_intr, 547 mp, isdp->id_unit); 548 } 549 } else { 550 if (isdp->id_reconfig) { 551 (*dp->attach)(isdp); /* reconfiguration attach */ 552 } 553 if (!last_alive) { 554 if (!isdp->id_reconfig) { 555 printf("%s%d not found", 556 dp->name, isdp->id_unit); 557 if (isdp->id_iobase != -1) 558 printf(" at 0x%x", isdp->id_iobase); 559 printf("\n"); 560 } 561 } 562 else { 563#if 0 564 /* This code has not been tested.... */ 565 if (isdp->id_irq) { 566 icu_unset(ffs(isdp->id_irq) - 1, 567 isdp->id_intr); 568 if (mp) 569 INTRUNMASK(*mp, isdp->id_irq); 570 } 571#else 572 printf ("icu_unset() not supported here ...\n"); 573#endif 574 } 575 } 576} 577 578static caddr_t dma_bouncebuf[8]; 579static u_int dma_bouncebufsize[8]; 580static u_int8_t dma_bounced = 0; 581static u_int8_t dma_busy = 0; /* Used in isa_dmastart() */ 582static u_int8_t dma_inuse = 0; /* User for acquire/release */ 583 584#define VALID_DMA_MASK (7) 585 586/* high byte of address is stored in this port for i-th dma channel */ 587static int dmapageport[8] = { 0x87, 0x83, 0x81, 0x82, 0x8f, 0x8b, 0x89, 0x8a }; 588 589/* 590 * Setup a DMA channel's bounce buffer. 591 */ 592void 593isa_dmainit(chan, bouncebufsize) 594 int chan; 595 u_int bouncebufsize; 596{ 597 void *buf; 598 599#ifdef DIAGNOSTIC 600 if (chan & ~VALID_DMA_MASK) 601 panic("isa_dmainit: channel out of range"); 602 603 if (dma_bouncebuf[chan] != NULL) 604 panic("isa_dmainit: impossible request"); 605#endif 606 607 dma_bouncebufsize[chan] = bouncebufsize; 608 609 /* Try malloc() first. It works better if it works. */ 610 buf = malloc(bouncebufsize, M_DEVBUF, M_NOWAIT); 611 if (buf != NULL) { 612 if (isa_dmarangecheck(buf, bouncebufsize, chan) == 0) { 613 dma_bouncebuf[chan] = buf; 614 return; 615 } 616 free(buf, M_DEVBUF); 617 } 618 buf = contigmalloc(bouncebufsize, M_DEVBUF, M_NOWAIT, 0ul, 0xfffffful, 619 1ul, chan & 4 ? 0x20000ul : 0x10000ul); 620 if (buf == NULL) 621 printf("isa_dmainit(%d, %d) failed\n", chan, bouncebufsize); 622 else 623 dma_bouncebuf[chan] = buf; 624} 625 626/* 627 * Register a DMA channel's usage. Usually called from a device driver 628 * in open() or during it's initialization. 629 */ 630int 631isa_dma_acquire(chan) 632 int chan; 633{ 634#ifdef DIAGNOSTIC 635 if (chan & ~VALID_DMA_MASK) 636 panic("isa_dma_acquire: channel out of range"); 637#endif 638 639 if (dma_inuse & (1 << chan)) { 640 printf("isa_dma_acquire: channel %d already in use\n", chan); 641 return (EBUSY); 642 } 643 dma_inuse |= (1 << chan); 644 645 return (0); 646} 647 648/* 649 * Unregister a DMA channel's usage. Usually called from a device driver 650 * during close() or during it's shutdown. 651 */ 652void 653isa_dma_release(chan) 654 int chan; 655{ 656#ifdef DIAGNOSTIC 657 if (chan & ~VALID_DMA_MASK) 658 panic("isa_dma_release: channel out of range"); 659 660 if (dma_inuse & (1 << chan) == 0) 661 printf("isa_dma_release: channel %d not in use\n", chan); 662#endif 663 664 if (dma_busy & (1 << chan)) { 665 dma_busy &= ~(1 << chan); 666 /* 667 * XXX We should also do "dma_bounced &= (1 << chan);" 668 * because we are acting on behalf of isa_dmadone() which 669 * was not called to end the last DMA operation. This does 670 * not matter now, but it may in the future. 671 */ 672 } 673 674 dma_inuse &= ~(1 << chan); 675} 676 677/* 678 * isa_dmacascade(): program 8237 DMA controller channel to accept 679 * external dma control by a board. 680 */ 681void isa_dmacascade(chan) 682 int chan; 683{ 684#ifdef DIAGNOSTIC 685 if (chan & ~VALID_DMA_MASK) 686 panic("isa_dmacascade: channel out of range"); 687#endif 688 689 /* set dma channel mode, and set dma channel mode */ 690 if ((chan & 4) == 0) { 691 outb(DMA1_MODE, DMA37MD_CASCADE | chan); 692 outb(DMA1_SMSK, chan); 693 } else { 694 outb(DMA2_MODE, DMA37MD_CASCADE | (chan & 3)); 695 outb(DMA2_SMSK, chan & 3); 696 } 697} 698 699/* 700 * isa_dmastart(): program 8237 DMA controller channel, avoid page alignment 701 * problems by using a bounce buffer. 702 */ 703void isa_dmastart(int flags, caddr_t addr, u_int nbytes, int chan) 704{ 705 vm_offset_t phys; 706 int waport; 707 caddr_t newaddr; 708 709#ifdef DIAGNOSTIC 710 if (chan & ~VALID_DMA_MASK) 711 panic("isa_dmastart: channel out of range"); 712 713 if ((chan < 4 && nbytes > (1<<16)) 714 || (chan >= 4 && (nbytes > (1<<17) || (u_int)addr & 1))) 715 panic("isa_dmastart: impossible request"); 716 717 if (dma_inuse & (1 << chan) == 0) 718 printf("isa_dmastart: channel %d not acquired\n", chan); 719#endif 720 721#if 0 722 /* 723 * XXX This should be checked, but drivers like ad1848 only call 724 * isa_dmastart() once because they use Auto DMA mode. If we 725 * leave this in, drivers that do this will print this continuously. 726 */ 727 if (dma_busy & (1 << chan)) 728 printf("isa_dmastart: channel %d busy\n", chan); 729#endif 730 731 dma_busy |= (1 << chan); 732 733 if (isa_dmarangecheck(addr, nbytes, chan)) { 734 if (dma_bouncebuf[chan] == NULL 735 || dma_bouncebufsize[chan] < nbytes) 736 panic("isa_dmastart: bad bounce buffer"); 737 dma_bounced |= (1 << chan); 738 newaddr = dma_bouncebuf[chan]; 739 740 /* copy bounce buffer on write */ 741 if (!(flags & B_READ)) 742 bcopy(addr, newaddr, nbytes); 743 addr = newaddr; 744 } 745 746 /* translate to physical */ 747 phys = pmap_extract(pmap_kernel(), (vm_offset_t)addr); 748 749 if ((chan & 4) == 0) { 750 /* 751 * Program one of DMA channels 0..3. These are 752 * byte mode channels. 753 */ 754 /* set dma channel mode, and reset address ff */ 755 756 /* If B_RAW flag is set, then use autoinitialise mode */ 757 if (flags & B_RAW) { 758 if (flags & B_READ) 759 outb(DMA1_MODE, DMA37MD_AUTO|DMA37MD_WRITE|chan); 760 else 761 outb(DMA1_MODE, DMA37MD_AUTO|DMA37MD_READ|chan); 762 } 763 else 764 if (flags & B_READ) 765 outb(DMA1_MODE, DMA37MD_SINGLE|DMA37MD_WRITE|chan); 766 else 767 outb(DMA1_MODE, DMA37MD_SINGLE|DMA37MD_READ|chan); 768 outb(DMA1_FFC, 0); 769 770 /* send start address */ 771 waport = DMA1_CHN(chan); 772 outb(waport, phys); 773 outb(waport, phys>>8); 774 outb(dmapageport[chan], phys>>16); 775 776 /* send count */ 777 outb(waport + 1, --nbytes); 778 outb(waport + 1, nbytes>>8); 779 780 /* unmask channel */ 781 outb(DMA1_SMSK, chan); 782 } else { 783 /* 784 * Program one of DMA channels 4..7. These are 785 * word mode channels. 786 */ 787 /* set dma channel mode, and reset address ff */ 788 789 /* If B_RAW flag is set, then use autoinitialise mode */ 790 if (flags & B_RAW) { 791 if (flags & B_READ) 792 outb(DMA2_MODE, DMA37MD_AUTO|DMA37MD_WRITE|(chan&3)); 793 else 794 outb(DMA2_MODE, DMA37MD_AUTO|DMA37MD_READ|(chan&3)); 795 } 796 else 797 if (flags & B_READ) 798 outb(DMA2_MODE, DMA37MD_SINGLE|DMA37MD_WRITE|(chan&3)); 799 else 800 outb(DMA2_MODE, DMA37MD_SINGLE|DMA37MD_READ|(chan&3)); 801 outb(DMA2_FFC, 0); 802 803 /* send start address */ 804 waport = DMA2_CHN(chan - 4); 805 outb(waport, phys>>1); 806 outb(waport, phys>>9); 807 outb(dmapageport[chan], phys>>16); 808 809 /* send count */ 810 nbytes >>= 1; 811 outb(waport + 2, --nbytes); 812 outb(waport + 2, nbytes>>8); 813 814 /* unmask channel */ 815 outb(DMA2_SMSK, chan & 3); 816 } 817} 818 819void isa_dmadone(int flags, caddr_t addr, int nbytes, int chan) 820{ 821#ifdef DIAGNOSTIC 822 if (chan & ~VALID_DMA_MASK) 823 panic("isa_dmadone: channel out of range"); 824 825 if (dma_inuse & (1 << chan) == 0) 826 printf("isa_dmadone: channel %d not acquired\n", chan); 827#endif 828 829#if 0 830 /* 831 * XXX This should be checked, but drivers like ad1848 only call 832 * isa_dmastart() once because they use Auto DMA mode. If we 833 * leave this in, drivers that do this will print this continuously. 834 */ 835 if (dma_busy & (1 << chan) == 0) 836 printf("isa_dmadone: channel %d not busy\n", chan); 837#endif 838 839 if (dma_bounced & (1 << chan)) { 840 /* copy bounce buffer on read */ 841 if (flags & B_READ) 842 bcopy(dma_bouncebuf[chan], addr, nbytes); 843 844 dma_bounced &= ~(1 << chan); 845 } 846 dma_busy &= ~(1 << chan); 847} 848 849/* 850 * Check for problems with the address range of a DMA transfer 851 * (non-contiguous physical pages, outside of bus address space, 852 * crossing DMA page boundaries). 853 * Return true if special handling needed. 854 */ 855 856static int 857isa_dmarangecheck(caddr_t va, u_int length, int chan) { 858 vm_offset_t phys, priorpage = 0, endva; 859 u_int dma_pgmsk = (chan & 4) ? ~(128*1024-1) : ~(64*1024-1); 860 861 endva = (vm_offset_t)round_page(va + length); 862 for (; va < (caddr_t) endva ; va += PAGE_SIZE) { 863 phys = trunc_page(pmap_extract(pmap_kernel(), (vm_offset_t)va)); 864#define ISARAM_END RAM_END 865 if (phys == 0) 866 panic("isa_dmacheck: no physical page present"); 867 if (phys >= ISARAM_END) 868 return (1); 869 if (priorpage) { 870 if (priorpage + PAGE_SIZE != phys) 871 return (1); 872 /* check if crossing a DMA page boundary */ 873 if (((u_int)priorpage ^ (u_int)phys) & dma_pgmsk) 874 return (1); 875 } 876 priorpage = phys; 877 } 878 return (0); 879} 880 881/* 882 * Find the highest priority enabled display device. Since we can't 883 * distinguish display devices from ttys, depend on display devices 884 * being sensitive and before sensitive non-display devices (if any) 885 * in isa_devtab_tty. 886 * 887 * XXX we should add capability flags IAMDISPLAY and ISUPPORTCONSOLES. 888 */ 889struct isa_device * 890find_display() 891{ 892 struct isa_device *dvp; 893 894 for (dvp = isa_devtab_tty; dvp->id_driver != NULL; dvp++) 895 if (dvp->id_driver->sensitive_hw && dvp->id_enabled) 896 return (dvp); 897 return (NULL); 898} 899 900/* 901 * find an ISA device in a given isa_devtab_* table, given 902 * the table to search, the expected id_driver entry, and the unit number. 903 * 904 * this function is defined in isa_device.h, and this location is debatable; 905 * i put it there because it's useless w/o, and directly operates on 906 * the other stuff in that file. 907 * 908 */ 909 910struct isa_device *find_isadev(table, driverp, unit) 911 struct isa_device *table; 912 struct isa_driver *driverp; 913 int unit; 914{ 915 if (driverp == NULL) /* sanity check */ 916 return (NULL); 917 918 while ((table->id_driver != driverp) || (table->id_unit != unit)) { 919 if (table->id_driver == 0) 920 return NULL; 921 922 table++; 923 } 924 925 return (table); 926} 927 928