Home | History | Annotate | Line # | Download | only in pci
pci_machdep.c revision 1.11
      1 /*	$NetBSD: pci_machdep.c,v 1.11 2000/06/04 19:14:49 cgd 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 const struct evcnt *
    249 pci_intr_evcnt(pc, ih)
    250 	pci_chipset_tag_t pc;
    251 	pci_intr_handle_t ih;
    252 {
    253 
    254 	/* XXX for now, no evcnt parent reported */
    255 	return NULL;
    256 }
    257 
    258 extern void * intr_establish();
    259 extern void intr_disestablish();
    260 
    261 void *
    262 pci_intr_establish(pc, ih, level, func, arg)
    263 	pci_chipset_tag_t pc;
    264 	pci_intr_handle_t ih;
    265 	int level, (*func) __P((void *));
    266 	void *arg;
    267 {
    268 
    269 	if (ih == 0 || ih >= ICU_LEN)
    270 		panic("pci_intr_establish: bogus handle 0x%x\n", ih);
    271 
    272 	return intr_establish(ih, IST_LEVEL, level, func, arg);
    273 }
    274 
    275 void
    276 pci_intr_disestablish(pc, cookie)
    277 	pci_chipset_tag_t pc;
    278 	void *cookie;
    279 {
    280 
    281 	intr_disestablish(cookie);
    282 }
    283 
    284 #define pcibus(x) \
    285 	(((x) & OFW_PCI_PHYS_HI_BUSMASK) >> OFW_PCI_PHYS_HI_BUSSHIFT)
    286 #define pcidev(x) \
    287 	(((x) & OFW_PCI_PHYS_HI_DEVICEMASK) >> OFW_PCI_PHYS_HI_DEVICESHIFT)
    288 #define pcifunc(x) \
    289 	(((x) & OFW_PCI_PHYS_HI_FUNCTIONMASK) >> OFW_PCI_PHYS_HI_FUNCTIONSHIFT)
    290 
    291 void
    292 fixpci(parent, pc)
    293 	int parent;
    294 	pci_chipset_tag_t pc;
    295 {
    296 	int node;
    297 	pcitag_t tag;
    298 	pcireg_t csr, intr;
    299 	int len, i;
    300 	int32_t irqs[4];
    301 	struct {
    302 		u_int32_t phys_hi, phys_mid, phys_lo;
    303 		u_int32_t size_hi, size_lo;
    304 	} addr[8];
    305 
    306 	for (node = OF_child(parent); node; node = OF_peer(node)) {
    307 		len = OF_getprop(node, "assigned-addresses", addr,
    308 				 sizeof(addr));
    309 		if (len < (int)sizeof(addr[0]))
    310 			continue;
    311 
    312 		tag = pci_make_tag(pc, pcibus(addr[0].phys_hi),
    313 				   pcidev(addr[0].phys_hi),
    314 				   pcifunc(addr[0].phys_hi));
    315 
    316 		/*
    317 		 * Make sure the IO and MEM enable bits are set in the CSR.
    318 		 */
    319 		csr = pci_conf_read(pc, tag, PCI_COMMAND_STATUS_REG);
    320 		csr &= ~(PCI_COMMAND_IO_ENABLE | PCI_COMMAND_MEM_ENABLE);
    321 
    322 		for (i = 0; i < len / sizeof(addr[0]); i++) {
    323 			switch (addr[i].phys_hi & OFW_PCI_PHYS_HI_SPACEMASK) {
    324 			case OFW_PCI_PHYS_HI_SPACE_IO:
    325 				csr |= PCI_COMMAND_IO_ENABLE;
    326 				break;
    327 
    328 			case OFW_PCI_PHYS_HI_SPACE_MEM32:
    329 				csr |= PCI_COMMAND_MEM_ENABLE;
    330 				break;
    331 			}
    332 		}
    333 
    334 		pci_conf_write(pc, tag, PCI_COMMAND_STATUS_REG, csr);
    335 
    336 		/*
    337 		 * Make sure the line register is programmed with the
    338 		 * interrupt mapping.
    339 		 */
    340 		if (find_node_intr(node, &addr[0].phys_hi, irqs) == -1)
    341 			continue;
    342 
    343 		intr = pci_conf_read(pc, tag, PCI_INTERRUPT_REG);
    344 		intr &= ~PCI_INTERRUPT_LINE_MASK;
    345 		intr |= irqs[0] & PCI_INTERRUPT_LINE_MASK;
    346 		pci_conf_write(pc, tag, PCI_INTERRUPT_REG, intr);
    347 	}
    348 }
    349 
    350 /*
    351  * Find PCI IRQ of the node from OF tree.
    352  */
    353 int
    354 find_node_intr(node, addr, intr)
    355 	int node;
    356 	u_int32_t *addr, *intr;
    357 {
    358 	int parent, len, mlen, iparent;
    359 	int match, i;
    360 	u_int32_t map[64], *mp;
    361 	u_int32_t imask[8], maskedaddr[8];
    362 	u_int32_t icells;
    363 	char name[32];
    364 
    365 	len = OF_getprop(node, "AAPL,interrupts", intr, 4) ;
    366 	if (len == 4)
    367 		return len;
    368 
    369 	parent = OF_parent(node);
    370 	len = OF_getprop(parent, "interrupt-map", map, sizeof(map));
    371 	mlen = OF_getprop(parent, "interrupt-map-mask", imask, sizeof(imask));
    372 
    373 	if (len == -1 || mlen == -1)
    374 		goto nomap;
    375 
    376 #ifdef DIAGNOSTIC
    377 	if (mlen == sizeof(imask)) {
    378 		printf("interrupt-map too long\n");
    379 		return -1;
    380 	}
    381 #endif
    382 
    383 	/* mask addr by "interrupt-map-mask" */
    384 	bcopy(addr, maskedaddr, mlen);
    385 	for (i = 0; i < mlen / 4; i++)
    386 		maskedaddr[i] &= imask[i];
    387 
    388 	mp = map;
    389 	while (len > mlen) {
    390 		match = bcmp(maskedaddr, mp, mlen);
    391 		mp += mlen / 4;
    392 		len -= mlen;
    393 
    394 		/*
    395 		 * We must read "#interrupt-cells" for each time because
    396 		 * interrupt-parent may be defferent.
    397 		 *
    398 		 * XXX assume #address-cells == 1
    399 		 */
    400 		iparent = *mp++;
    401 		len -= 4;
    402 		if (OF_getprop(iparent, "#interrupt-cells", &icells, 4) != 4)
    403 			return -1;
    404 
    405 		/* Found. */
    406 		if (match == 0) {
    407 			bcopy(mp, intr, icells * 4);
    408 			return icells * 4;
    409 		}
    410 
    411 		mp += icells;
    412 		len -= icells * 4;
    413 	}
    414 
    415 nomap:
    416 	/*
    417 	 * If the node has no interrupt property and the parent is a
    418 	 * pci-bridge, use parent's interrupt.  This occurs on a PCI
    419 	 * slot.  (e.g. AHA-3940)
    420 	 */
    421 	bzero(name, sizeof(name));
    422 	OF_getprop(parent, "name", name, sizeof(name));
    423 	if (strcmp(name, "pci-bridge") == 0) {
    424 		len = OF_getprop(parent, "AAPL,interrupts", intr, 4) ;
    425 		if (len == 4)
    426 			return len;
    427 	}
    428 
    429 	/* XXX This may be wrong... */
    430 	len = OF_getprop(node, "interrupts", intr, 4) ;
    431 	if (len == 4)
    432 		return len;
    433 
    434 	return -1;
    435 }
    436