pci_pir.c revision 26159
126159Sse/*
226159Sse * Copyright (c) 1997, Stefan Esser <se@freebsd.org>
326159Sse * All rights reserved.
426159Sse *
526159Sse * Redistribution and use in source and binary forms, with or without
626159Sse * modification, are permitted provided that the following conditions
726159Sse * are met:
826159Sse * 1. Redistributions of source code must retain the above copyright
926159Sse *    notice unmodified, this list of conditions, and the following
1026159Sse *    disclaimer.
1126159Sse * 2. Redistributions in binary form must reproduce the above copyright
1226159Sse *    notice, this list of conditions and the following disclaimer in the
1326159Sse *    documentation and/or other materials provided with the distribution.
1426159Sse *
1526159Sse * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
1626159Sse * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
1726159Sse * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
1826159Sse * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
1926159Sse * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
2026159Sse * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
2126159Sse * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
2226159Sse * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
2326159Sse * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
2426159Sse * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
2526159Sse *
2626159Sse * $Id$
2726159Sse *
2826159Sse */
296104Sse
3026159Sse#include <sys/types.h>
316734Sbde#include <sys/systm.h>
326734Sbde
3326159Sse#include <pci/pcireg.h>
346104Sse#include <pci/pcivar.h>
3526159Sse#include <i386/isa/pcibus.h>
366104Sse
3726159Sse#ifdef PCI_COMPAT
3826159Sse/* XXX this is a terrible hack, which keeps the Tekram AMD SCSI driver happy */
3926159Sse#define cfgmech pci_mechanism
4026159Sseint cfgmech;
4126159Sse#else
4226159Ssestatic int cfgmech;
4326159Sse#endif /* PCI_COMPAT */
4426159Ssestatic int devmax;
456104Sse
4626159Sse/* enable configuration space accesses and return data port address */
4726159Sse
4810887Ssestatic int
4926159Ssepci_cfgenable(unsigned bus, unsigned slot, unsigned func, int reg, int bytes)
5026159Sse{
5126159Sse	int dataport = 0;
5210887Sse
5326159Sse	if (bus <= PCI_BUSMAX
5426159Sse	    && slot < devmax
5526159Sse	    && func <= PCI_FUNCMAX
5626159Sse	    && reg <= PCI_REGMAX
5726159Sse	    && bytes != 3
5826159Sse	    && (unsigned) bytes <= 4
5926159Sse	    && (reg & (bytes -1)) == 0) {
6026159Sse		switch (cfgmech) {
6126159Sse		case 1:
6226159Sse			outl(CONF1_ADDR_PORT,
6326159Sse			     (bus << 16) | (slot << 11) | (func << 8) | reg);
6426159Sse			dataport = CONF1_DATA_PORT;
6526159Sse			break;
6626159Sse		case 2:
6726159Sse			outb(CONF2_ENABLE_PORT, 0xf0 | (func << 1));
6826159Sse			outb(CONF2_FORWARD_PORT, bus);
6926159Sse			dataport = 0xc000 | (slot << 8) | reg;
7026159Sse			break;
7126159Sse		}
7226159Sse	}
7326159Sse	return (dataport);
7426159Sse}
756104Sse
7626159Sse/* disable configuration space accesses */
776104Sse
786104Ssestatic void
7926159Ssepci_cfgdisable(void)
8026159Sse{
8126159Sse	switch (cfgmech) {
8226159Sse	case 1:
8326159Sse		outl(CONF1_ADDR_PORT, 0);
8426159Sse		break;
8526159Sse	case 2:
8626159Sse		outb(CONF2_ENABLE_PORT, 0);
8726159Sse		outb(CONF2_FORWARD_PORT, 0);
8826159Sse		break;
8926159Sse	}
9026159Sse}
916104Sse
9226159Sse/* read configuration space register */
936104Sse
9426159Sseint
9526159Ssepci_cfgread(pcicfgregs *cfg, int reg, int bytes)
9626159Sse{
9726159Sse	int data = -1;
9826159Sse	int port;
997234Sse
10026159Sse	port = pci_cfgenable(cfg->bus, cfg->slot, cfg->func, reg, bytes);
1017234Sse
10226159Sse	if (port != 0) {
10326159Sse		switch (bytes) {
10426159Sse		case 1:
10526159Sse			data = inb(port);
10626159Sse			break;
10726159Sse		case 2:
10826159Sse			data = inw(port);
10926159Sse			break;
11026159Sse		case 4:
11126159Sse			data = inl(port);
11226159Sse			break;
11326159Sse		}
11426159Sse		pci_cfgdisable();
11526159Sse	}
11626159Sse	return (data);
11726159Sse}
1187234Sse
11926159Sse/* write configuration space register */
1206104Sse
12126159Ssevoid
12226159Ssepci_cfgwrite(pcicfgregs *cfg, int reg, int data, int bytes)
12326159Sse{
12426159Sse	int port;
1256104Sse
12626159Sse	port = pci_cfgenable(cfg->bus, cfg->slot, cfg->func, reg, bytes);
12726159Sse	if (port != 0) {
12826159Sse		switch (bytes) {
12926159Sse		case 1:
13026159Sse			outb(port, data);
13126159Sse			break;
13226159Sse		case 2:
13326159Sse			outw(port, data);
13426159Sse			break;
13526159Sse		case 4:
13626159Sse			outl(port, data);
13726159Sse			break;
13826159Sse		}
13926159Sse		pci_cfgdisable();
14026159Sse	}
14126159Sse}
1426104Sse
14326159Sse/* check whether the configuration mechanism has been correct identified */
1446104Sse
14510887Ssestatic int
14626159Ssepci_cfgcheck(int maxdev)
14710887Sse{
14810887Sse	u_char device;
14910735Sse
15026159Sse	if (bootverbose)
15126159Sse		printf("pci_cfgcheck:\tdevice ");
15210960Sse
15326159Sse	for (device = 0; device < maxdev; device++) {
15426159Sse		unsigned id, class, header;
15511378Sse		if (bootverbose)
15626159Sse			printf("%d ", device);
15726159Sse
15826159Sse		id = inl(pci_cfgenable(0, device, 0, 0, 4));
15926159Sse		if (id == 0 || id == -1)
16023415Sse			continue;
16123415Sse
16226159Sse		class = inl(pci_cfgenable(0, device, 0, 8, 4)) >> 8;
16323415Sse		if (bootverbose)
16426159Sse			printf("[class=%06x] ", class);
16526159Sse		if (class == 0 || (class & 0xf8f0ff) != 0)
16623415Sse			continue;
16723415Sse
16826159Sse		header = inb(pci_cfgenable(0, device, 0, 14, 1));
16923415Sse		if (bootverbose)
17026159Sse			printf("[hdr=%02x] ", header);
17126159Sse		if ((header & 0x7e) != 0)
17223415Sse			continue;
17323415Sse
17426159Sse		if (bootverbose)
17526159Sse			printf("is there (id=%08x)\n", id);
17626159Sse
17726159Sse		pci_cfgdisable();
17826159Sse		return (1);
17910887Sse	}
18011378Sse	if (bootverbose)
18126159Sse		printf("-- nothing found\n");
18226159Sse
18326159Sse	pci_cfgdisable();
18426159Sse	return (0);
18510887Sse}
18610887Sse
18726159Sseint
18826159Ssepci_cfgopen(void)
1896104Sse{
19011524Sse	unsigned long mode1res,oldval1;
19111524Sse	unsigned char mode2res,oldval2;
1926104Sse
19326159Sse	oldval1 = inl(CONF1_ADDR_PORT);
19410960Sse
19510960Sse	if (bootverbose) {
19626159Sse		printf("pci_open(1):\tmode 1 addr port (0x0cf8) is 0x%08lx\n",
19726159Sse		       oldval1);
19810960Sse	}
19910960Sse
20011544Sse	if ((oldval1 & CONF1_ENABLE_MSK) == 0) {
20110960Sse
20226159Sse		cfgmech = 1;
20326159Sse		devmax = 32;
20410960Sse
20526159Sse		outl(CONF1_ADDR_PORT, CONF1_ENABLE_CHK);
20626159Sse		outb(CONF1_ADDR_PORT +3, 0);
20726159Sse		mode1res = inl(CONF1_ADDR_PORT);
20826159Sse		outl(CONF1_ADDR_PORT, oldval1);
20910960Sse
21011524Sse		if (bootverbose)
21126159Sse			printf("pci_open(1a):\tmode1res=0x%08lx (0x%08lx)\n",
21226159Sse			       mode1res, CONF1_ENABLE_CHK);
2136104Sse
21411524Sse		if (mode1res) {
21526159Sse			if (pci_cfgcheck(32))
21626159Sse				return (cfgmech);
21726159Sse		}
21810960Sse
21926159Sse		outl(CONF1_ADDR_PORT, CONF1_ENABLE_CHK1);
22011524Sse		mode1res = inl(CONF1_ADDR_PORT);
22126159Sse		outl(CONF1_ADDR_PORT, oldval1);
2226104Sse
22311524Sse		if (bootverbose)
22426159Sse			printf("pci_open(1b):\tmode1res=0x%08lx (0x%08lx)\n",
22526159Sse			       mode1res, CONF1_ENABLE_CHK1);
2269360Sse
22711524Sse		if ((mode1res & CONF1_ENABLE_MSK1) == CONF1_ENABLE_RES1) {
22826159Sse			if (pci_cfgcheck(32))
22926159Sse				return (cfgmech);
23026159Sse		}
23111524Sse	}
23210807Sse
23326159Sse	oldval2 = inb(CONF2_ENABLE_PORT);
23410887Sse
23511524Sse	if (bootverbose) {
23626159Sse		printf("pci_open(2):\tmode 2 enable port (0x0cf8) is 0x%02x\n",
23726159Sse		       oldval2);
23811524Sse	}
23910887Sse
24011524Sse	if ((oldval2 & 0xf0) == 0) {
24110887Sse
24226159Sse		cfgmech = 2;
24326159Sse		devmax = 16;
24426159Sse
24526159Sse		outb(CONF2_ENABLE_PORT, CONF2_ENABLE_CHK);
24611524Sse		mode2res = inb(CONF2_ENABLE_PORT);
24726159Sse		outb(CONF2_ENABLE_PORT, oldval2);
24811524Sse
24911524Sse		if (bootverbose)
25026159Sse			printf("pci_open(2a):\tmode2res=0x%02x (0x%02x)\n",
25126159Sse			       mode2res, CONF2_ENABLE_CHK);
25211524Sse
25311524Sse		if (mode2res == CONF2_ENABLE_RES) {
25426159Sse			if (bootverbose)
25526159Sse				printf("pci_open(2a):\tnow trying mechanism 2\n");
25611524Sse
25726159Sse			if (pci_cfgcheck(16))
25826159Sse				return (cfgmech);
25911524Sse		}
26011524Sse	}
26111524Sse
26226159Sse	cfgmech = 0;
26326159Sse	devmax = 0;
26426159Sse	return (cfgmech);
2656104Sse}
266