Home | History | Annotate | Line # | Download | only in pci
pci_machdep.c revision 1.10
      1 /*	$NetBSD: pci_machdep.c,v 1.10 2000/02/03 19:27:46 tsubai Exp $	*/
      2 
      3 /*
      4  * Copyright (c) 1996 Christopher G. Demetriou.  All rights reserved.
      5  * Copyright (c) 1994 Charles M. Hannum.  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, this list of conditions and the following disclaimer.
     12  * 2. Redistributions in binary form must reproduce the above copyright
     13  *    notice, this list of conditions and the following disclaimer in the
     14  *    documentation and/or other materials provided with the distribution.
     15  * 3. All advertising materials mentioning features or use of this software
     16  *    must display the following acknowledgement:
     17  *	This product includes software developed by Charles M. Hannum.
     18  * 4. The name of the author may not be used to endorse or promote products
     19  *    derived from this software without specific prior written permission.
     20  *
     21  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
     22  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
     23  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
     24  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
     25  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
     26  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
     27  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
     28  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
     29  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
     30  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
     31  */
     32 
     33 /*
     34  * Machine-specific functions for PCI autoconfiguration.
     35  *
     36  * On PCs, there are two methods of generating PCI configuration cycles.
     37  * We try to detect the appropriate mechanism for this machine and set
     38  * up a few function pointers to access the correct method directly.
     39  *
     40  * The configuration method can be hard-coded in the config file by
     41  * using `options PCI_CONF_MODE=N', where `N' is the configuration mode
     42  * as defined section 3.6.4.1, `Generating Configuration Cycles'.
     43  */
     44 
     45 #include <sys/types.h>
     46 #include <sys/param.h>
     47 #include <sys/time.h>
     48 #include <sys/systm.h>
     49 #include <sys/errno.h>
     50 #include <sys/device.h>
     51 
     52 #include <vm/vm.h>
     53 #include <vm/vm_kern.h>
     54 
     55 #define _MACPPC_BUS_DMA_PRIVATE
     56 #include <machine/bus.h>
     57 
     58 #include <machine/bus.h>
     59 #include <machine/pio.h>
     60 #include <machine/intr.h>
     61 
     62 #include <dev/pci/pcivar.h>
     63 #include <dev/pci/pcireg.h>
     64 
     65 #include <dev/ofw/openfirm.h>
     66 #include <dev/ofw/ofw_pci.h>
     67 
     68 static void fixpci __P((int, pci_chipset_tag_t));
     69 static int find_node_intr __P((int, u_int32_t *, u_int32_t *));
     70 
     71 /*
     72  * PCI doesn't have any special needs; just use the generic versions
     73  * of these functions.
     74  */
     75 struct macppc_bus_dma_tag pci_bus_dma_tag = {
     76 	0,			/* _bounce_thresh */
     77 	_bus_dmamap_create,
     78 	_bus_dmamap_destroy,
     79 	_bus_dmamap_load,
     80 	_bus_dmamap_load_mbuf,
     81 	_bus_dmamap_load_uio,
     82 	_bus_dmamap_load_raw,
     83 	_bus_dmamap_unload,
     84 	NULL,			/* _dmamap_sync */
     85 	_bus_dmamem_alloc,
     86 	_bus_dmamem_free,
     87 	_bus_dmamem_map,
     88 	_bus_dmamem_unmap,
     89 	_bus_dmamem_mmap,
     90 };
     91 
     92 void
     93 pci_attach_hook(parent, self, pba)
     94 	struct device *parent, *self;
     95 	struct pcibus_attach_args *pba;
     96 {
     97 	pci_chipset_tag_t pc = pba->pba_pc;
     98 	int bus = pba->pba_bus;
     99 	int node, nn, sz;
    100 	int32_t busrange[2];
    101 
    102 	for (node = pc->node; node; node = nn) {
    103 		sz = OF_getprop(node, "bus-range", busrange, 8);
    104 		if (sz == 8 && busrange[0] == bus) {
    105 			fixpci(node, pc);
    106 			return;
    107 		}
    108 		if ((nn = OF_child(node)) != 0)
    109 			continue;
    110 		while ((nn = OF_peer(node)) == 0) {
    111 			node = OF_parent(node);
    112 			if (node == pc->node)
    113 				return;		/* not found */
    114 		}
    115 	}
    116 }
    117 
    118 int
    119 pci_bus_maxdevs(pc, busno)
    120 	pci_chipset_tag_t pc;
    121 	int busno;
    122 {
    123 
    124 	/*
    125 	 * Bus number is irrelevant.  Configuration Mechanism 1 is in
    126 	 * use, can have devices 0-32 (i.e. the `normal' range).
    127 	 */
    128 	return 32;
    129 }
    130 
    131 pcitag_t
    132 pci_make_tag(pc, bus, device, function)
    133 	pci_chipset_tag_t pc;
    134 	int bus, device, function;
    135 {
    136 	pcitag_t tag;
    137 
    138 	if (bus >= 256 || device >= 32 || function >= 8)
    139 		panic("pci_make_tag: bad request");
    140 
    141 	/* XXX magic number */
    142 	tag = 0x80000000 | (bus << 16) | (device << 11) | (function << 8);
    143 
    144 	return tag;
    145 }
    146 
    147 void
    148 pci_decompose_tag(pc, tag, bp, dp, fp)
    149 	pci_chipset_tag_t pc;
    150 	pcitag_t tag;
    151 	int *bp, *dp, *fp;
    152 {
    153 
    154 	if (bp != NULL)
    155 		*bp = (tag >> 16) & 0xff;
    156 	if (dp != NULL)
    157 		*dp = (tag >> 11) & 0x1f;
    158 	if (fp != NULL)
    159 		*fp = (tag >> 8) & 0x07;
    160 }
    161 
    162 pcireg_t
    163 pci_conf_read(pc, tag, reg)
    164 	pci_chipset_tag_t pc;
    165 	pcitag_t tag;
    166 	int reg;
    167 {
    168 
    169 	return (*pc->conf_read)(pc, tag, reg);
    170 }
    171 
    172 void
    173 pci_conf_write(pc, tag, reg, data)
    174 	pci_chipset_tag_t pc;
    175 	pcitag_t tag;
    176 	int reg;
    177 	pcireg_t data;
    178 {
    179 
    180 	(*pc->conf_write)(pc, tag, reg, data);
    181 }
    182 
    183 int
    184 pci_intr_map(pc, intrtag, pin, line, ihp)
    185 	pci_chipset_tag_t pc;
    186 	pcitag_t intrtag;
    187 	int pin, line;
    188 	pci_intr_handle_t *ihp;
    189 {
    190 
    191 	if (pin == 0) {
    192 		/* No IRQ used. */
    193 		goto bad;
    194 	}
    195 
    196 	if (pin > 4) {
    197 		printf("pci_intr_map: bad interrupt pin %d\n", pin);
    198 		goto bad;
    199 	}
    200 
    201 	/*
    202 	 * Section 6.2.4, `Miscellaneous Functions', says that 255 means
    203 	 * `unknown' or `no connection' on a PC.  We assume that a device with
    204 	 * `no connection' either doesn't have an interrupt (in which case the
    205 	 * pin number should be 0, and would have been noticed above), or
    206 	 * wasn't configured by the BIOS (in which case we punt, since there's
    207 	 * no real way we can know how the interrupt lines are mapped in the
    208 	 * hardware).
    209 	 *
    210 	 * XXX
    211 	 * Since IRQ 0 is only used by the clock, and we can't actually be sure
    212 	 * that the BIOS did its job, we also recognize that as meaning that
    213 	 * the BIOS has not configured the device.
    214 	 */
    215 	if (line == 0 || line == 255) {
    216 		printf("pci_intr_map: no mapping for pin %c\n", '@' + pin);
    217 		goto bad;
    218 	} else {
    219 		if (line >= ICU_LEN) {
    220 			printf("pci_intr_map: bad interrupt line %d\n", line);
    221 			goto bad;
    222 		}
    223 	}
    224 
    225 	*ihp = line;
    226 	return 0;
    227 
    228 bad:
    229 	*ihp = -1;
    230 	return 1;
    231 }
    232 
    233 const char *
    234 pci_intr_string(pc, ih)
    235 	pci_chipset_tag_t pc;
    236 	pci_intr_handle_t ih;
    237 {
    238 	static char irqstr[8];		/* 4 + 2 + NULL + sanity */
    239 
    240 	if (ih == 0 || ih >= ICU_LEN)
    241 		panic("pci_intr_string: bogus handle 0x%x\n", ih);
    242 
    243 	sprintf(irqstr, "irq %d", ih);
    244 	return (irqstr);
    245 
    246 }
    247 
    248 extern void * intr_establish();
    249 extern void intr_disestablish();
    250 
    251 void *
    252 pci_intr_establish(pc, ih, level, func, arg)
    253 	pci_chipset_tag_t pc;
    254 	pci_intr_handle_t ih;
    255 	int level, (*func) __P((void *));
    256 	void *arg;
    257 {
    258 
    259 	if (ih == 0 || ih >= ICU_LEN)
    260 		panic("pci_intr_establish: bogus handle 0x%x\n", ih);
    261 
    262 	return intr_establish(ih, IST_LEVEL, level, func, arg);
    263 }
    264 
    265 void
    266 pci_intr_disestablish(pc, cookie)
    267 	pci_chipset_tag_t pc;
    268 	void *cookie;
    269 {
    270 
    271 	intr_disestablish(cookie);
    272 }
    273 
    274 #define pcibus(x) \
    275 	(((x) & OFW_PCI_PHYS_HI_BUSMASK) >> OFW_PCI_PHYS_HI_BUSSHIFT)
    276 #define pcidev(x) \
    277 	(((x) & OFW_PCI_PHYS_HI_DEVICEMASK) >> OFW_PCI_PHYS_HI_DEVICESHIFT)
    278 #define pcifunc(x) \
    279 	(((x) & OFW_PCI_PHYS_HI_FUNCTIONMASK) >> OFW_PCI_PHYS_HI_FUNCTIONSHIFT)
    280 
    281 void
    282 fixpci(parent, pc)
    283 	int parent;
    284 	pci_chipset_tag_t pc;
    285 {
    286 	int node;
    287 	pcitag_t tag;
    288 	pcireg_t csr, intr;
    289 	int len, i;
    290 	int32_t irqs[4];
    291 	struct {
    292 		u_int32_t phys_hi, phys_mid, phys_lo;
    293 		u_int32_t size_hi, size_lo;
    294 	} addr[8];
    295 
    296 	for (node = OF_child(parent); node; node = OF_peer(node)) {
    297 		len = OF_getprop(node, "assigned-addresses", addr,
    298 				 sizeof(addr));
    299 		if (len < (int)sizeof(addr[0]))
    300 			continue;
    301 
    302 		tag = pci_make_tag(pc, pcibus(addr[0].phys_hi),
    303 				   pcidev(addr[0].phys_hi),
    304 				   pcifunc(addr[0].phys_hi));
    305 
    306 		/*
    307 		 * Make sure the IO and MEM enable bits are set in the CSR.
    308 		 */
    309 		csr = pci_conf_read(pc, tag, PCI_COMMAND_STATUS_REG);
    310 		csr &= ~(PCI_COMMAND_IO_ENABLE | PCI_COMMAND_MEM_ENABLE);
    311 
    312 		for (i = 0; i < len / sizeof(addr[0]); i++) {
    313 			switch (addr[i].phys_hi & OFW_PCI_PHYS_HI_SPACEMASK) {
    314 			case OFW_PCI_PHYS_HI_SPACE_IO:
    315 				csr |= PCI_COMMAND_IO_ENABLE;
    316 				break;
    317 
    318 			case OFW_PCI_PHYS_HI_SPACE_MEM32:
    319 				csr |= PCI_COMMAND_MEM_ENABLE;
    320 				break;
    321 			}
    322 		}
    323 
    324 		pci_conf_write(pc, tag, PCI_COMMAND_STATUS_REG, csr);
    325 
    326 		/*
    327 		 * Make sure the line register is programmed with the
    328 		 * interrupt mapping.
    329 		 */
    330 		if (find_node_intr(node, &addr[0].phys_hi, irqs) == -1)
    331 			continue;
    332 
    333 		intr = pci_conf_read(pc, tag, PCI_INTERRUPT_REG);
    334 		intr &= ~PCI_INTERRUPT_LINE_MASK;
    335 		intr |= irqs[0] & PCI_INTERRUPT_LINE_MASK;
    336 		pci_conf_write(pc, tag, PCI_INTERRUPT_REG, intr);
    337 	}
    338 }
    339 
    340 /*
    341  * Find PCI IRQ of the node from OF tree.
    342  */
    343 int
    344 find_node_intr(node, addr, intr)
    345 	int node;
    346 	u_int32_t *addr, *intr;
    347 {
    348 	int parent, len, mlen, iparent;
    349 	int match, i;
    350 	u_int32_t map[64], *mp;
    351 	u_int32_t imask[8], maskedaddr[8];
    352 	u_int32_t icells;
    353 	char name[32];
    354 
    355 	len = OF_getprop(node, "AAPL,interrupts", intr, 4) ;
    356 	if (len == 4)
    357 		return len;
    358 
    359 	parent = OF_parent(node);
    360 	len = OF_getprop(parent, "interrupt-map", map, sizeof(map));
    361 	mlen = OF_getprop(parent, "interrupt-map-mask", imask, sizeof(imask));
    362 
    363 	if (len == -1 || mlen == -1)
    364 		goto nomap;
    365 
    366 #ifdef DIAGNOSTIC
    367 	if (mlen == sizeof(imask)) {
    368 		printf("interrupt-map too long\n");
    369 		return -1;
    370 	}
    371 #endif
    372 
    373 	/* mask addr by "interrupt-map-mask" */
    374 	bcopy(addr, maskedaddr, mlen);
    375 	for (i = 0; i < mlen / 4; i++)
    376 		maskedaddr[i] &= imask[i];
    377 
    378 	mp = map;
    379 	while (len > mlen) {
    380 		match = bcmp(maskedaddr, mp, mlen);
    381 		mp += mlen / 4;
    382 		len -= mlen;
    383 
    384 		/*
    385 		 * We must read "#interrupt-cells" for each time because
    386 		 * interrupt-parent may be defferent.
    387 		 *
    388 		 * XXX assume #address-cells == 1
    389 		 */
    390 		iparent = *mp++;
    391 		len -= 4;
    392 		if (OF_getprop(iparent, "#interrupt-cells", &icells, 4) != 4)
    393 			return -1;
    394 
    395 		/* Found. */
    396 		if (match == 0) {
    397 			bcopy(mp, intr, icells * 4);
    398 			return icells * 4;
    399 		}
    400 
    401 		mp += icells;
    402 		len -= icells * 4;
    403 	}
    404 
    405 nomap:
    406 	/*
    407 	 * If the node has no interrupt property and the parent is a
    408 	 * pci-bridge, use parent's interrupt.  This occurs on a PCI
    409 	 * slot.  (e.g. AHA-3940)
    410 	 */
    411 	bzero(name, sizeof(name));
    412 	OF_getprop(parent, "name", name, sizeof(name));
    413 	if (strcmp(name, "pci-bridge") == 0) {
    414 		len = OF_getprop(parent, "AAPL,interrupts", intr, 4) ;
    415 		if (len == 4)
    416 			return len;
    417 	}
    418 
    419 	/* XXX This may be wrong... */
    420 	len = OF_getprop(node, "interrupts", intr, 4) ;
    421 	if (len == 4)
    422 		return len;
    423 
    424 	return -1;
    425 }
    426