Home | History | Annotate | Line # | Download | only in pci
pci.c revision 1.19.4.1
      1  1.19.4.1   mycroft /*	$NetBSD: pci.c,v 1.19.4.1 1996/12/10 05:45:27 mycroft Exp $	*/
      2       1.3       cgd 
      3       1.1   mycroft /*
      4      1.10       cgd  * Copyright (c) 1995, 1996 Christopher G. Demetriou.  All rights reserved.
      5       1.1   mycroft  * Copyright (c) 1994 Charles Hannum.  All rights reserved.
      6       1.1   mycroft  *
      7       1.1   mycroft  * Redistribution and use in source and binary forms, with or without
      8       1.1   mycroft  * modification, are permitted provided that the following conditions
      9       1.1   mycroft  * are met:
     10       1.1   mycroft  * 1. Redistributions of source code must retain the above copyright
     11       1.1   mycroft  *    notice, this list of conditions and the following disclaimer.
     12       1.1   mycroft  * 2. Redistributions in binary form must reproduce the above copyright
     13       1.1   mycroft  *    notice, this list of conditions and the following disclaimer in the
     14       1.1   mycroft  *    documentation and/or other materials provided with the distribution.
     15       1.1   mycroft  * 3. All advertising materials mentioning features or use of this software
     16       1.1   mycroft  *    must display the following acknowledgement:
     17       1.1   mycroft  *	This product includes software developed by Charles Hannum.
     18       1.1   mycroft  * 4. The name of the author may not be used to endorse or promote products
     19       1.1   mycroft  *    derived from this software without specific prior written permission.
     20       1.1   mycroft  *
     21       1.1   mycroft  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
     22       1.1   mycroft  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
     23       1.1   mycroft  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
     24       1.1   mycroft  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
     25       1.1   mycroft  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
     26       1.1   mycroft  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
     27       1.1   mycroft  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
     28       1.1   mycroft  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
     29       1.1   mycroft  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
     30       1.1   mycroft  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
     31       1.1   mycroft  */
     32       1.1   mycroft 
     33       1.1   mycroft /*
     34      1.10       cgd  * PCI bus autoconfiguration.
     35       1.1   mycroft  */
     36       1.1   mycroft 
     37       1.1   mycroft #include <sys/param.h>
     38      1.10       cgd #include <sys/systm.h>
     39       1.1   mycroft #include <sys/device.h>
     40       1.1   mycroft 
     41      1.10       cgd #include <dev/pci/pcireg.h>
     42       1.7       cgd #include <dev/pci/pcivar.h>
     43      1.10       cgd 
     44      1.10       cgd int pcimatch __P((struct device *, void *, void *));
     45      1.10       cgd void pciattach __P((struct device *, struct device *, void *));
     46      1.10       cgd 
     47      1.16   thorpej struct cfattach pci_ca = {
     48      1.16   thorpej 	sizeof(struct device), pcimatch, pciattach
     49      1.16   thorpej };
     50      1.16   thorpej 
     51      1.16   thorpej struct cfdriver pci_cd = {
     52      1.16   thorpej 	NULL, "pci", DV_DULL
     53      1.10       cgd };
     54      1.10       cgd 
     55      1.10       cgd int	pciprint __P((void *, char *));
     56      1.10       cgd int	pcisubmatch __P((struct device *, void *, void *));
     57      1.10       cgd 
     58      1.10       cgd int
     59      1.10       cgd pcimatch(parent, match, aux)
     60      1.10       cgd 	struct device *parent;
     61      1.10       cgd 	void *match, *aux;
     62      1.10       cgd {
     63      1.10       cgd 	struct cfdata *cf = match;
     64      1.10       cgd 	struct pcibus_attach_args *pba = aux;
     65      1.10       cgd 
     66      1.10       cgd 	if (strcmp(pba->pba_busname, cf->cf_driver->cd_name))
     67      1.10       cgd 		return (0);
     68      1.10       cgd 
     69      1.10       cgd 	/* Check the locators */
     70      1.14       cgd 	if (cf->pcibuscf_bus != PCIBUS_UNK_BUS &&
     71      1.14       cgd 	    cf->pcibuscf_bus != pba->pba_bus)
     72      1.10       cgd 		return (0);
     73      1.10       cgd 
     74      1.10       cgd 	/* sanity */
     75      1.10       cgd 	if (pba->pba_bus < 0 || pba->pba_bus > 255)
     76      1.10       cgd 		return (0);
     77      1.10       cgd 
     78      1.10       cgd 	/*
     79      1.10       cgd 	 * XXX check other (hardware?) indicators
     80      1.10       cgd 	 */
     81      1.10       cgd 
     82      1.10       cgd 	return 1;
     83      1.10       cgd }
     84      1.10       cgd 
     85      1.10       cgd void
     86      1.10       cgd pciattach(parent, self, aux)
     87      1.10       cgd 	struct device *parent, *self;
     88      1.10       cgd 	void *aux;
     89      1.10       cgd {
     90      1.10       cgd 	struct pcibus_attach_args *pba = aux;
     91      1.13       cgd 	bus_chipset_tag_t bc;
     92      1.18       cgd 	pci_chipset_tag_t pc;
     93      1.18       cgd 	int bus, device, maxndevs, function, nfunctions;
     94      1.10       cgd 
     95      1.18       cgd 	pci_attach_hook(parent, self, pba);
     96      1.14       cgd 	printf("\n");
     97      1.10       cgd 
     98      1.18       cgd 	bc = pba->pba_bc;
     99      1.18       cgd 	pc = pba->pba_pc;
    100      1.18       cgd 	bus = pba->pba_bus;
    101      1.18       cgd 	maxndevs = pci_bus_maxdevs(pc, bus);
    102      1.18       cgd 
    103      1.18       cgd 	for (device = 0; device < maxndevs; device++) {
    104      1.10       cgd 		pcitag_t tag;
    105      1.18       cgd 		pcireg_t id, class, intr, bhlcr;
    106      1.10       cgd 		struct pci_attach_args pa;
    107      1.19  christos 		int pin;
    108      1.10       cgd 
    109      1.18       cgd 		tag = pci_make_tag(pc, bus, device, 0);
    110      1.18       cgd 		id = pci_conf_read(pc, tag, PCI_ID_REG);
    111      1.10       cgd 		if (id == 0 || id == 0xffffffff)
    112      1.10       cgd 			continue;
    113      1.10       cgd 
    114      1.18       cgd 		bhlcr = pci_conf_read(pc, tag, PCI_BHLC_REG);
    115      1.17       cgd 		nfunctions = PCI_HDRTYPE_MULTIFN(bhlcr) ? 8 : 1;
    116      1.10       cgd 
    117      1.10       cgd 		for (function = 0; function < nfunctions; function++) {
    118      1.18       cgd 			tag = pci_make_tag(pc, bus, device, function);
    119      1.18       cgd 			id = pci_conf_read(pc, tag, PCI_ID_REG);
    120      1.10       cgd 			if (id == 0 || id == 0xffffffff)
    121      1.10       cgd 				continue;
    122      1.18       cgd 			class = pci_conf_read(pc, tag, PCI_CLASS_REG);
    123      1.18       cgd 			intr = pci_conf_read(pc, tag, PCI_INTERRUPT_REG);
    124      1.10       cgd 
    125      1.18       cgd 			pa.pa_bc = bc;
    126      1.18       cgd 			pa.pa_pc = pc;
    127      1.10       cgd 			pa.pa_device = device;
    128      1.10       cgd 			pa.pa_function = function;
    129      1.10       cgd 			pa.pa_tag = tag;
    130      1.10       cgd 			pa.pa_id = id;
    131      1.10       cgd 			pa.pa_class = class;
    132      1.10       cgd 
    133      1.18       cgd 			if (bus == 0) {
    134      1.18       cgd 				pa.pa_intrswiz = 0;
    135      1.18       cgd 				pa.pa_intrtag = tag;
    136      1.18       cgd 			} else {
    137      1.18       cgd 				pa.pa_intrswiz = pba->pba_intrswiz + device;
    138      1.18       cgd 				pa.pa_intrtag = pba->pba_intrtag;
    139      1.18       cgd 			}
    140      1.18       cgd 			pin = PCI_INTERRUPT_PIN(intr);
    141      1.18       cgd 			if (pin == PCI_INTERRUPT_PIN_NONE) {
    142      1.18       cgd 				/* no interrupt */
    143      1.18       cgd 				pa.pa_intrpin = 0;
    144      1.18       cgd 			} else {
    145      1.18       cgd 				/*
    146      1.18       cgd 				 * swizzle it based on the number of
    147      1.18       cgd 				 * busses we're behind and our device
    148      1.18       cgd 				 * number.
    149      1.18       cgd 				 */
    150      1.18       cgd 				pa.pa_intrpin =			/* XXX */
    151      1.18       cgd 				    ((pin + pa.pa_intrswiz - 1) % 4) + 1;
    152      1.18       cgd 			}
    153      1.18       cgd 			pa.pa_intrline = PCI_INTERRUPT_LINE(intr);
    154      1.18       cgd 
    155      1.10       cgd 			config_found_sm(self, &pa, pciprint, pcisubmatch);
    156      1.10       cgd 		}
    157      1.10       cgd 	}
    158      1.10       cgd }
    159       1.1   mycroft 
    160       1.1   mycroft int
    161      1.10       cgd pciprint(aux, pnp)
    162       1.1   mycroft 	void *aux;
    163      1.10       cgd 	char *pnp;
    164       1.1   mycroft {
    165       1.1   mycroft 	register struct pci_attach_args *pa = aux;
    166      1.10       cgd 	char devinfo[256];
    167       1.1   mycroft 
    168      1.10       cgd 	if (pnp) {
    169      1.10       cgd 		pci_devinfo(pa->pa_id, pa->pa_class, 1, devinfo);
    170      1.10       cgd 		printf("%s at %s", devinfo, pnp);
    171      1.10       cgd 	}
    172      1.10       cgd 	printf(" dev %d function %d", pa->pa_device, pa->pa_function);
    173       1.6   mycroft 	return (UNCONF);
    174       1.6   mycroft }
    175       1.6   mycroft 
    176       1.6   mycroft int
    177       1.6   mycroft pcisubmatch(parent, match, aux)
    178       1.6   mycroft 	struct device *parent;
    179       1.6   mycroft 	void *match, *aux;
    180       1.6   mycroft {
    181       1.6   mycroft 	struct cfdata *cf = match;
    182       1.6   mycroft 	struct pci_attach_args *pa = aux;
    183       1.6   mycroft 
    184      1.14       cgd 	if (cf->pcicf_dev != PCI_UNK_DEV &&
    185      1.14       cgd 	    cf->pcicf_dev != pa->pa_device)
    186       1.6   mycroft 		return 0;
    187      1.14       cgd 	if (cf->pcicf_function != PCI_UNK_FUNCTION &&
    188      1.14       cgd 	    cf->pcicf_function != pa->pa_function)
    189       1.6   mycroft 		return 0;
    190      1.16   thorpej 	return ((*cf->cf_attach->ca_match)(parent, match, aux));
    191      1.18       cgd }
    192      1.18       cgd 
    193      1.18       cgd int
    194      1.18       cgd pci_io_find(pc, pcitag, reg, iobasep, iosizep)
    195      1.18       cgd 	pci_chipset_tag_t pc;
    196      1.18       cgd 	pcitag_t pcitag;
    197      1.18       cgd 	int reg;
    198      1.18       cgd 	bus_io_addr_t *iobasep;
    199      1.18       cgd 	bus_io_size_t *iosizep;
    200      1.18       cgd {
    201      1.18       cgd 	pcireg_t addrdata, sizedata;
    202      1.18       cgd 	int s;
    203      1.18       cgd 
    204      1.18       cgd 	if (reg < PCI_MAPREG_START || reg >= PCI_MAPREG_END || (reg & 3))
    205      1.18       cgd 		panic("pci_io_find: bad request");
    206      1.18       cgd 
    207      1.18       cgd 	/* XXX?
    208      1.18       cgd 	 * Section 6.2.5.1, `Address Maps', tells us that:
    209      1.18       cgd 	 *
    210      1.18       cgd 	 * 1) The builtin software should have already mapped the device in a
    211      1.18       cgd 	 * reasonable way.
    212      1.18       cgd 	 *
    213      1.18       cgd 	 * 2) A device which wants 2^n bytes of memory will hardwire the bottom
    214      1.18       cgd 	 * n bits of the address to 0.  As recommended, we write all 1s and see
    215      1.18       cgd 	 * what we get back.
    216      1.18       cgd 	 */
    217      1.18       cgd 	addrdata = pci_conf_read(pc, pcitag, reg);
    218      1.18       cgd 
    219      1.18       cgd 	s = splhigh();
    220      1.18       cgd 	pci_conf_write(pc, pcitag, reg, 0xffffffff);
    221      1.18       cgd 	sizedata = pci_conf_read(pc, pcitag, reg);
    222      1.18       cgd 	pci_conf_write(pc, pcitag, reg, addrdata);
    223      1.18       cgd 	splx(s);
    224      1.18       cgd 
    225      1.18       cgd 	if (PCI_MAPREG_TYPE(addrdata) != PCI_MAPREG_TYPE_IO)
    226      1.18       cgd 		panic("pci_io_find: not an I/O region");
    227      1.18       cgd 
    228      1.18       cgd 	if (iobasep != NULL)
    229      1.18       cgd 		*iobasep = PCI_MAPREG_IO_ADDR(addrdata);
    230      1.18       cgd 	if (iosizep != NULL)
    231  1.19.4.1   mycroft 		*iosizep = PCI_MAPREG_IO_SIZE(sizedata);
    232      1.18       cgd 
    233      1.18       cgd 	return (0);
    234      1.18       cgd }
    235      1.18       cgd 
    236      1.18       cgd int
    237      1.18       cgd pci_mem_find(pc, pcitag, reg, membasep, memsizep, cacheablep)
    238      1.18       cgd 	pci_chipset_tag_t pc;
    239      1.18       cgd 	pcitag_t pcitag;
    240      1.18       cgd 	int reg;
    241      1.18       cgd 	bus_mem_addr_t *membasep;
    242      1.18       cgd 	bus_mem_size_t *memsizep;
    243      1.18       cgd 	int *cacheablep;
    244      1.18       cgd {
    245      1.18       cgd 	pcireg_t addrdata, sizedata;
    246      1.18       cgd 	int s;
    247      1.18       cgd 
    248      1.18       cgd 	if (reg < PCI_MAPREG_START || reg >= PCI_MAPREG_END || (reg & 3))
    249      1.18       cgd 		panic("pci_find_mem: bad request");
    250      1.18       cgd 
    251      1.18       cgd 	/*
    252      1.18       cgd 	 * Section 6.2.5.1, `Address Maps', tells us that:
    253      1.18       cgd 	 *
    254      1.18       cgd 	 * 1) The builtin software should have already mapped the device in a
    255      1.18       cgd 	 * reasonable way.
    256      1.18       cgd 	 *
    257      1.18       cgd 	 * 2) A device which wants 2^n bytes of memory will hardwire the bottom
    258      1.18       cgd 	 * n bits of the address to 0.  As recommended, we write all 1s and see
    259      1.18       cgd 	 * what we get back.
    260      1.18       cgd 	 */
    261      1.18       cgd 	addrdata = pci_conf_read(pc, pcitag, reg);
    262      1.18       cgd 
    263      1.18       cgd 	s = splhigh();
    264      1.18       cgd 	pci_conf_write(pc, pcitag, reg, 0xffffffff);
    265      1.18       cgd 	sizedata = pci_conf_read(pc, pcitag, reg);
    266      1.18       cgd 	pci_conf_write(pc, pcitag, reg, addrdata);
    267      1.18       cgd 	splx(s);
    268      1.18       cgd 
    269      1.18       cgd 	if (PCI_MAPREG_TYPE(addrdata) == PCI_MAPREG_TYPE_IO)
    270      1.18       cgd 		panic("pci_find_mem: I/O region");
    271      1.18       cgd 
    272      1.18       cgd 	switch (PCI_MAPREG_MEM_TYPE(addrdata)) {
    273      1.18       cgd 	case PCI_MAPREG_MEM_TYPE_32BIT:
    274      1.18       cgd 	case PCI_MAPREG_MEM_TYPE_32BIT_1M:
    275      1.18       cgd 		break;
    276      1.18       cgd 	case PCI_MAPREG_MEM_TYPE_64BIT:
    277      1.18       cgd /* XXX */	printf("pci_find_mem: 64-bit region\n");
    278      1.18       cgd /* XXX */	return (1);
    279      1.18       cgd 	default:
    280      1.18       cgd 		printf("pci_find_mem: reserved region type\n");
    281      1.18       cgd 		return (1);
    282      1.18       cgd 	}
    283      1.18       cgd 
    284      1.18       cgd 	if (membasep != NULL)
    285      1.18       cgd 		*membasep = PCI_MAPREG_MEM_ADDR(addrdata);	/* PCI addr */
    286      1.18       cgd 	if (memsizep != NULL)
    287  1.19.4.1   mycroft 		*memsizep = PCI_MAPREG_MEM_SIZE(sizedata);
    288      1.18       cgd 	if (cacheablep != NULL)
    289      1.18       cgd 		*cacheablep = PCI_MAPREG_MEM_CACHEABLE(addrdata);
    290      1.18       cgd 
    291      1.18       cgd 	return 0;
    292       1.1   mycroft }
    293