pci_pir.c revision 57092
136108Sjb/*
248558Sdes * Copyright (c) 1997, Stefan Esser <se@freebsd.org>
336108Sjb * All rights reserved.
436108Sjb *
543818Swes * Redistribution and use in source and binary forms, with or without
643818Swes * modification, are permitted provided that the following conditions
743818Swes * are met:
843818Swes * 1. Redistributions of source code must retain the above copyright
943818Swes *    notice unmodified, this list of conditions, and the following
1043818Swes *    disclaimer.
1143818Swes * 2. Redistributions in binary form must reproduce the above copyright
1243818Swes *    notice, this list of conditions and the following disclaimer in the
1343818Swes *    documentation and/or other materials provided with the distribution.
1443818Swes *
1543818Swes * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
1643818Swes * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
1743818Swes * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
1843818Swes * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
1943818Swes * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
2043818Swes * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
2143818Swes * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
2243818Swes * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
2343818Swes * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
2443818Swes * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
2543818Swes *
2643818Swes * $FreeBSD: head/sys/i386/pci/pci_pir.c 57092 2000-02-09 20:05:30Z gallatin $
2736108Sjb *
2836108Sjb */
2936108Sjb
3036108Sjb#include <sys/param.h>
3136108Sjb#include <sys/systm.h>
3236108Sjb#include <sys/bus.h>
3336108Sjb#include <sys/kernel.h>
3436108Sjb
3536108Sjb#include <pci/pcivar.h>
3636108Sjb#include <pci/pcireg.h>
3748558Sdes#include <i386/isa/pcibus.h>
3848558Sdes
3948558Sdesstatic int cfgmech;
4048558Sdesstatic int devmax;
4148558Sdes
4248558Sdes/* enable configuration space accesses and return data port address */
4336108Sjb
4436108Sjbstatic int
4536108Sjbpci_cfgenable(unsigned bus, unsigned slot, unsigned func, int reg, int bytes)
4636108Sjb{
4736108Sjb	int dataport = 0;
4836108Sjb
4936108Sjb	if (bus <= PCI_BUSMAX
5036108Sjb	    && slot < devmax
5136108Sjb	    && func <= PCI_FUNCMAX
5236108Sjb	    && reg <= PCI_REGMAX
5336108Sjb	    && bytes != 3
5436108Sjb	    && (unsigned) bytes <= 4
5536108Sjb	    && (reg & (bytes -1)) == 0) {
5636108Sjb		switch (cfgmech) {
5736108Sjb		case 1:
5836108Sjb			outl(CONF1_ADDR_PORT, (1 << 31)
5936108Sjb			     | (bus << 16) | (slot << 11)
6036108Sjb			     | (func << 8) | (reg & ~0x03));
6136108Sjb			dataport = CONF1_DATA_PORT + (reg & 0x03);
6236108Sjb			break;
6336108Sjb		case 2:
6436108Sjb			outb(CONF2_ENABLE_PORT, 0xf0 | (func << 1));
6536108Sjb			outb(CONF2_FORWARD_PORT, bus);
6636108Sjb			dataport = 0xc000 | (slot << 8) | reg;
6736108Sjb			break;
6836108Sjb		}
6936108Sjb	}
7036108Sjb	return (dataport);
7136108Sjb}
7236108Sjb
7336108Sjb/* disable configuration space accesses */
7436108Sjb
7536108Sjbstatic void
7636108Sjbpci_cfgdisable(void)
7736108Sjb{
7836108Sjb	switch (cfgmech) {
7936108Sjb	case 1:
8036108Sjb		outl(CONF1_ADDR_PORT, 0);
8136108Sjb		break;
8236108Sjb	case 2:
8336108Sjb		outb(CONF2_ENABLE_PORT, 0);
8436108Sjb		outb(CONF2_FORWARD_PORT, 0);
8536108Sjb		break;
8636108Sjb	}
8736108Sjb}
8836108Sjb
8936108Sjb/* read configuration space register */
9036108Sjb
9136108Sjbint
9236108Sjbpci_cfgread(pcicfgregs *cfg, int reg, int bytes)
9336108Sjb{
9436108Sjb	int data = -1;
9536108Sjb	int port;
9636108Sjb
9736108Sjb	port = pci_cfgenable(cfg->bus, cfg->slot, cfg->func, reg, bytes);
9836108Sjb
9936108Sjb	if (port != 0) {
10036108Sjb		switch (bytes) {
10136108Sjb		case 1:
10236108Sjb			data = inb(port);
10336108Sjb			break;
10436108Sjb		case 2:
10536108Sjb			data = inw(port);
10636108Sjb			break;
10736108Sjb		case 4:
10836108Sjb			data = inl(port);
10936108Sjb			break;
11036108Sjb		}
11136108Sjb		pci_cfgdisable();
11236108Sjb	}
11336108Sjb	return (data);
11436108Sjb}
11536108Sjb
11636108Sjb/* write configuration space register */
11736108Sjb
11836108Sjbvoid
11936108Sjbpci_cfgwrite(pcicfgregs *cfg, int reg, int data, int bytes)
12036108Sjb{
12136108Sjb	int port;
12236108Sjb
12336108Sjb	port = pci_cfgenable(cfg->bus, cfg->slot, cfg->func, reg, bytes);
12436108Sjb	if (port != 0) {
12536108Sjb		switch (bytes) {
12636108Sjb		case 1:
12736108Sjb			outb(port, data);
12836108Sjb			break;
12936108Sjb		case 2:
13036108Sjb			outw(port, data);
13136108Sjb			break;
13236108Sjb		case 4:
13336108Sjb			outl(port, data);
13436108Sjb			break;
13536108Sjb		}
13636108Sjb		pci_cfgdisable();
13736108Sjb	}
13836108Sjb}
13936108Sjb
14036108Sjb/* check whether the configuration mechanism has been correct identified */
14136108Sjb
14236108Sjbstatic int
14336108Sjbpci_cfgcheck(int maxdev)
14436108Sjb{
14536108Sjb	u_char device;
14636108Sjb
14736108Sjb	if (bootverbose)
14836108Sjb		printf("pci_cfgcheck:\tdevice ");
14936108Sjb
15036108Sjb	for (device = 0; device < maxdev; device++) {
15136108Sjb		unsigned id, class, header;
15236108Sjb		if (bootverbose)
15336108Sjb			printf("%d ", device);
15436108Sjb
15536108Sjb		id = inl(pci_cfgenable(0, device, 0, 0, 4));
15636108Sjb		if (id == 0 || id == -1)
15736108Sjb			continue;
15836108Sjb
15936108Sjb		class = inl(pci_cfgenable(0, device, 0, 8, 4)) >> 8;
16036108Sjb		if (bootverbose)
16136108Sjb			printf("[class=%06x] ", class);
16236108Sjb		if (class == 0 || (class & 0xf870ff) != 0)
16336108Sjb			continue;
16436108Sjb
16536108Sjb		header = inb(pci_cfgenable(0, device, 0, 14, 1));
16636108Sjb		if (bootverbose)
16736108Sjb			printf("[hdr=%02x] ", header);
16836108Sjb		if ((header & 0x7e) != 0)
16936108Sjb			continue;
17036108Sjb
17136108Sjb		if (bootverbose)
17236108Sjb			printf("is there (id=%08x)\n", id);
17336108Sjb
17436108Sjb		pci_cfgdisable();
17536108Sjb		return (1);
17636108Sjb	}
17736108Sjb	if (bootverbose)
17836108Sjb		printf("-- nothing found\n");
17936108Sjb
18036108Sjb	pci_cfgdisable();
18136108Sjb	return (0);
18236108Sjb}
18336108Sjb
18436108Sjbstatic int
18536108Sjbpci_cfgopen(void)
18636108Sjb{
18736108Sjb	unsigned long mode1res,oldval1;
18836108Sjb	unsigned char mode2res,oldval2;
18936108Sjb
19036108Sjb	oldval1 = inl(CONF1_ADDR_PORT);
19136108Sjb
19236108Sjb	if (bootverbose) {
19336108Sjb		printf("pci_open(1):\tmode 1 addr port (0x0cf8) is 0x%08lx\n",
19436108Sjb		       oldval1);
19536108Sjb	}
19636108Sjb
19736108Sjb	if ((oldval1 & CONF1_ENABLE_MSK) == 0) {
19836108Sjb
19936108Sjb		cfgmech = 1;
20036108Sjb		devmax = 32;
20136108Sjb
20236108Sjb		outl(CONF1_ADDR_PORT, CONF1_ENABLE_CHK);
20336108Sjb		outb(CONF1_ADDR_PORT +3, 0);
20436108Sjb		mode1res = inl(CONF1_ADDR_PORT);
20536108Sjb		outl(CONF1_ADDR_PORT, oldval1);
20636108Sjb
20736108Sjb		if (bootverbose)
20836108Sjb			printf("pci_open(1a):\tmode1res=0x%08lx (0x%08lx)\n",
20936108Sjb			       mode1res, CONF1_ENABLE_CHK);
21036108Sjb
21136108Sjb		if (mode1res) {
21236108Sjb			if (pci_cfgcheck(32))
21336108Sjb				return (cfgmech);
21436108Sjb		}
21536108Sjb
21636108Sjb		outl(CONF1_ADDR_PORT, CONF1_ENABLE_CHK1);
21736108Sjb		mode1res = inl(CONF1_ADDR_PORT);
21836108Sjb		outl(CONF1_ADDR_PORT, oldval1);
21936108Sjb
22036108Sjb		if (bootverbose)
22136108Sjb			printf("pci_open(1b):\tmode1res=0x%08lx (0x%08lx)\n",
22236108Sjb			       mode1res, CONF1_ENABLE_CHK1);
22336108Sjb
22436108Sjb		if ((mode1res & CONF1_ENABLE_MSK1) == CONF1_ENABLE_RES1) {
22536108Sjb			if (pci_cfgcheck(32))
22636108Sjb				return (cfgmech);
22736108Sjb		}
22836108Sjb	}
22936108Sjb
23036108Sjb	oldval2 = inb(CONF2_ENABLE_PORT);
23136108Sjb
23236108Sjb	if (bootverbose) {
23336108Sjb		printf("pci_open(2):\tmode 2 enable port (0x0cf8) is 0x%02x\n",
23436108Sjb		       oldval2);
23536108Sjb	}
23636108Sjb
23736108Sjb	if ((oldval2 & 0xf0) == 0) {
23836108Sjb
23936108Sjb		cfgmech = 2;
24036108Sjb		devmax = 16;
24136108Sjb
24236108Sjb		outb(CONF2_ENABLE_PORT, CONF2_ENABLE_CHK);
24336108Sjb		mode2res = inb(CONF2_ENABLE_PORT);
24436108Sjb		outb(CONF2_ENABLE_PORT, oldval2);
24536108Sjb
24636108Sjb		if (bootverbose)
24736108Sjb			printf("pci_open(2a):\tmode2res=0x%02x (0x%02x)\n",
24836108Sjb			       mode2res, CONF2_ENABLE_CHK);
24936108Sjb
25036108Sjb		if (mode2res == CONF2_ENABLE_RES) {
25136108Sjb			if (bootverbose)
25236108Sjb				printf("pci_open(2a):\tnow trying mechanism 2\n");
25336108Sjb
25436108Sjb			if (pci_cfgcheck(16))
25536108Sjb				return (cfgmech);
25636108Sjb		}
25736108Sjb	}
25836108Sjb
25936108Sjb	cfgmech = 0;
26036108Sjb	devmax = 0;
26136108Sjb	return (cfgmech);
26236108Sjb}
26336108Sjb
26436108Sjbstatic devclass_t	pcib_devclass;
26536108Sjb
26636108Sjbstatic const char *
26736108Sjbnexus_pcib_is_host_bridge(pcicfgregs *cfg,
26836108Sjb			  u_int32_t id, u_int8_t class, u_int8_t subclass,
26936108Sjb			  u_int8_t *busnum)
27036108Sjb{
27136108Sjb	const char *s = NULL;
27236108Sjb	static u_int8_t pxb[4];	/* hack for 450nx */
27336108Sjb
27436108Sjb	*busnum = 0;
27536108Sjb
27636108Sjb	switch (id) {
27736108Sjb	case 0x12258086:
27836108Sjb		s = "Intel 824?? host to PCI bridge";
27936108Sjb		/* XXX This is a guess */
28036108Sjb		*busnum = pci_cfgread(cfg, 0x41, 1);
28136108Sjb		break;
28236108Sjb	case 0x71208086:
28336108Sjb		s = "Intel 82810 (i810 GMCH) Host To Hub bridge";
28436108Sjb		break;
28536108Sjb	case 0x71228086:
28636108Sjb		s = "Intel 82810-DC100 (i810-DC100 GMCH) Host To Hub bridge";
28736108Sjb		break;
28836108Sjb	case 0x71248086:
28936108Sjb		s = "Intel 82810E (i810E GMCH) Host To Hub bridge";
29036108Sjb		break;
29136108Sjb	case 0x71808086:
29236108Sjb		s = "Intel 82443LX (440 LX) host to PCI bridge";
29336108Sjb		break;
29436108Sjb	case 0x71908086:
29536108Sjb		s = "Intel 82443BX (440 BX) host to PCI bridge";
29636108Sjb		break;
29736108Sjb	case 0x71928086:
29836108Sjb		s = "Intel 82443BX host to PCI bridge (AGP disabled)";
29936108Sjb		break;
30036108Sjb	case 0x71a08086:
30136108Sjb		s = "Intel 82443GX host to PCI bridge";
30236108Sjb		break;
30336108Sjb	case 0x71a18086:
30436108Sjb		s = "Intel 82443GX host to AGP bridge";
30536108Sjb		break;
306	case 0x71a28086:
307		s = "Intel 82443GX host to PCI bridge (AGP disabled)";
308		break;
309	case 0x84c48086:
310		s = "Intel 82454KX/GX (Orion) host to PCI bridge";
311		*busnum = pci_cfgread(cfg, 0x4a, 1);
312		break;
313	case 0x84ca8086:
314		/*
315		 * For the 450nx chipset, there is a whole bundle of
316		 * things pretending to be host bridges. The MIOC will
317		 * be seen first and isn't really a pci bridge (the
318		 * actual busses are attached to the PXB's). We need to
319		 * read the registers of the MIOC to figure out the
320		 * bus numbers for the PXB channels.
321		 *
322		 * Since the MIOC doesn't have a pci bus attached, we
323		 * pretend it wasn't there.
324		 */
325		pxb[0] = pci_cfgread(cfg, 0xd0, 1); /* BUSNO[0] */
326		pxb[1] = pci_cfgread(cfg, 0xd1, 1) + 1;	/* SUBA[0]+1 */
327		pxb[2] = pci_cfgread(cfg, 0xd3, 1); /* BUSNO[1] */
328		pxb[3] = pci_cfgread(cfg, 0xd4, 1) + 1;	/* SUBA[1]+1 */
329		return NULL;
330	case 0x84cb8086:
331		switch (cfg->slot) {
332		case 0x12:
333			s = "Intel 82454NX PXB#0, Bus#A";
334			*busnum = pxb[0];
335			break;
336		case 0x13:
337			s = "Intel 82454NX PXB#0, Bus#B";
338			*busnum = pxb[1];
339			break;
340		case 0x14:
341			s = "Intel 82454NX PXB#1, Bus#A";
342			*busnum = pxb[2];
343			break;
344		case 0x15:
345			s = "Intel 82454NX PXB#1, Bus#B";
346			*busnum = pxb[3];
347			break;
348		}
349		break;
350
351		/* AMD -- vendor 0x1022 */
352	case 0x70061022:
353		s = "AMD-751 host to PCI bridge";
354		break;
355
356		/* SiS -- vendor 0x1039 */
357	case 0x04961039:
358		s = "SiS 85c496";
359		break;
360	case 0x04061039:
361		s = "SiS 85c501";
362		break;
363	case 0x06011039:
364		s = "SiS 85c601";
365		break;
366	case 0x55911039:
367		s = "SiS 5591 host to PCI bridge";
368		break;
369	case 0x00011039:
370		s = "SiS 5591 host to AGP bridge";
371		break;
372
373		/* VLSI -- vendor 0x1004 */
374	case 0x00051004:
375		s = "VLSI 82C592 Host to PCI bridge";
376		break;
377
378		/* XXX Here is MVP3, I got the datasheet but NO M/B to test it  */
379		/* totally. Please let me know if anything wrong.            -F */
380		/* XXX need info on the MVP3 -- any takers? */
381	case 0x05981106:
382		s = "VIA 82C598MVP (Apollo MVP3) host bridge";
383		break;
384
385		/* AcerLabs -- vendor 0x10b9 */
386		/* Funny : The datasheet told me vendor id is "10b8",sub-vendor */
387		/* id is '10b9" but the register always shows "10b9". -Foxfair  */
388	case 0x154110b9:
389		s = "AcerLabs M1541 (Aladdin-V) PCI host bridge";
390		break;
391
392		/* OPTi -- vendor 0x1045 */
393	case 0xc8221045:
394		s = "OPTi 82C822 host to PCI Bridge";
395		break;
396
397		/* RCC -- vendor 0x1166 */
398	case 0x00051166:
399		s = "RCC HE host to PCI bridge";
400		*busnum = pci_cfgread(cfg, 0x44, 1);
401		break;
402
403	case 0x00061166:
404		/* FALLTHROUGH */
405	case 0x00081166:
406		s = "RCC host to PCI bridge";
407		*busnum = pci_cfgread(cfg, 0x44, 1);
408		break;
409
410	case 0x00091166:
411		s = "RCC LE host to PCI bridge";
412		*busnum = pci_cfgread(cfg, 0x44, 1);
413		break;
414
415		/* Integrated Micro Solutions -- vendor 0x10e0 */
416	case 0x884910e0:
417		s = "Integrated Micro Solutions VL Bridge";
418		break;
419
420	default:
421		if (class == PCIC_BRIDGE && subclass == PCIS_BRIDGE_HOST)
422			s = "Host to PCI bridge";
423		break;
424	}
425
426	return s;
427}
428
429/*
430 * Scan the first pci bus for host-pci bridges and add pcib instances
431 * to the nexus for each bridge.
432 */
433static void
434nexus_pcib_identify(driver_t *driver, device_t parent)
435{
436	pcicfgregs probe;
437	u_int8_t  hdrtype;
438	int found = 0;
439	int pcifunchigh;
440
441	if (pci_cfgopen() == 0)
442		return;
443	probe.hose = 0;
444	probe.bus = 0;
445	for (probe.slot = 0; probe.slot <= PCI_SLOTMAX; probe.slot++) {
446		hdrtype = pci_cfgread(&probe, PCIR_HEADERTYPE, 1);
447		if (hdrtype & PCIM_MFDEV)
448			pcifunchigh = 7;
449		else
450			pcifunchigh = 0;
451		for (probe.func = 0;
452		     probe.func <= pcifunchigh;
453		     probe.func++) {
454			/*
455			 * Read the IDs and class from the device.
456			 */
457			u_int32_t id;
458			u_int8_t class, subclass, busnum;
459			device_t child;
460			const char *s;
461
462			id = pci_cfgread(&probe, PCIR_DEVVENDOR, 4);
463			if (id == -1)
464				continue;
465			class = pci_cfgread(&probe, PCIR_CLASS, 1);
466			subclass = pci_cfgread(&probe, PCIR_SUBCLASS, 1);
467
468			s = nexus_pcib_is_host_bridge(&probe, id,
469						      class, subclass,
470						      &busnum);
471			if (s) {
472				/*
473				 * Add at priority 100 to make sure we
474				 * go after any motherboard resources
475				 */
476				child = BUS_ADD_CHILD(parent, 100,
477						      "pcib", busnum);
478				device_set_desc(child, s);
479				found = 1;
480			}
481		}
482	}
483
484	/*
485	 * Make sure we add at least one bridge since some old
486	 * hardware doesn't actually have a host-pci bridge device.
487	 * Note that pci_cfgopen() thinks we have PCI devices..
488	 */
489	if (!found) {
490		if (bootverbose)
491			printf(
492	"nexus_pcib_identify: no bridge found, adding pcib0 anyway\n");
493		BUS_ADD_CHILD(parent, 100, "pcib", 0);
494	}
495}
496
497static int
498nexus_pcib_probe(device_t dev)
499{
500	if (pci_cfgopen() != 0) {
501		device_add_child(dev, "pci", device_get_unit(dev));
502		return 0;
503	}
504	return ENXIO;
505}
506
507static device_method_t nexus_pcib_methods[] = {
508	/* Device interface */
509	DEVMETHOD(device_identify,	nexus_pcib_identify),
510	DEVMETHOD(device_probe,		nexus_pcib_probe),
511	DEVMETHOD(device_attach,	bus_generic_attach),
512	DEVMETHOD(device_shutdown,	bus_generic_shutdown),
513	DEVMETHOD(device_suspend,	bus_generic_suspend),
514	DEVMETHOD(device_resume,	bus_generic_resume),
515
516	/* Bus interface */
517	DEVMETHOD(bus_print_child,	bus_generic_print_child),
518	DEVMETHOD(bus_alloc_resource,	bus_generic_alloc_resource),
519	DEVMETHOD(bus_release_resource,	bus_generic_release_resource),
520	DEVMETHOD(bus_activate_resource, bus_generic_activate_resource),
521	DEVMETHOD(bus_deactivate_resource, bus_generic_deactivate_resource),
522	DEVMETHOD(bus_setup_intr,	bus_generic_setup_intr),
523	DEVMETHOD(bus_teardown_intr,	bus_generic_teardown_intr),
524
525	{ 0, 0 }
526};
527
528static driver_t nexus_pcib_driver = {
529	"pcib",
530	nexus_pcib_methods,
531	1,
532};
533
534DRIVER_MODULE(pcib, nexus, nexus_pcib_driver, pcib_devclass, 0, 0);
535