Home | History | Annotate | Line # | Download | only in pci
pchb.c revision 1.3
      1 /*	$NetBSD: pchb.c,v 1.3 2007/11/12 19:40:49 joerg Exp $ */
      2 
      3 /*-
      4  * Copyright (c) 1996, 1998, 2000 The NetBSD Foundation, Inc.
      5  * All rights reserved.
      6  *
      7  * This code is derived from software contributed to The NetBSD Foundation
      8  * by Jason R. Thorpe.
      9  *
     10  * Redistribution and use in source and binary forms, with or without
     11  * modification, are permitted provided that the following conditions
     12  * are met:
     13  * 1. Redistributions of source code must retain the above copyright
     14  *    notice, this list of conditions and the following disclaimer.
     15  * 2. Redistributions in binary form must reproduce the above copyright
     16  *    notice, this list of conditions and the following disclaimer in the
     17  *    documentation and/or other materials provided with the distribution.
     18  * 3. All advertising materials mentioning features or use of this software
     19  *    must display the following acknowledgement:
     20  *        This product includes software developed by the NetBSD
     21  *        Foundation, Inc. and its contributors.
     22  * 4. Neither the name of The NetBSD Foundation nor the names of its
     23  *    contributors may be used to endorse or promote products derived
     24  *    from this software without specific prior written permission.
     25  *
     26  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
     27  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
     28  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
     29  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
     30  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
     31  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
     32  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
     33  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
     34  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
     35  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
     36  * POSSIBILITY OF SUCH DAMAGE.
     37  */
     38 
     39 #include <sys/cdefs.h>
     40 __KERNEL_RCSID(0, "$NetBSD: pchb.c,v 1.3 2007/11/12 19:40:49 joerg Exp $");
     41 
     42 #include <sys/types.h>
     43 #include <sys/param.h>
     44 #include <sys/systm.h>
     45 #include <sys/device.h>
     46 
     47 #include <machine/bus.h>
     48 
     49 #include <dev/pci/pcivar.h>
     50 #include <dev/pci/pcireg.h>
     51 
     52 #include <dev/pci/pcidevs.h>
     53 
     54 #include <dev/pci/agpreg.h>
     55 #include <dev/pci/agpvar.h>
     56 
     57 #include <arch/x86/pci/pchbvar.h>
     58 
     59 #include "rnd.h"
     60 
     61 #define PCISET_BRIDGETYPE_MASK	0x3
     62 #define PCISET_TYPE_COMPAT	0x1
     63 #define PCISET_TYPE_AUX		0x2
     64 
     65 #define PCISET_BUSCONFIG_REG	0x48
     66 #define PCISET_BRIDGE_NUMBER(reg)	(((reg) >> 8) & 0xff)
     67 #define PCISET_PCI_BUS_NUMBER(reg)	(((reg) >> 16) & 0xff)
     68 
     69 /* XXX should be in dev/ic/i82443reg.h */
     70 #define	I82443BX_SDRAMC_REG	0x76
     71 
     72 /* XXX should be in dev/ic/i82424{reg.var}.h */
     73 #define I82424_CPU_BCTL_REG		0x53
     74 #define I82424_PCI_BCTL_REG		0x54
     75 
     76 #define I82424_BCTL_CPUMEM_POSTEN	0x01
     77 #define I82424_BCTL_CPUPCI_POSTEN	0x02
     78 #define I82424_BCTL_PCIMEM_BURSTEN	0x01
     79 #define I82424_BCTL_PCI_BURSTEN		0x02
     80 
     81 int	pchbmatch(struct device *, struct cfdata *, void *);
     82 void	pchbattach(struct device *, struct device *, void *);
     83 
     84 CFATTACH_DECL(pchb, sizeof(struct pchb_softc),
     85     pchbmatch, pchbattach, NULL, NULL);
     86 
     87 int
     88 pchbmatch(struct device *parent, struct cfdata *match, void *aux)
     89 {
     90 	struct pci_attach_args *pa = aux;
     91 
     92 	if (PCI_CLASS(pa->pa_class) == PCI_CLASS_BRIDGE &&
     93 	    PCI_SUBCLASS(pa->pa_class) == PCI_SUBCLASS_BRIDGE_HOST)
     94 		return 1;
     95 
     96 	return 0;
     97 }
     98 
     99 void
    100 pchbattach(struct device *parent, struct device *self, void *aux)
    101 {
    102 #if NRND > 0
    103 	struct pchb_softc *sc = (void *) self;
    104 #endif
    105 	struct pci_attach_args *pa = aux;
    106 	char devinfo[256];
    107 	struct pcibus_attach_args pba;
    108 	struct agpbus_attach_args apa;
    109 	pcireg_t bcreg;
    110 	u_char bdnum, pbnum = 0; /* XXX: gcc */
    111 	pcitag_t tag;
    112 	int doattach, attachflags, has_agp;
    113 
    114 	aprint_naive("\n");
    115 	aprint_normal("\n");
    116 
    117 	doattach = 0;
    118 	has_agp = 0;
    119 	attachflags = pa->pa_flags;
    120 
    121 	/*
    122 	 * Print out a description, and configure certain chipsets which
    123 	 * have auxiliary PCI buses.
    124 	 */
    125 
    126 	pci_devinfo(pa->pa_id, pa->pa_class, 0, devinfo, sizeof(devinfo));
    127 	aprint_normal("%s: %s (rev. 0x%02x)\n", self->dv_xname, devinfo,
    128 	    PCI_REVISION(pa->pa_class));
    129 
    130 	switch (PCI_VENDOR(pa->pa_id)) {
    131 	/*
    132 	 * i386 stuff.
    133 	 */
    134 	case PCI_VENDOR_SERVERWORKS:
    135 		pbnum = pci_conf_read(pa->pa_pc, pa->pa_tag, 0x44) & 0xff;
    136 
    137 		if (pbnum == 0)
    138 			break;
    139 
    140 		/*
    141 		 * This host bridge has a second PCI bus.
    142 		 * Configure it.
    143 		 */
    144 		switch (PCI_PRODUCT(pa->pa_id)) {
    145 		case PCI_PRODUCT_SERVERWORKS_CSB5:
    146 		case PCI_PRODUCT_SERVERWORKS_CSB6:
    147 			/* These devices show up as host bridges, but are
    148 			   really southbridges. */
    149 			break;
    150 		case PCI_PRODUCT_SERVERWORKS_CMIC_HE:
    151 		case PCI_PRODUCT_SERVERWORKS_CMIC_LE:
    152 		case PCI_PRODUCT_SERVERWORKS_CMIC_SL:
    153 			/* CNBs and CIOBs are connected to these using a
    154 			   private bus.  The bus number register is that of
    155 			   the first PCI bus hanging off the CIOB.  We let
    156 			   the CIOB attachment handle configuring the PCI
    157 			   buses. */
    158 			break;
    159 		default:
    160 			aprint_error("%s: unknown ServerWorks chip ID "
    161 			    "0x%04x; trying to attach PCI buses behind it\n",
    162 			    self->dv_xname, PCI_PRODUCT(pa->pa_id));
    163 			/* FALLTHROUGH */
    164 		case PCI_PRODUCT_SERVERWORKS_CNB20_LE_AGP:
    165 		case PCI_PRODUCT_SERVERWORKS_CNB30_LE_PCI:
    166 		case PCI_PRODUCT_SERVERWORKS_CNB20_LE_PCI:
    167 		case PCI_PRODUCT_SERVERWORKS_CNB20_HE_PCI:
    168 		case PCI_PRODUCT_SERVERWORKS_CNB20_HE_AGP:
    169 		case PCI_PRODUCT_SERVERWORKS_CIOB_X:
    170 		case PCI_PRODUCT_SERVERWORKS_CNB30_HE:
    171 		case PCI_PRODUCT_SERVERWORKS_CNB20_HE_PCI2:
    172 		case PCI_PRODUCT_SERVERWORKS_CIOB_X2:
    173 		case PCI_PRODUCT_SERVERWORKS_CIOB_E:
    174 			switch (attachflags &
    175 			    (PCI_FLAGS_IO_ENABLED | PCI_FLAGS_MEM_ENABLED)) {
    176 			case 0:
    177 				/* Doesn't smell like there's anything there. */
    178 				break;
    179 			case PCI_FLAGS_MEM_ENABLED:
    180 				attachflags |= PCI_FLAGS_IO_ENABLED;
    181 				/* FALLTHROUGH */
    182 			default:
    183 				doattach = 1;
    184 				break;
    185 			}
    186 			break;
    187 		}
    188 		break;
    189 	case PCI_VENDOR_INTEL:
    190 		switch (PCI_PRODUCT(pa->pa_id)) {
    191 		case PCI_PRODUCT_INTEL_82452_PB:
    192 			bcreg = pci_conf_read(pa->pa_pc, pa->pa_tag, 0x40);
    193 			pbnum = PCISET_BRIDGE_NUMBER(bcreg);
    194 			if (pbnum != 0xff) {
    195 				pbnum++;
    196 				doattach = 1;
    197 			}
    198 			break;
    199 		case PCI_PRODUCT_INTEL_82443BX_AGP:
    200 		case PCI_PRODUCT_INTEL_82443BX_NOAGP:
    201 		/*
    202 		 * http://www.intel.com/design/chipsets/specupdt/290639.htm
    203 		 * says this bug is fixed in steppings >= C0 (erratum 11),
    204 		 * so don't tweak the bits in that case.
    205 		 */
    206 			if (!(PCI_REVISION(pa->pa_class) >= 0x03)) {
    207 				/*
    208 				 * BIOS BUG WORKAROUND!  The 82443BX
    209 				 * datasheet indicates that the only
    210 				 * legal setting for the "Idle/Pipeline
    211 				 * DRAM Leadoff Timing (IPLDT)" parameter
    212 				 * (bits 9:8) is 01.  Unfortunately, some
    213 				 * BIOSs do not set these bits properly.
    214 				 */
    215 				bcreg = pci_conf_read(pa->pa_pc, pa->pa_tag,
    216 				    I82443BX_SDRAMC_REG);
    217 				if ((bcreg & 0x0300) != 0x0100) {
    218 					aprint_verbose("%s: fixing "
    219 					    "Idle/Pipeline DRAM "
    220 					    "Leadoff Timing\n", self->dv_xname);
    221 					bcreg &= ~0x0300;
    222 					bcreg |=  0x0100;
    223 					pci_conf_write(pa->pa_pc, pa->pa_tag,
    224 					    I82443BX_SDRAMC_REG, bcreg);
    225 				}
    226 			}
    227 			break;
    228 
    229 		case PCI_PRODUCT_INTEL_PCI450_PB:
    230 			bcreg = pci_conf_read(pa->pa_pc, pa->pa_tag,
    231 					      PCISET_BUSCONFIG_REG);
    232 			bdnum = PCISET_BRIDGE_NUMBER(bcreg);
    233 			pbnum = PCISET_PCI_BUS_NUMBER(bcreg);
    234 			switch (bdnum & PCISET_BRIDGETYPE_MASK) {
    235 			default:
    236 				aprint_error("%s: bdnum=%x (reserved)\n",
    237 				       self->dv_xname, bdnum);
    238 				break;
    239 			case PCISET_TYPE_COMPAT:
    240 				aprint_verbose(
    241 				    "%s: Compatibility PB (bus %d)\n",
    242 				    self->dv_xname, pbnum);
    243 				break;
    244 			case PCISET_TYPE_AUX:
    245 				aprint_verbose("%s: Auxiliary PB (bus %d)\n",
    246 				       self->dv_xname, pbnum);
    247 				/*
    248 				 * This host bridge has a second PCI bus.
    249 				 * Configure it.
    250 				 */
    251 				doattach = 1;
    252 				break;
    253 			}
    254 			break;
    255 		case PCI_PRODUCT_INTEL_CDC:
    256 			bcreg = pci_conf_read(pa->pa_pc, pa->pa_tag,
    257 					      I82424_CPU_BCTL_REG);
    258 			if (bcreg & I82424_BCTL_CPUPCI_POSTEN) {
    259 				bcreg &= ~I82424_BCTL_CPUPCI_POSTEN;
    260 				pci_conf_write(pa->pa_pc, pa->pa_tag,
    261 					       I82424_CPU_BCTL_REG, bcreg);
    262 				aprint_verbose(
    263 				    "%s: disabled CPU-PCI write posting\n",
    264 				    self->dv_xname);
    265 			}
    266 			break;
    267 		case PCI_PRODUCT_INTEL_82451NX_PXB:
    268 			/*
    269 			 * The NX chipset supports up to 2 "PXB" chips
    270 			 * which can drive 2 PCI buses each. Each bus
    271 			 * shows up as logical PCI device, with fixed
    272 			 * device numbers between 18 and 21.
    273 			 * See the datasheet at
    274 		ftp://download.intel.com/design/chipsets/datashts/24377102.pdf
    275 			 * for details.
    276 			 * (It would be easier to attach all the buses
    277 			 * at the MIOC, but less aesthetical imho.)
    278 			 */
    279 			if ((attachflags &
    280 			    (PCI_FLAGS_IO_ENABLED | PCI_FLAGS_MEM_ENABLED)) ==
    281 			    PCI_FLAGS_MEM_ENABLED)
    282 				attachflags |= PCI_FLAGS_IO_ENABLED;
    283 
    284 			pbnum = 0;
    285 			switch (pa->pa_device) {
    286 			case 18: /* PXB 0 bus A - primary bus */
    287 				break;
    288 			case 19: /* PXB 0 bus B */
    289 				/* read SUBA0 from MIOC */
    290 				tag = pci_make_tag(pa->pa_pc, 0, 16, 0);
    291 				bcreg = pci_conf_read(pa->pa_pc, tag, 0xd0);
    292 				pbnum = ((bcreg & 0x0000ff00) >> 8) + 1;
    293 				break;
    294 			case 20: /* PXB 1 bus A */
    295 				/* read BUSNO1 from MIOC */
    296 				tag = pci_make_tag(pa->pa_pc, 0, 16, 0);
    297 				bcreg = pci_conf_read(pa->pa_pc, tag, 0xd0);
    298 				pbnum = (bcreg & 0xff000000) >> 24;
    299 				break;
    300 			case 21: /* PXB 1 bus B */
    301 				/* read SUBA1 from MIOC */
    302 				tag = pci_make_tag(pa->pa_pc, 0, 16, 0);
    303 				bcreg = pci_conf_read(pa->pa_pc, tag, 0xd4);
    304 				pbnum = (bcreg & 0x000000ff) + 1;
    305 				break;
    306 			}
    307 			if (pbnum != 0)
    308 				doattach = 1;
    309 			break;
    310 
    311 		/*
    312 		 * i386 and amd64 stuff.
    313 		 */
    314 		case PCI_PRODUCT_INTEL_82810_MCH:
    315 		case PCI_PRODUCT_INTEL_82810_DC100_MCH:
    316 		case PCI_PRODUCT_INTEL_82810E_MCH:
    317 		case PCI_PRODUCT_INTEL_82815_FULL_HUB:
    318 		case PCI_PRODUCT_INTEL_82830MP_IO_1:
    319 		case PCI_PRODUCT_INTEL_82845G_DRAM:
    320 		case PCI_PRODUCT_INTEL_82855GM_MCH:
    321 		case PCI_PRODUCT_INTEL_82865_HB:
    322 		case PCI_PRODUCT_INTEL_82915G_HB:
    323 		case PCI_PRODUCT_INTEL_82915GM_HB:
    324 		case PCI_PRODUCT_INTEL_82945P_MCH:
    325 		case PCI_PRODUCT_INTEL_82945GM_HB:
    326 		case PCI_PRODUCT_INTEL_82965Q_HB:
    327 		case PCI_PRODUCT_INTEL_82965G_HB:
    328 		case PCI_PRODUCT_INTEL_82965PM_HB:
    329 			/*
    330 			 * The host bridge is either in GFX mode (internal
    331 			 * graphics) or in AGP mode. In GFX mode, we pretend
    332 			 * to have AGP because the graphics memory access
    333 			 * is very similar and the AGP GATT code will
    334 			 * deal with this. In the latter case, the
    335 			 * pci_get_capability(PCI_CAP_AGP) test below will
    336 			 * fire, so we do no harm by already setting the flag.
    337 			 */
    338 			has_agp = 1;
    339 			break;
    340 		}
    341 		break;
    342 	}
    343 
    344 #if NRND > 0
    345 	/*
    346 	 * Attach a random number generator, if there is one.
    347 	 */
    348 	pchb_attach_rnd(sc, pa);
    349 #endif
    350 
    351 	/*
    352 	 * If we haven't detected AGP yet (via a product ID),
    353 	 * then check for AGP capability on the device.
    354 	 */
    355 	if (has_agp ||
    356 	    pci_get_capability(pa->pa_pc, pa->pa_tag, PCI_CAP_AGP,
    357 			       NULL, NULL) != 0) {
    358 		apa.apa_pci_args = *pa;
    359 		config_found_ia(self, "agpbus", &apa, agpbusprint);
    360 	}
    361 
    362 	if (doattach) {
    363 		pba.pba_iot = pa->pa_iot;
    364 		pba.pba_memt = pa->pa_memt;
    365 		pba.pba_dmat = pa->pa_dmat;
    366 		pba.pba_dmat64 = pa->pa_dmat64;
    367 		pba.pba_pc = pa->pa_pc;
    368 		pba.pba_flags = attachflags;
    369 		pba.pba_bus = pbnum;
    370 		pba.pba_bridgetag = NULL;
    371 		pba.pba_pc = pa->pa_pc;
    372 		pba.pba_intrswiz = 0;
    373 		memset(&pba.pba_intrtag, 0, sizeof(pba.pba_intrtag));
    374 		config_found_ia(self, "pcibus", &pba, pcibusprint);
    375 	}
    376 }
    377