Home | History | Annotate | Line # | Download | only in pci
pci_machdep.c revision 1.10
      1 /*	$NetBSD: pci_machdep.c,v 1.10 2001/06/15 15:50:06 nonaka 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 
     41 #include <sys/types.h>
     42 #include <sys/param.h>
     43 #include <sys/time.h>
     44 #include <sys/systm.h>
     45 #include <sys/errno.h>
     46 #include <sys/device.h>
     47 
     48 #include <uvm/uvm_extern.h>
     49 
     50 #define _POWERPC_BUS_DMA_PRIVATE
     51 #include <machine/bus.h>
     52 #include <machine/pio.h>
     53 #include <machine/intr.h>
     54 
     55 #include <dev/isa/isavar.h>
     56 #include <dev/pci/pcivar.h>
     57 #include <dev/pci/pcireg.h>
     58 #include <dev/pci/pcidevs.h>
     59 
     60 #define	PCI_MODE1_ENABLE	0x80000000UL
     61 #define	PCI_MODE1_ADDRESS_REG	(PREP_BUS_SPACE_IO + 0xcf8)
     62 #define	PCI_MODE1_DATA_REG	(PREP_BUS_SPACE_IO + 0xcfc)
     63 
     64 #define	o2i(off)	((off)/sizeof(pcireg_t))
     65 
     66 /*
     67  * PCI doesn't have any special needs; just use the generic versions
     68  * of these functions.
     69  */
     70 struct powerpc_bus_dma_tag pci_bus_dma_tag = {
     71 	0,			/* _bounce_thresh */
     72 	_bus_dmamap_create,
     73 	_bus_dmamap_destroy,
     74 	_bus_dmamap_load,
     75 	_bus_dmamap_load_mbuf,
     76 	_bus_dmamap_load_uio,
     77 	_bus_dmamap_load_raw,
     78 	_bus_dmamap_unload,
     79 	NULL,			/* _dmamap_sync */
     80 	_bus_dmamem_alloc,
     81 	_bus_dmamem_free,
     82 	_bus_dmamem_map,
     83 	_bus_dmamem_unmap,
     84 	_bus_dmamem_mmap,
     85 };
     86 
     87 void
     88 pci_attach_hook(parent, self, pba)
     89 	struct device *parent, *self;
     90 	struct pcibus_attach_args *pba;
     91 {
     92 	pci_chipset_tag_t pc;
     93 	int bus, device, maxndevs, function, nfunctions;
     94 	int iq = 2;		/* fixup ioaddr: 0x02000000~ */
     95 	int mq = 1;		/* fixup memaddr: 0x01000000~ */
     96 
     97 	pc = pba->pba_pc;
     98 	bus = pba->pba_bus;
     99 
    100 	maxndevs = pci_bus_maxdevs(pba->pba_pc, pba->pba_bus);
    101 
    102 	for (device = 0; device < maxndevs; device++) {
    103 		pcitag_t tag;
    104 		pcireg_t id, intr, bhlcr, csr, adr;
    105 		int line;
    106 
    107 		tag = pci_make_tag(pc, bus, device, 0);
    108 		id = pci_conf_read(pc, tag, PCI_ID_REG);
    109 
    110 		/* Invalid vendor ID value? */
    111 		if (PCI_VENDOR(id) == PCI_VENDOR_INVALID)
    112 			continue;
    113 		/* XXX Not invalid, but we've done this ~forever. */
    114 		if (PCI_VENDOR(id) == 0)
    115 			continue;
    116 
    117 		bhlcr = pci_conf_read(pc, tag, PCI_BHLC_REG);
    118 		if (PCI_HDRTYPE_MULTIFN(bhlcr))
    119 			nfunctions = 8;
    120 		else
    121 			nfunctions = 1;
    122 
    123 		for (function = 0; function < nfunctions; function++) {
    124 			pcireg_t regs[256/sizeof(pcireg_t)];
    125 			pcireg_t mask;
    126 			pcireg_t rval;
    127 			int off;
    128 			int memfound, iofound;
    129 
    130 			tag = pci_make_tag(pc, bus, device, function);
    131 			id = pci_conf_read(pc, tag, PCI_ID_REG);
    132 
    133 			/* Invalid vendor ID value? */
    134 			if (PCI_VENDOR(id) == PCI_VENDOR_INVALID)
    135                                 continue;
    136 			/* XXX Not invalid, but we've done this ~forever. */
    137 			if (PCI_VENDOR(id) == 0)
    138 				continue;
    139 
    140 			/* Enable io/mem */
    141 			memfound = 0;
    142 			iofound = 0;
    143 			for (off = 0; off < 256; off += sizeof(pcireg_t))
    144 				regs[o2i(off)] = pci_conf_read(pc, tag, off);
    145 			/* is it a std device header? */
    146 			if (PCI_HDRTYPE_TYPE(regs[o2i(PCI_BHLC_REG)]) != 0)
    147 				continue;
    148 			for (off = PCI_MAPREG_START;
    149 			    off < PCI_MAPREG_END; off += sizeof(pcireg_t)) {
    150 				rval = regs[o2i(off)];
    151 				if (rval != 0) {
    152 					pci_conf_write(pc, tag, off, 0xffffffff);
    153 					mask = pci_conf_read(pc, tag, off);
    154 					pci_conf_write(pc, tag, off, rval);
    155 				} else
    156 					mask = 0;
    157 #ifdef DEBUG
    158 				printf("\n");
    159 				printf("dev %d func %d ", device, function);
    160 				printf("off %02x addr %08x mask %08x",
    161 				    off, rval, mask);
    162 #endif
    163 				if (rval == 0)
    164 					continue;
    165 				/* find IO or MEM space */
    166 				if (PCI_MAPREG_TYPE(rval) == PCI_MAPREG_TYPE_MEM)
    167 					memfound = 1;
    168 				else
    169 					iofound = 1;
    170 			}
    171 			if (memfound) {
    172 				csr = pci_conf_read(pc, tag,
    173 				    PCI_COMMAND_STATUS_REG);
    174 				csr |= PCI_COMMAND_MEM_ENABLE;
    175 				pci_conf_write(pc, tag,
    176 				    PCI_COMMAND_STATUS_REG, csr);
    177 #ifdef DEBUG
    178 				printf("\n");
    179 				printf("dev %d func %d: mem", device, function);
    180 #endif
    181 			}
    182 			if (iofound) {
    183 				csr = pci_conf_read(pc, tag,
    184 				    PCI_COMMAND_STATUS_REG);
    185 				csr |= PCI_COMMAND_IO_ENABLE;
    186 				pci_conf_write(pc, tag,
    187 				    PCI_COMMAND_STATUS_REG, csr);
    188 #ifdef DEBUG
    189 				printf("\n");
    190 				printf("dev %d func %d: io", device, function);
    191 #endif
    192 			}
    193 
    194 			/* Fixup insane address */
    195 			for (off = PCI_MAPREG_START;
    196 			    off < PCI_MAPREG_END; off += sizeof(pcireg_t)) {
    197 				int need_fixup;
    198 
    199 				need_fixup = 0;
    200 				adr = pci_conf_read(pc, tag, off);
    201 				if (adr > 0x10000000 ||
    202 				    (adr < 0x1000 && adr != 0))
    203 					need_fixup = 1;
    204 
    205 				if (need_fixup) {
    206 #ifdef DEBUG
    207 					printf("\n");
    208 					printf("dev %d func %d %saddr %08x -> ",
    209 					    device, function,
    210 					    PCI_MAPREG_TYPE(adr) ==
    211 					      PCI_MAPREG_TYPE_MEM ? "mem":"io",
    212 					    adr);
    213 #endif
    214 					adr &= 0x00ffffff;
    215 					adr |= 0x01000000 *
    216 					    (PCI_MAPREG_TYPE(adr) ==
    217 					      PCI_MAPREG_TYPE_MEM ? mq++:iq++);
    218 #ifdef DEBUG
    219 					printf("%08x", adr);
    220 #endif
    221 					pci_conf_write(pc, tag, off, adr);
    222 				}
    223 			}
    224 
    225 			/* Fixup intr */
    226 #if 1
    227 			/* XXX: ibm_machdep : ppc830 depend */
    228 			switch (device) {
    229 			case 12:
    230 			case 18:
    231 			case 22:
    232 				line = 15;
    233 				break;
    234 			default:
    235 				line = 0;
    236 				break;
    237 			}
    238 
    239 			if (line) {
    240 				intr = pci_conf_read(pc, tag, PCI_INTERRUPT_REG);
    241 				pci_conf_write(pc, tag, PCI_INTERRUPT_REG,
    242 				    (intr & ~0xff) | line);
    243 			}
    244 #endif
    245 		}
    246 	}
    247 }
    248 
    249 int
    250 pci_bus_maxdevs(pc, busno)
    251 	pci_chipset_tag_t pc;
    252 	int busno;
    253 {
    254 
    255 	/*
    256 	 * Bus number is irrelevant.  Configuration Mechanism 1 is in
    257 	 * use, can have devices 0-32 (i.e. the `normal' range).
    258 	 */
    259 	return (32);
    260 }
    261 
    262 pcitag_t
    263 pci_make_tag(pc, bus, device, function)
    264 	pci_chipset_tag_t pc;
    265 	int bus, device, function;
    266 {
    267 	pcitag_t tag;
    268 
    269 	if (bus >= 256 || device >= 32 || function >= 8)
    270 		panic("pci_make_tag: bad request");
    271 
    272 	tag = PCI_MODE1_ENABLE |
    273 		    (bus << 16) | (device << 11) | (function << 8);
    274 	return tag;
    275 }
    276 
    277 void
    278 pci_decompose_tag(pc, tag, bp, dp, fp)
    279 	pci_chipset_tag_t pc;
    280 	pcitag_t tag;
    281 	int *bp, *dp, *fp;
    282 {
    283 
    284 	if (bp != NULL)
    285 		*bp = (tag >> 16) & 0xff;
    286 	if (dp != NULL)
    287 		*dp = (tag >> 11) & 0x1f;
    288 	if (fp != NULL)
    289 		*fp = (tag >> 8) & 0x7;
    290 	return;
    291 }
    292 
    293 pcireg_t
    294 pci_conf_read(pc, tag, reg)
    295 	pci_chipset_tag_t pc;
    296 	pcitag_t tag;
    297 	int reg;
    298 {
    299 	pcireg_t data;
    300 
    301 	out32rb(PCI_MODE1_ADDRESS_REG, tag | reg);
    302 	data = in32rb(PCI_MODE1_DATA_REG);
    303 	out32rb(PCI_MODE1_ADDRESS_REG, 0);
    304 	return data;
    305 }
    306 
    307 void
    308 pci_conf_write(pc, tag, reg, data)
    309 	pci_chipset_tag_t pc;
    310 	pcitag_t tag;
    311 	int reg;
    312 	pcireg_t data;
    313 {
    314 
    315 	out32rb(PCI_MODE1_ADDRESS_REG, tag | reg);
    316 	out32rb(PCI_MODE1_DATA_REG, data);
    317 	out32rb(PCI_MODE1_ADDRESS_REG, 0);
    318 }
    319 
    320 int
    321 pci_intr_map(pa, ihp)
    322 	struct pci_attach_args *pa;
    323 	pci_intr_handle_t *ihp;
    324 {
    325 	int pin = pa->pa_intrpin;
    326 	int line = pa->pa_intrline;
    327 
    328 	if (pin == 0) {
    329 		/* No IRQ used. */
    330 		goto bad;
    331 	}
    332 
    333 	if (pin > 4) {
    334 		printf("pci_intr_map: bad interrupt pin %d\n", pin);
    335 		goto bad;
    336 	}
    337 
    338 	/*
    339 	* Section 6.2.4, `Miscellaneous Functions', says that 255 means
    340 	* `unknown' or `no connection' on a PC.  We assume that a device with
    341 	* `no connection' either doesn't have an interrupt (in which case the
    342 	* pin number should be 0, and would have been noticed above), or
    343 	* wasn't configured by the BIOS (in which case we punt, since there's
    344 	* no real way we can know how the interrupt lines are mapped in the
    345 	* hardware).
    346 	*
    347 	* XXX
    348 	* Since IRQ 0 is only used by the clock, and we can't actually be sure
    349 	* that the BIOS did its job, we also recognize that as meaning that
    350 	* the BIOS has not configured the device.
    351 	*/
    352 	if (line == 0 || line == 255) {
    353 		printf("pci_intr_map: no mapping for pin %c\n", '@' + pin);
    354 		goto bad;
    355 	} else {
    356 		if (line >= ICU_LEN) {
    357 			printf("pci_intr_map: bad interrupt line %d\n", line);
    358 			goto bad;
    359 		}
    360 		if (line == IRQ_SLAVE) {
    361 			printf("pci_intr_map: changed line 2 to line 9\n");
    362 			line = 9;
    363 		}
    364 	}
    365 
    366 	*ihp = line;
    367 	return 0;
    368 
    369 bad:
    370 	*ihp = -1;
    371 	return 1;
    372 }
    373 
    374 const char *
    375 pci_intr_string(pc, ih)
    376 	pci_chipset_tag_t pc;
    377 	pci_intr_handle_t ih;
    378 {
    379 	static char irqstr[8];		/* 4 + 2 + NULL + sanity */
    380 
    381 	if (ih == 0 || ih >= ICU_LEN || ih == IRQ_SLAVE)
    382 		panic("pci_intr_string: bogus handle 0x%x\n", ih);
    383 
    384 	sprintf(irqstr, "irq %d", ih);
    385 	return (irqstr);
    386 
    387 }
    388 
    389 const struct evcnt *
    390 pci_intr_evcnt(pc, ih)
    391 	pci_chipset_tag_t pc;
    392 	pci_intr_handle_t ih;
    393 {
    394 
    395 	/* XXX for now, no evcnt parent reported */
    396 	return NULL;
    397 }
    398 
    399 void *
    400 pci_intr_establish(pc, ih, level, func, arg)
    401 	pci_chipset_tag_t pc;
    402 	pci_intr_handle_t ih;
    403 	int level, (*func) __P((void *));
    404 	void *arg;
    405 {
    406 
    407 	if (ih == 0 || ih >= ICU_LEN || ih == IRQ_SLAVE)
    408 		panic("pci_intr_establish: bogus handle 0x%x\n", ih);
    409 
    410 	return isa_intr_establish(NULL, ih, IST_LEVEL, level, func, arg);
    411 }
    412 
    413 void
    414 pci_intr_disestablish(pc, cookie)
    415 	pci_chipset_tag_t pc;
    416 	void *cookie;
    417 {
    418 
    419 	isa_intr_disestablish(NULL, cookie);
    420 }
    421