pci_pir.c revision 26173
143412Snewton/*
243412Snewton * Copyright (c) 1997, Stefan Esser <se@freebsd.org>
343412Snewton * All rights reserved.
443412Snewton *
543412Snewton * Redistribution and use in source and binary forms, with or without
643412Snewton * modification, are permitted provided that the following conditions
743412Snewton * are met:
843412Snewton * 1. Redistributions of source code must retain the above copyright
943412Snewton *    notice unmodified, this list of conditions, and the following
1043412Snewton *    disclaimer.
1143412Snewton * 2. Redistributions in binary form must reproduce the above copyright
1243412Snewton *    notice, this list of conditions and the following disclaimer in the
1343412Snewton *    documentation and/or other materials provided with the distribution.
1443412Snewton *
1543412Snewton * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
1643412Snewton * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
1743412Snewton * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
1843412Snewton * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
1943412Snewton * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
2043412Snewton * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
2143412Snewton * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
2243412Snewton * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
2343412Snewton * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
2443412Snewton * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
2543412Snewton *
2643412Snewton * $Id: pcibus.c,v 1.37 1997/05/26 21:11:05 se Exp $
2749267Snewton *
2850477Speter */
2943412Snewton
3043412Snewton#include <sys/types.h>
3143412Snewton#include <sys/systm.h>
3243412Snewton
3343412Snewton#include <pci/pcireg.h>
3443412Snewton#include <pci/pcivar.h>
3543412Snewton#include <i386/isa/pcibus.h>
3643412Snewton
3743412Snewton#ifdef PCI_COMPAT
3843412Snewton/* XXX this is a terrible hack, which keeps the Tekram AMD SCSI driver happy */
3943412Snewton#define cfgmech pci_mechanism
4043412Snewtonint cfgmech;
4143412Snewton#else
4243499Snewtonstatic int cfgmech;
4343412Snewton#endif /* PCI_COMPAT */
4443412Snewtonstatic int devmax;
4543412Snewton
4643412Snewton/* enable configuration space accesses and return data port address */
4743412Snewton
4843412Snewtonstatic int
4943412Snewtonpci_cfgenable(unsigned bus, unsigned slot, unsigned func, int reg, int bytes)
5043412Snewton{
5143412Snewton	int dataport = 0;
5243412Snewton
5343412Snewton	if (bus <= PCI_BUSMAX
5443412Snewton	    && slot < devmax
5543412Snewton	    && func <= PCI_FUNCMAX
5643412Snewton	    && reg <= PCI_REGMAX
5743412Snewton	    && bytes != 3
5843412Snewton	    && (unsigned) bytes <= 4
5943412Snewton	    && (reg & (bytes -1)) == 0) {
6043412Snewton		switch (cfgmech) {
6143412Snewton		case 1:
6243412Snewton			outl(CONF1_ADDR_PORT, (1 << 31) |
6343412Snewton			     (bus << 16) | (slot << 11) | (func << 8) | reg);
6443412Snewton			dataport = CONF1_DATA_PORT;
6565302Sobrien			break;
6665302Sobrien		case 2:
6765302Sobrien			outb(CONF2_ENABLE_PORT, 0xf0 | (func << 1));
6865302Sobrien			outb(CONF2_FORWARD_PORT, bus);
6965302Sobrien			dataport = 0xc000 | (slot << 8) | reg;
7065302Sobrien			break;
7165302Sobrien		}
7265302Sobrien	}
7365302Sobrien	return (dataport);
7465302Sobrien}
7565302Sobrien
7665302Sobrien/* disable configuration space accesses */
7765302Sobrien
7843412Snewtonstatic void
7943412Snewtonpci_cfgdisable(void)
8043412Snewton{
8143412Snewton	switch (cfgmech) {
8243412Snewton	case 1:
8371452Sjhb		outl(CONF1_ADDR_PORT, 0);
8471452Sjhb		break;
8571452Sjhb	case 2:
8643412Snewton		outb(CONF2_ENABLE_PORT, 0);
8743412Snewton		outb(CONF2_FORWARD_PORT, 0);
8843412Snewton		break;
8943412Snewton	}
9043412Snewton}
9143412Snewton
9243412Snewton/* read configuration space register */
9343412Snewton
9443412Snewtonint
9543412Snewtonpci_cfgread(pcicfgregs *cfg, int reg, int bytes)
9643412Snewton{
9743412Snewton	int data = -1;
9843412Snewton	int port;
9943412Snewton
10043412Snewton	port = pci_cfgenable(cfg->bus, cfg->slot, cfg->func, reg, bytes);
10143412Snewton
10243412Snewton	if (port != 0) {
10343412Snewton		switch (bytes) {
10443412Snewton		case 1:
10543412Snewton			data = inb(port);
10643412Snewton			break;
10743412Snewton		case 2:
10843412Snewton			data = inw(port);
10943412Snewton			break;
11043412Snewton		case 4:
11143412Snewton			data = inl(port);
11243412Snewton			break;
11343412Snewton		}
11443412Snewton		pci_cfgdisable();
11543412Snewton	}
11643412Snewton	return (data);
11743412Snewton}
11843412Snewton
11943412Snewton/* write configuration space register */
12043412Snewton
12143412Snewtonvoid
12243412Snewtonpci_cfgwrite(pcicfgregs *cfg, int reg, int data, int bytes)
12343412Snewton{
12443412Snewton	int port;
12543412Snewton
12643412Snewton	port = pci_cfgenable(cfg->bus, cfg->slot, cfg->func, reg, bytes);
12743412Snewton	if (port != 0) {
12843412Snewton		switch (bytes) {
12943412Snewton		case 1:
13043412Snewton			outb(port, data);
13143412Snewton			break;
13243412Snewton		case 2:
13343412Snewton			outw(port, data);
13443412Snewton			break;
13543412Snewton		case 4:
13643412Snewton			outl(port, data);
13743412Snewton			break;
13843412Snewton		}
13943412Snewton		pci_cfgdisable();
14043412Snewton	}
14143412Snewton}
14243412Snewton
14343412Snewton/* check whether the configuration mechanism has been correct identified */
14443412Snewton
14543412Snewtonstatic int
14643412Snewtonpci_cfgcheck(int maxdev)
14743412Snewton{
14843412Snewton	u_char device;
14943412Snewton
15043412Snewton	if (bootverbose)
15143412Snewton		printf("pci_cfgcheck:\tdevice ");
15243412Snewton
15351793Smarcel	for (device = 0; device < maxdev; device++) {
15443412Snewton		unsigned id, class, header;
15543412Snewton		if (bootverbose)
15643412Snewton			printf("%d ", device);
15751793Smarcel
15843412Snewton		id = inl(pci_cfgenable(0, device, 0, 0, 4));
15943412Snewton		if (id == 0 || id == -1)
16043412Snewton			continue;
16143412Snewton
16243412Snewton		class = inl(pci_cfgenable(0, device, 0, 8, 4)) >> 8;
16343412Snewton		if (bootverbose)
16443412Snewton			printf("[class=%06x] ", class);
16543412Snewton		if (class == 0 || (class & 0xf8f0ff) != 0)
16643412Snewton			continue;
16743412Snewton
16843412Snewton		header = inb(pci_cfgenable(0, device, 0, 14, 1));
16943412Snewton		if (bootverbose)
17043412Snewton			printf("[hdr=%02x] ", header);
17143412Snewton		if ((header & 0x7e) != 0)
17243412Snewton			continue;
17343412Snewton
17443412Snewton		if (bootverbose)
17543412Snewton			printf("is there (id=%08x)\n", id);
17643412Snewton
17743412Snewton		pci_cfgdisable();
17843412Snewton		return (1);
17943412Snewton	}
18043412Snewton	if (bootverbose)
18143412Snewton		printf("-- nothing found\n");
18243412Snewton
18343412Snewton	pci_cfgdisable();
18443412Snewton	return (0);
18543412Snewton}
18643412Snewton
18743412Snewtonint
18843412Snewtonpci_cfgopen(void)
18943412Snewton{
19043412Snewton	unsigned long mode1res,oldval1;
19143412Snewton	unsigned char mode2res,oldval2;
19243412Snewton
19343412Snewton	oldval1 = inl(CONF1_ADDR_PORT);
19443412Snewton
19543412Snewton	if (bootverbose) {
19643412Snewton		printf("pci_open(1):\tmode 1 addr port (0x0cf8) is 0x%08lx\n",
19743412Snewton		       oldval1);
19843412Snewton	}
19943412Snewton
20043412Snewton	if ((oldval1 & CONF1_ENABLE_MSK) == 0) {
20143412Snewton
20243412Snewton		cfgmech = 1;
20343412Snewton		devmax = 32;
20443412Snewton
20543412Snewton		outl(CONF1_ADDR_PORT, CONF1_ENABLE_CHK);
20643412Snewton		outb(CONF1_ADDR_PORT +3, 0);
20743412Snewton		mode1res = inl(CONF1_ADDR_PORT);
20843412Snewton		outl(CONF1_ADDR_PORT, oldval1);
20943412Snewton
21043412Snewton		if (bootverbose)
21143412Snewton			printf("pci_open(1a):\tmode1res=0x%08lx (0x%08lx)\n",
21243412Snewton			       mode1res, CONF1_ENABLE_CHK);
21343412Snewton
21443412Snewton		if (mode1res) {
21543412Snewton			if (pci_cfgcheck(32))
21643412Snewton				return (cfgmech);
21743412Snewton		}
21843412Snewton
21943412Snewton		outl(CONF1_ADDR_PORT, CONF1_ENABLE_CHK1);
22043412Snewton		mode1res = inl(CONF1_ADDR_PORT);
22143412Snewton		outl(CONF1_ADDR_PORT, oldval1);
22243412Snewton
22343412Snewton		if (bootverbose)
22443412Snewton			printf("pci_open(1b):\tmode1res=0x%08lx (0x%08lx)\n",
22543412Snewton			       mode1res, CONF1_ENABLE_CHK1);
22643412Snewton
22743412Snewton		if ((mode1res & CONF1_ENABLE_MSK1) == CONF1_ENABLE_RES1) {
22843412Snewton			if (pci_cfgcheck(32))
22943412Snewton				return (cfgmech);
23054494Snewton		}
23143412Snewton	}
23254494Snewton
23354494Snewton	oldval2 = inb(CONF2_ENABLE_PORT);
23454494Snewton
23543412Snewton	if (bootverbose) {
23643412Snewton		printf("pci_open(2):\tmode 2 enable port (0x0cf8) is 0x%02x\n",
23743412Snewton		       oldval2);
23843412Snewton	}
23943412Snewton
24043412Snewton	if ((oldval2 & 0xf0) == 0) {
24154494Snewton
24243412Snewton		cfgmech = 2;
24354494Snewton		devmax = 16;
24454494Snewton
24554494Snewton		outb(CONF2_ENABLE_PORT, CONF2_ENABLE_CHK);
24654494Snewton		mode2res = inb(CONF2_ENABLE_PORT);
24743412Snewton		outb(CONF2_ENABLE_PORT, oldval2);
24843412Snewton
24943412Snewton		if (bootverbose)
25054494Snewton			printf("pci_open(2a):\tmode2res=0x%02x (0x%02x)\n",
25171452Sjhb			       mode2res, CONF2_ENABLE_CHK);
25254494Snewton
25354494Snewton		if (mode2res == CONF2_ENABLE_RES) {
25454494Snewton			if (bootverbose)
25554494Snewton				printf("pci_open(2a):\tnow trying mechanism 2\n");
25654494Snewton
25743412Snewton			if (pci_cfgcheck(16))
25854494Snewton				return (cfgmech);
25954494Snewton		}
26054494Snewton	}
26143412Snewton
26254494Snewton	cfgmech = 0;
26343412Snewton	devmax = 0;
26443412Snewton	return (cfgmech);
26543412Snewton}
26643412Snewton