File:  [DragonFly] / src / sys / bus / pci / i386 / pci_cfgreg.c
Revision 1.7: download - view: text, annotated - select for diffs
Sun Feb 8 07:10:46 2004 UTC (10 years, 2 months ago) by hmp
Branches: MAIN
CVS tags: HEAD, DragonFly_Snap29Sep2004, DragonFly_Snap13Sep2004, DragonFly_1_0_REL, DragonFly_1_0_RC1, DragonFly_1_0A_REL
Merge from FreeBSD:

	Replace an outb() with a DELAY(1) during the test for configuration
	mechanism #1.  This fixes probing for PCI on some systems.

    1: /*
    2:  * Copyright (c) 1997, Stefan Esser <se@freebsd.org>
    3:  * Copyright (c) 2000, Michael Smith <msmith@freebsd.org>
    4:  * Copyright (c) 2000, BSDi
    5:  * All rights reserved.
    6:  *
    7:  * Redistribution and use in source and binary forms, with or without
    8:  * modification, are permitted provided that the following conditions
    9:  * are met:
   10:  * 1. Redistributions of source code must retain the above copyright
   11:  *    notice unmodified, this list of conditions, and the following
   12:  *    disclaimer.
   13:  * 2. Redistributions in binary form must reproduce the above copyright
   14:  *    notice, this list of conditions and the following disclaimer in the
   15:  *    documentation and/or other materials provided with the distribution.
   16:  *
   17:  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
   18:  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
   19:  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
   20:  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
   21:  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
   22:  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
   23:  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
   24:  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
   25:  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
   26:  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
   27:  *
   28:  * $FreeBSD: src/sys/i386/isa/pci_cfgreg.c,v 1.1.2.7 2001/11/28 05:47:03 imp Exp $
   29:  * $DragonFly: src/sys/bus/pci/i386/pci_cfgreg.c,v 1.7 2004/02/08 07:10:46 hmp Exp $
   30:  *
   31:  */
   32: 
   33: #include <sys/param.h>		/* XXX trim includes */
   34: #include <sys/systm.h>
   35: #include <sys/bus.h>
   36: #include <sys/kernel.h>
   37: #include <sys/module.h>
   38: #include <sys/malloc.h>
   39: #include <sys/sysctl.h>
   40: #include <vm/vm.h>
   41: #include <vm/pmap.h>
   42: #include <machine/md_var.h>
   43: #include <machine/clock.h>
   44: #include <bus/pci/pcivar.h>
   45: #include <bus/pci/pcireg.h>
   46: #include <bus/isa/isavar.h>
   47: #include <bus/pci/i386/pci_cfgreg.h>
   48: #include <machine/segments.h>
   49: #include <machine/pc/bios.h>
   50: 
   51: #ifdef APIC_IO
   52: #include <machine/smp.h>
   53: #endif /* APIC_IO */
   54: 
   55: #define PRVERB(a) do {							\
   56: 	if (bootverbose)						\
   57: 		printf a ;						\
   58: } while(0)
   59: 
   60: static int pci_disable_bios_route = 0;
   61: SYSCTL_INT(_hw, OID_AUTO, pci_disable_bios_route, CTLFLAG_RD,
   62: 	&pci_disable_bios_route, 0, "disable interrupt routing via PCI-BIOS");
   63: TUNABLE_INT("hw.pci_disable_bios_route", &pci_disable_bios_route);
   64: 
   65: static int cfgmech;
   66: static int devmax;
   67: 
   68: static int	pci_cfgintr_valid(struct PIR_entry *pe, int pin, int irq);
   69: static int	pci_cfgintr_unique(struct PIR_entry *pe, int pin);
   70: static int	pci_cfgintr_linked(struct PIR_entry *pe, int pin);
   71: static int	pci_cfgintr_search(struct PIR_entry *pe, int bus, int device, int matchpin, int pin);
   72: static int	pci_cfgintr_virgin(struct PIR_entry *pe, int pin);
   73: 
   74: static void	pci_print_irqmask(u_int16_t irqs);
   75: static void	pci_print_route_table(struct PIR_table *prt, int size);
   76: static int	pcireg_cfgread(int bus, int slot, int func, int reg, int bytes);
   77: static void	pcireg_cfgwrite(int bus, int slot, int func, int reg, int data, int bytes);
   78: static int	pcireg_cfgopen(void);
   79: 
   80: static struct PIR_table	*pci_route_table;
   81: static int		pci_route_count;
   82: 
   83: /*
   84:  * Some BIOS writers seem to want to ignore the spec and put
   85:  * 0 in the intline rather than 255 to indicate none. Some use
   86:  * numbers in the range 128-254 to indicate something strange and
   87:  * apparently undocumented anywhere. Assume these are completely bogus
   88:  * and map them to 255, which means "none".
   89:  */
   90: static int
   91: pci_i386_map_intline(int line)
   92: {
   93: 	if (line == 0 || line >= 128)
   94: 		return (PCI_INVALID_IRQ);
   95: 	return (line);
   96: }
   97: 
   98: static u_int16_t
   99: pcibios_get_version(void)
  100: {
  101: 	struct bios_regs args;
  102: 
  103: 	if (PCIbios.ventry == 0) {
  104: 		PRVERB(("pcibios: No call entry point\n"));
  105: 		return (0);
  106: 	}
  107: 	args.eax = PCIBIOS_BIOS_PRESENT;
  108: 	if (bios32(&args, PCIbios.ventry, GSEL(GCODE_SEL, SEL_KPL))) {
  109: 		PRVERB(("pcibios: BIOS_PRESENT call failed\n"));
  110: 		return (0);
  111: 	}
  112: 	if (args.edx != 0x20494350) {
  113: 		PRVERB(("pcibios: BIOS_PRESENT didn't return 'PCI ' in edx\n"));
  114: 		return (0);
  115: 	}
  116: 	return (args.ebx & 0xffff);
  117: }
  118: 
  119: /* 
  120:  * Initialise access to PCI configuration space 
  121:  */
  122: int
  123: pci_cfgregopen(void)
  124: {
  125: 	static int		opened = 0;
  126: 	u_long			sigaddr;
  127: 	static struct PIR_table	*pt;
  128: 	u_int16_t		v;
  129: 	u_int8_t		ck, *cv;
  130: 	int			i;
  131: 
  132: 	if (opened)
  133: 		return (1);
  134: 
  135: 	if (pcireg_cfgopen() == 0)
  136: 		return (0);
  137: 
  138: 	v = pcibios_get_version();
  139: 	if (v > 0)
  140: 		printf("pcibios: BIOS version %x.%02x\n", (v & 0xff00) >> 8,
  141: 		       v & 0xff);
  142: 
  143: 	/*
  144: 	 * Look for the interrupt routing table.
  145: 	 *
  146: 	 * We use PCI BIOS's PIR table if it's available $PIR is the
  147: 	 * standard way to do this.  Sadly some machines are not
  148: 	 * standards conforming and have _PIR instead. We shrug and cope
  149: 	 * by looking for both.
  150: 	 */
  151: 	if (pcibios_get_version() >= 0x0210 && pt == NULL) {
  152: 		sigaddr = bios_sigsearch(0, "$PIR", 4, 16, 0);
  153: 		if (sigaddr == 0)
  154: 			sigaddr = bios_sigsearch(0, "_PIR", 4, 16, 0);
  155: 		if (sigaddr != 0) {
  156: 			pt = (struct PIR_table *)(uintptr_t)
  157: 			     BIOS_PADDRTOVADDR(sigaddr);
  158: 			for (cv = (u_int8_t *)pt, ck = 0, i = 0;
  159: 			     i < (pt->pt_header.ph_length); i++)
  160: 				ck += cv[i];
  161: 			if (ck == 0 && pt->pt_header.ph_length >
  162: 			    sizeof(struct PIR_header)) {
  163: 				pci_route_table = pt;
  164: 				pci_route_count = (pt->pt_header.ph_length -
  165: 				    sizeof(struct PIR_header)) /
  166: 				    sizeof(struct PIR_entry);
  167: 				printf("Using $PIR table, %d entries at %p\n",
  168: 				       pci_route_count, pci_route_table);
  169: 				if (bootverbose)
  170: 					pci_print_route_table(pci_route_table,
  171: 					    pci_route_count);
  172: 			}
  173: 		}
  174: 	}
  175: 	opened = 1;
  176: 	return (1);	
  177: }
  178: 
  179: /* 
  180:  * Read configuration space register
  181:  */
  182: u_int32_t
  183: pci_cfgregread(int bus, int slot, int func, int reg, int bytes)
  184: {
  185: 	uint32_t line;
  186: #ifdef APIC_IO
  187: 	uint32_t pin;
  188: 
  189: 	/*
  190: 	 * If we are using the APIC, the contents of the intline
  191: 	 * register will probably be wrong (since they are set up for
  192: 	 * use with the PIC.  Rather than rewrite these registers
  193: 	 * (maybe that would be smarter) we trap attempts to read them
  194: 	 * and translate to our private vector numbers.
  195: 	 */
  196: 	if ((reg == PCIR_INTLINE) && (bytes == 1)) {
  197: 
  198: 		pin = pcireg_cfgread(bus, slot, func, PCIR_INTPIN, 1);
  199: 		line = pcireg_cfgread(bus, slot, func, PCIR_INTLINE, 1);
  200: 
  201: 		if (pin != 0) {
  202: 			int airq;
  203: 
  204: 			airq = pci_apic_irq(bus, slot, pin);
  205: 			if (airq >= 0) {
  206: 				/* PCI specific entry found in MP table */
  207: 				if (airq != line)
  208: 					undirect_pci_irq(line);
  209: 				return (airq);
  210: 			} else {
  211: 				/* 
  212: 			 	 * PCI interrupts might be redirected to the
  213: 				 * ISA bus according to some MP tables. Use the
  214: 				 * same methods as used by the ISA devices
  215: 				 * devices to find the proper IOAPIC int pin.
  216: 				 */
  217: 				airq = isa_apic_irq(line);
  218: 				if ((airq >= 0) && (airq != line)) {
  219: 					/* XXX: undirect_pci_irq() ? */
  220: 					undirect_isa_irq(line);
  221: 					return (airq);
  222: 				}
  223: 			}
  224: 		}
  225: 		return (line);
  226:     	}
  227: #else
  228: 	/*
  229: 	 * Some BIOS writers seem to want to ignore the spec and put
  230: 	 * 0 in the intline rather than 255 to indicate none.  The rest of
  231: 	 * the code uses 255 as an invalid IRQ.
  232: 	 */
  233: 	if (reg == PCIR_INTLINE && bytes == 1) {
  234: 		line = pcireg_cfgread(bus, slot, func, PCIR_INTLINE, 1);
  235: 		return pci_i386_map_intline(line);
  236: 	}
  237: #endif /* APIC_IO */
  238: 	return (pcireg_cfgread(bus, slot, func, reg, bytes));
  239: }
  240: 
  241: /* 
  242:  * Write configuration space register 
  243:  */
  244: void
  245: pci_cfgregwrite(int bus, int slot, int func, int reg, u_int32_t data, int bytes)
  246: {
  247: 	pcireg_cfgwrite(bus, slot, func, reg, data, bytes);
  248: }
  249: 
  250: int
  251: pci_cfgread(pcicfgregs *cfg, int reg, int bytes)
  252: {
  253: 	return (pci_cfgregread(cfg->bus, cfg->slot, cfg->func, reg, bytes));
  254: }
  255: 
  256: void
  257: pci_cfgwrite(pcicfgregs *cfg, int reg, int data, int bytes)
  258: {
  259: 	pci_cfgregwrite(cfg->bus, cfg->slot, cfg->func, reg, data, bytes);
  260: }
  261: 
  262: 
  263: /*
  264:  * Route a PCI interrupt
  265:  */
  266: int
  267: pci_cfgintr(int bus, int device, int pin, int oldirq)
  268: {
  269: 	struct PIR_entry	*pe;
  270: 	int			i, irq;
  271: 	struct bios_regs	args;
  272: 	u_int16_t		v;
  273: 
  274: 	int already = 0;
  275: 	int errok = 0;
  276:     
  277: 	v = pcibios_get_version();
  278: 	if (v < 0x0210) {
  279: 		PRVERB((
  280: 		  "pci_cfgintr: BIOS %x.%02x doesn't support interrupt routing\n",
  281: 		  (v & 0xff00) >> 8, v & 0xff));
  282: 		return (PCI_INVALID_IRQ);
  283: 	}
  284: 	if ((bus < 0) || (bus > 255) || (device < 0) || (device > 255) ||
  285: 	    (pin < 1) || (pin > 4))
  286: 		return (PCI_INVALID_IRQ);
  287: 
  288: 	/*
  289: 	 * Scan the entry table for a contender
  290: 	 */
  291: 	for (i = 0, pe = &pci_route_table->pt_entry[0]; i < pci_route_count;
  292: 	     i++, pe++) {
  293: 		if ((bus != pe->pe_bus) || (device != pe->pe_device))
  294: 			continue;
  295: 
  296: 		/*
  297: 		 * A link of 0 means that this intpin is not connected to
  298: 		 * any other device's interrupt pins and is not connected to
  299: 		 * any of the Interrupt Router's interrupt pins, so we can't
  300: 		 * route it.
  301: 		 */
  302: 		if (pe->pe_intpin[pin - 1].link == 0)
  303: 			continue;
  304: 
  305: 		if (pci_cfgintr_valid(pe, pin, oldirq)) {
  306: 			printf("pci_cfgintr: %d:%d INT%c BIOS irq %d\n", bus,
  307: 			       device, 'A' + pin - 1, oldirq);
  308: 			return (oldirq);
  309: 		}
  310: 
  311: 		/*
  312: 		 * We try to find a linked interrupt, then we look to see
  313: 		 * if the interrupt is uniquely routed, then we look for
  314: 		 * a virgin interrupt. The virgin interrupt should return
  315: 		 * an interrupt we can route, but if that fails, maybe we
  316: 		 * should try harder to route a different interrupt.
  317: 		 * However, experience has shown that that's rarely the
  318: 		 * failure mode we see.
  319: 		 */
  320: 		irq = pci_cfgintr_linked(pe, pin);
  321: 		if (irq != PCI_INVALID_IRQ)
  322: 			already = 1;
  323: 		if (irq == PCI_INVALID_IRQ) {
  324: 			irq = pci_cfgintr_unique(pe, pin);
  325: 			if (irq != PCI_INVALID_IRQ)
  326: 				errok = 1;
  327: 		}
  328: 		if (irq == PCI_INVALID_IRQ)
  329: 			irq = pci_cfgintr_virgin(pe, pin);
  330: 
  331: 		if (irq == PCI_INVALID_IRQ)
  332: 			break;
  333: 
  334: 		if (pci_disable_bios_route != 0)
  335: 			break;
  336: 		/*
  337: 		 * Ask the BIOS to route the interrupt. If we picked an
  338: 		 * interrupt that failed, we should really try other
  339: 		 * choices that the BIOS offers us.
  340: 		 *
  341: 		 * For uniquely routed interrupts, we need to try
  342: 		 * to route them on some machines. Yet other machines
  343: 		 * fail to route, so we have to pretend that in that
  344: 		 * case it worked.  Isn't PC hardware fun?
  345: 		 *
  346: 		 * NOTE: if we want to whack hardware to do this, then
  347: 		 * I think the right way to do that would be to have
  348: 		 * bridge drivers that do this. I'm not sure that the
  349: 		 * $PIR table would be valid for those interrupt
  350: 		 * routers.
  351: 		 */
  352: 		args.eax = PCIBIOS_ROUTE_INTERRUPT;
  353: 		args.ebx = (bus << 8) | (device << 3);
  354: 		/* pin value is 0xa - 0xd */
  355: 		args.ecx = (irq << 8) | (0xa + pin -1);
  356: 		if (!already &&
  357: 		    bios32(&args, PCIbios.ventry, GSEL(GCODE_SEL, SEL_KPL)) &&
  358: 		    !errok) {
  359: 			PRVERB(("pci_cfgintr: ROUTE_INTERRUPT failed.\n"));
  360: 			return (PCI_INVALID_IRQ);
  361: 		}
  362: 		printf("pci_cfgintr: %d:%d INT%c routed to irq %d\n", bus,
  363: 		       device, 'A' + pin - 1, irq);
  364: 		return(irq);
  365: 	}
  366: 
  367: 	PRVERB(("pci_cfgintr: can't route an interrupt to %d:%d INT%c\n", bus,
  368: 	       device, 'A' + pin - 1));
  369: 	return (PCI_INVALID_IRQ);
  370: }
  371: 
  372: /*
  373:  * Check to see if an existing IRQ setting is valid.
  374:  */
  375: static int
  376: pci_cfgintr_valid(struct PIR_entry *pe, int pin, int irq)
  377: {
  378: 	uint32_t irqmask;
  379: 
  380: 	if (!PCI_INTERRUPT_VALID(irq))
  381: 		return (0);
  382: 	irqmask = pe->pe_intpin[pin - 1].irqs;
  383: 	if (irqmask & (1 << irq)) {
  384: 		PRVERB(("pci_cfgintr_valid: BIOS irq %d is valid\n", irq));
  385: 		return (1);
  386: 	}
  387: 	return (0);
  388: }
  389: 
  390: /*
  391:  * Look to see if the routing table claims this pin is uniquely routed.
  392:  */
  393: static int
  394: pci_cfgintr_unique(struct PIR_entry *pe, int pin)
  395: {
  396: 	int		irq;
  397: 	uint32_t	irqmask;
  398: 
  399: 	irqmask = pe->pe_intpin[pin - 1].irqs;
  400: 	if(irqmask != 0 && powerof2(irqmask)) {
  401: 		irq = ffs(irqmask) - 1;
  402: 		PRVERB(("pci_cfgintr_unique: hard-routed to irq %d\n", irq));
  403: 		return (irq);
  404: 	}
  405: 	return (PCI_INVALID_IRQ);
  406: }
  407: 
  408: /*
  409:  * Look for another device which shares the same link byte and
  410:  * already has a unique IRQ, or which has had one routed already.
  411:  */
  412: static int
  413: pci_cfgintr_linked(struct PIR_entry *pe, int pin)
  414: {
  415: 	struct PIR_entry	*oe;
  416: 	struct PIR_intpin	*pi;
  417: 	int			i, j, irq;
  418: 
  419: 	/*
  420: 	 * Scan table slots.
  421: 	 */
  422: 	for (i = 0, oe = &pci_route_table->pt_entry[0]; i < pci_route_count;
  423: 	     i++, oe++) {
  424: 		/* scan interrupt pins */
  425: 		for (j = 0, pi = &oe->pe_intpin[0]; j < 4; j++, pi++) {
  426: 
  427: 			/* don't look at the entry we're trying to match */
  428: 			if ((pe == oe) && (i == (pin - 1)))
  429: 				continue;
  430: 			/* compare link bytes */
  431: 			if (pi->link != pe->pe_intpin[pin - 1].link)
  432: 				continue;
  433: 			/* link destination mapped to a unique interrupt? */
  434: 			if (pi->irqs != 0 && powerof2(pi->irqs)) {
  435: 				irq = ffs(pi->irqs) - 1;
  436: 				PRVERB(("pci_cfgintr_linked: linked (%x) to hard-routed irq %d\n",
  437: 				       pi->link, irq));
  438: 				return(irq);
  439: 			} 
  440: 
  441: 			/*
  442: 			 * look for the real PCI device that matches this
  443: 			 * table entry
  444: 			 */
  445: 			irq = pci_cfgintr_search(pe, oe->pe_bus, oe->pe_device,
  446: 						 j, pin);
  447: 			if (irq != PCI_INVALID_IRQ)
  448: 				return (irq);
  449: 		}
  450: 	}
  451: 	return (PCI_INVALID_IRQ);
  452: }
  453: 
  454: /*
  455:  * Scan for the real PCI device at (bus)/(device) using intpin (matchpin) and
  456:  * see if it has already been assigned an interrupt.
  457:  */
  458: static int
  459: pci_cfgintr_search(struct PIR_entry *pe, int bus, int device, int matchpin, int pin)
  460: {
  461: 	devclass_t		pci_devclass;
  462: 	device_t		*pci_devices;
  463: 	int			pci_count;
  464: 	device_t		*pci_children;
  465: 	int			pci_childcount;
  466: 	device_t		*busp, *childp;
  467: 	int			i, j, irq;
  468: 
  469: 	/*
  470: 	 * Find all the PCI busses.
  471: 	 */
  472: 	pci_count = 0;
  473: 	if ((pci_devclass = devclass_find("pci")) != NULL)
  474: 		devclass_get_devices(pci_devclass, &pci_devices, &pci_count);
  475: 
  476: 	/*
  477: 	 * Scan all the PCI busses/devices looking for this one.
  478: 	 */
  479: 	irq = PCI_INVALID_IRQ;
  480: 	for (i = 0, busp = pci_devices; (i < pci_count) && (irq == PCI_INVALID_IRQ);
  481: 	     i++, busp++) {
  482: 		pci_childcount = 0;
  483: 		device_get_children(*busp, &pci_children, &pci_childcount);
  484: 		
  485: 		for (j = 0, childp = pci_children; j < pci_childcount; j++,
  486: 		     childp++) {
  487: 			if ((pci_get_bus(*childp) == bus) &&
  488: 			    (pci_get_slot(*childp) == device) &&
  489: 			    (pci_get_intpin(*childp) == matchpin)) {
  490: 				irq = pci_i386_map_intline(pci_get_irq(*childp));
  491: 				if (irq != PCI_INVALID_IRQ)
  492: 					PRVERB(("pci_cfgintr_search: linked (%x) to configured irq %d at %d:%d:%d\n",
  493: 					    pe->pe_intpin[pin - 1].link, irq,
  494: 					    pci_get_bus(*childp),
  495: 					    pci_get_slot(*childp),
  496: 					    pci_get_function(*childp)));
  497: 				break;
  498: 			}
  499: 		}
  500: 		if (pci_children != NULL)
  501: 			free(pci_children, M_TEMP);
  502: 	}
  503: 	if (pci_devices != NULL)
  504: 		free(pci_devices, M_TEMP);
  505: 	return (irq);
  506: }
  507: 
  508: /*
  509:  * Pick a suitable IRQ from those listed as routable to this device.
  510:  */
  511: static int
  512: pci_cfgintr_virgin(struct PIR_entry *pe, int pin)
  513: {
  514: 	int irq, ibit;
  515:     
  516: 	/*
  517: 	 * first scan the set of PCI-only interrupts and see if any of these
  518: 	 * are routable
  519: 	 */
  520: 	for (irq = 0; irq < 16; irq++) {
  521: 		ibit = (1 << irq);
  522: 
  523: 		/* can we use this interrupt? */
  524: 		if ((pci_route_table->pt_header.ph_pci_irqs & ibit) &&
  525: 		    (pe->pe_intpin[pin - 1].irqs & ibit)) {
  526: 			PRVERB(("pci_cfgintr_virgin: using routable PCI-only interrupt %d\n", irq));
  527: 			return (irq);
  528: 		}
  529: 	}
  530:     
  531: 	/* life is tough, so just pick an interrupt */
  532: 	for (irq = 0; irq < 16; irq++) {
  533: 		ibit = (1 << irq);
  534:     
  535: 		if (pe->pe_intpin[pin - 1].irqs & ibit) {
  536: 			PRVERB(("pci_cfgintr_virgin: using routable interrupt %d\n", irq));
  537: 			return (irq);
  538: 		}
  539: 	}
  540: 	return (PCI_INVALID_IRQ);
  541: }
  542: 
  543: static void
  544: pci_print_irqmask(u_int16_t irqs)
  545: {
  546: 	int i, first;
  547: 
  548: 	if (irqs == 0) {
  549: 		printf("none");
  550: 		return;
  551: 	}
  552: 	first = 1;
  553: 	for (i = 0; i < 16; i++, irqs >>= 1)
  554: 		if (irqs & 1) {
  555: 			if (!first)
  556: 				printf(" ");
  557: 			else
  558: 				first = 0;
  559: 			printf("%d", i);
  560: 		}
  561: }
  562: 
  563: /*
  564:  * Dump the contents of a PCI BIOS Interrupt Routing Table to the console.
  565:  */
  566: static void
  567: pci_print_route_table(struct PIR_table *ptr, int size)
  568: {
  569: 	struct PIR_entry *entry;
  570: 	struct PIR_intpin *intpin;
  571: 	int i, pin;
  572: 
  573: 	printf("PCI-Only Interrupts: ");
  574: 	pci_print_irqmask(ptr->pt_header.ph_pci_irqs);
  575: 	printf("\nLocation  Bus Device Pin  Link  IRQs\n");
  576: 	entry = &ptr->pt_entry[0];
  577: 	for (i = 0; i < size; i++, entry++) {
  578: 		intpin = &entry->pe_intpin[0];
  579: 		for (pin = 0; pin < 4; pin++, intpin++)
  580: 			if (intpin->link != 0) {
  581: 				if (entry->pe_slot == 0)
  582: 					printf("embedded ");
  583: 				else
  584: 					printf("slot %-3d ", entry->pe_slot);
  585: 				printf(" %3d  %3d    %c   0x%02x  ",
  586: 				       entry->pe_bus, entry->pe_device,
  587: 				       'A' + pin, intpin->link);
  588: 				pci_print_irqmask(intpin->irqs);
  589: 				printf("\n");
  590: 			}
  591: 	}
  592: }
  593: 
  594: /*
  595:  * See if any interrupts for a given PCI bus are routed in the PIR.  Don't
  596:  * even bother looking if the BIOS doesn't support routing anyways.
  597:  */
  598: int
  599: pci_probe_route_table(int bus)
  600: {
  601: 	int i;
  602: 	u_int16_t v;
  603: 
  604: 	v = pcibios_get_version();
  605: 	if (v < 0x0210)
  606: 		return (0);
  607: 	for (i = 0; i < pci_route_count; i++)
  608: 		if (pci_route_table->pt_entry[i].pe_bus == bus)
  609: 			return (1);
  610: 	return (0);
  611: }
  612: 
  613: /* 
  614:  * Configuration space access using direct register operations
  615:  */
  616: 
  617: /* enable configuration space accesses and return data port address */
  618: static int
  619: pci_cfgenable(unsigned bus, unsigned slot, unsigned func, int reg, int bytes)
  620: {
  621: 	int dataport = 0;
  622: 
  623: 	if (bus <= PCI_BUSMAX
  624: 	    && slot < devmax
  625: 	    && func <= PCI_FUNCMAX
  626: 	    && reg <= PCI_REGMAX
  627: 	    && bytes != 3
  628: 	    && (unsigned) bytes <= 4
  629: 	    && (reg & (bytes - 1)) == 0) {
  630: 		switch (cfgmech) {
  631: 		case 1:
  632: 			outl(CONF1_ADDR_PORT, (1 << 31)
  633: 			     | (bus << 16) | (slot << 11) 
  634: 			     | (func << 8) | (reg & ~0x03));
  635: 			dataport = CONF1_DATA_PORT + (reg & 0x03);
  636: 			break;
  637: 		case 2:
  638: 			outb(CONF2_ENABLE_PORT, 0xf0 | (func << 1));
  639: 			outb(CONF2_FORWARD_PORT, bus);
  640: 			dataport = 0xc000 | (slot << 8) | reg;
  641: 			break;
  642: 		}
  643: 	}
  644: 	return (dataport);
  645: }
  646: 
  647: /* disable configuration space accesses */
  648: static void
  649: pci_cfgdisable(void)
  650: {
  651: 	switch (cfgmech) {
  652: 	case 1:
  653: 		outl(CONF1_ADDR_PORT, 0);
  654: 		break;
  655: 	case 2:
  656: 		outb(CONF2_ENABLE_PORT, 0);
  657: 		outb(CONF2_FORWARD_PORT, 0);
  658: 		break;
  659: 	}
  660: }
  661: 
  662: static int
  663: pcireg_cfgread(int bus, int slot, int func, int reg, int bytes)
  664: {
  665: 	int data = -1;
  666: 	int port;
  667: 
  668: 	port = pci_cfgenable(bus, slot, func, reg, bytes);
  669: 	if (port != 0) {
  670: 		switch (bytes) {
  671: 		case 1:
  672: 			data = inb(port);
  673: 			break;
  674: 		case 2:
  675: 			data = inw(port);
  676: 			break;
  677: 		case 4:
  678: 			data = inl(port);
  679: 			break;
  680: 		}
  681: 		pci_cfgdisable();
  682: 	}
  683: 	return (data);
  684: }
  685: 
  686: static void
  687: pcireg_cfgwrite(int bus, int slot, int func, int reg, int data, int bytes)
  688: {
  689: 	int port;
  690: 
  691: 	port = pci_cfgenable(bus, slot, func, reg, bytes);
  692: 	if (port != 0) {
  693: 		switch (bytes) {
  694: 		case 1:
  695: 			outb(port, data);
  696: 			break;
  697: 		case 2:
  698: 			outw(port, data);
  699: 			break;
  700: 		case 4:
  701: 			outl(port, data);
  702: 			break;
  703: 		}
  704: 		pci_cfgdisable();
  705: 	}
  706: }
  707: 
  708: /* check whether the configuration mechanism has been correctly identified */
  709: static int
  710: pci_cfgcheck(int maxdev)
  711: {
  712: 	uint32_t id, class;
  713: 	uint8_t header;
  714: 	uint8_t device;
  715: 	int port;
  716: 
  717: 	if (bootverbose) 
  718: 		printf("pci_cfgcheck:\tdevice ");
  719: 
  720: 	for (device = 0; device < maxdev; device++) {
  721: 		if (bootverbose) 
  722: 			printf("%d ", device);
  723: 
  724: 		port = pci_cfgenable(0, device, 0, 0, 4);
  725: 		id = inl(port);
  726: 		if (id == 0 || id == 0xffffffff)
  727: 			continue;
  728: 
  729: 		port = pci_cfgenable(0, device, 0, 8, 4);
  730: 		class = inl(port) >> 8;
  731: 		if (bootverbose)
  732: 			printf("[class=%06x] ", class);
  733: 		if (class == 0 || (class & 0xf870ff) != 0)
  734: 			continue;
  735: 
  736: 		port = pci_cfgenable(0, device, 0, 14, 1);
  737: 		header = inb(port);
  738: 		if (bootverbose)
  739: 			printf("[hdr=%02x] ", header);
  740: 		if ((header & 0x7e) != 0)
  741: 			continue;
  742: 
  743: 		if (bootverbose)
  744: 			printf("is there (id=%08x)\n", id);
  745: 
  746: 		pci_cfgdisable();
  747: 		return (1);
  748: 	}
  749: 	if (bootverbose) 
  750: 		printf("-- nothing found\n");
  751: 
  752: 	pci_cfgdisable();
  753: 	return (0);
  754: }
  755: 
  756: static int
  757: pcireg_cfgopen(void)
  758: {
  759: 	uint32_t mode1res,oldval1;
  760: 	uint8_t mode2res,oldval2;
  761: 
  762: 	oldval1 = inl(CONF1_ADDR_PORT);
  763: 
  764: 	if (bootverbose) {
  765: 		printf("pci_open(1):\tmode 1 addr port (0x0cf8) is 0x%08x\n",
  766: 		       oldval1);
  767: 	}
  768: 
  769: 	if ((oldval1 & CONF1_ENABLE_MSK) == 0) {
  770: 
  771: 		cfgmech = 1;
  772: 		devmax = 32;
  773: 
  774: 		outl(CONF1_ADDR_PORT, CONF1_ENABLE_CHK);
  775: 		DELAY(1);
  776: 		mode1res = inl(CONF1_ADDR_PORT);
  777: 		outl(CONF1_ADDR_PORT, oldval1);
  778: 
  779: 		if (bootverbose)
  780: 			printf("pci_open(1a):\tmode1res=0x%08x (0x%08lx)\n", 
  781: 			       mode1res, CONF1_ENABLE_CHK);
  782: 
  783: 		if (mode1res) {
  784: 			if (pci_cfgcheck(32)) 
  785: 				return (cfgmech);
  786: 		}
  787: 
  788: 		outl(CONF1_ADDR_PORT, CONF1_ENABLE_CHK1);
  789: 		mode1res = inl(CONF1_ADDR_PORT);
  790: 		outl(CONF1_ADDR_PORT, oldval1);
  791: 
  792: 		if (bootverbose)
  793: 			printf("pci_open(1b):\tmode1res=0x%08x (0x%08lx)\n", 
  794: 			       mode1res, CONF1_ENABLE_CHK1);
  795: 
  796: 		if ((mode1res & CONF1_ENABLE_MSK1) == CONF1_ENABLE_RES1) {
  797: 			if (pci_cfgcheck(32)) 
  798: 				return (cfgmech);
  799: 		}
  800: 	}
  801: 
  802: 	oldval2 = inb(CONF2_ENABLE_PORT);
  803: 
  804: 	if (bootverbose) {
  805: 		printf("pci_open(2):\tmode 2 enable port (0x0cf8) is 0x%02x\n",
  806: 		       oldval2);
  807: 	}
  808: 
  809: 	if ((oldval2 & 0xf0) == 0) {
  810: 
  811: 		cfgmech = 2;
  812: 		devmax = 16;
  813: 
  814: 		outb(CONF2_ENABLE_PORT, CONF2_ENABLE_CHK);
  815: 		mode2res = inb(CONF2_ENABLE_PORT);
  816: 		outb(CONF2_ENABLE_PORT, oldval2);
  817: 
  818: 		if (bootverbose)
  819: 			printf("pci_open(2a):\tmode2res=0x%02x (0x%02x)\n", 
  820: 			       mode2res, CONF2_ENABLE_CHK);
  821: 
  822: 		if (mode2res == CONF2_ENABLE_RES) {
  823: 			if (bootverbose)
  824: 				printf("pci_open(2a):\tnow trying mechanism 2\n");
  825: 
  826: 			if (pci_cfgcheck(16)) 
  827: 				return (cfgmech);
  828: 		}
  829: 	}
  830: 
  831: 	cfgmech = 0;
  832: 	devmax = 0;
  833: 	return (cfgmech);
  834: }