pci_cfgreg.c revision 26173
15897Sjmz/*
25897Sjmz * Copyright (c) 1997, Stefan Esser <se@freebsd.org>
35897Sjmz * All rights reserved.
45897Sjmz *
55897Sjmz * Redistribution and use in source and binary forms, with or without
65897Sjmz * modification, are permitted provided that the following conditions
75897Sjmz * are met:
85897Sjmz * 1. Redistributions of source code must retain the above copyright
95897Sjmz *    notice unmodified, this list of conditions, and the following
105897Sjmz *    disclaimer.
115897Sjmz * 2. Redistributions in binary form must reproduce the above copyright
125897Sjmz *    notice, this list of conditions and the following disclaimer in the
135897Sjmz *    documentation and/or other materials provided with the distribution.
145897Sjmz *
1597748Sschweikh * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
165897Sjmz * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
175897Sjmz * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
185897Sjmz * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
195897Sjmz * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
205897Sjmz * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
215897Sjmz * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
225897Sjmz * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
235897Sjmz * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
245897Sjmz * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
255897Sjmz *
265897Sjmz * $Id: pcibus.c,v 1.37 1997/05/26 21:11:05 se Exp $
275897Sjmz *
285897Sjmz */
295897Sjmz
30119418Sobrien#include <sys/types.h>
31119418Sobrien#include <sys/systm.h>
32119418Sobrien
337430Sbde#include <pci/pcireg.h>
347430Sbde#include <pci/pcivar.h>
3512675Sjulian#include <i386/isa/pcibus.h>
3634924Sbde
3754156Speter#ifdef PCI_COMPAT
3854156Speter/* XXX this is a terrible hack, which keeps the Tekram AMD SCSI driver happy */
3954156Speter#define cfgmech pci_mechanism
4054156Speterint cfgmech;
4154156Speter#else
4254156Speterstatic int cfgmech;
4354156Speter#endif /* PCI_COMPAT */
4454156Speterstatic int devmax;
4587384Simp
466734Sbde/* enable configuration space accesses and return data port address */
478876Srgrimes
485897Sjmzstatic int
495897Sjmzpci_cfgenable(unsigned bus, unsigned slot, unsigned func, int reg, int bytes)
505897Sjmz{
515897Sjmz	int dataport = 0;
525897Sjmz
535897Sjmz	if (bus <= PCI_BUSMAX
545897Sjmz	    && slot < devmax
555897Sjmz	    && func <= PCI_FUNCMAX
565897Sjmz	    && reg <= PCI_REGMAX
57183397Sed	    && bytes != 3
585897Sjmz	    && (unsigned) bytes <= 4
595897Sjmz	    && (reg & (bytes -1)) == 0) {
605897Sjmz		switch (cfgmech) {
615897Sjmz		case 1:
6212675Sjulian			outl(CONF1_ADDR_PORT, (1 << 31) |
6312675Sjulian			     (bus << 16) | (slot << 11) | (func << 8) | reg);
6412675Sjulian			dataport = CONF1_DATA_PORT;
6512675Sjulian			break;
6612675Sjulian		case 2:
6747625Sphk			outb(CONF2_ENABLE_PORT, 0xf0 | (func << 1));
68126080Sphk			outb(CONF2_FORWARD_PORT, bus);
69126080Sphk			dataport = 0xc000 | (slot << 8) | reg;
70111815Sphk			break;
71111815Sphk		}
72111815Sphk	}
73111815Sphk	return (dataport);
74111815Sphk}
7547625Sphk
7612675Sjulian/* disable configuration space accesses */
7789086Simp
785897Sjmzstatic void
7987384Simppci_cfgdisable(void)
8087384Simp{
815897Sjmz	switch (cfgmech) {
825897Sjmz	case 1:
8354156Speter		outl(CONF1_ADDR_PORT, 0);
8487384Simp		break;
8587384Simp	case 2:
8687384Simp		outb(CONF2_ENABLE_PORT, 0);
8787384Simp		outb(CONF2_FORWARD_PORT, 0);
8887384Simp		break;
8954156Speter	}
905897Sjmz}
9187384Simp
925897Sjmz/* read configuration space register */
935897Sjmz
945897Sjmzint
9587384Simppci_cfgread(pcicfgregs *cfg, int reg, int bytes)
9687384Simp{
975897Sjmz	int data = -1;
9887384Simp	int port;
9987384Simp
1005897Sjmz	port = pci_cfgenable(cfg->bus, cfg->slot, cfg->func, reg, bytes);
10187384Simp
102127135Snjl	if (port != 0) {
103152249Sjylefort		switch (bytes) {
10487384Simp		case 1:
10587384Simp			data = inb(port);
10687384Simp			break;
10787384Simp		case 2:
10887384Simp			data = inw(port);
109152249Sjylefort			break;
110191054Sed		case 4:
11187384Simp			data = inl(port);
1125897Sjmz			break;
1135897Sjmz		}
11487384Simp		pci_cfgdisable();
11587384Simp	}
11687384Simp	return (data);
11787384Simp}
11854156Speter
11987384Simp/* write configuration space register */
12087384Simp
12187384Simpvoid
12287384Simppci_cfgwrite(pcicfgregs *cfg, int reg, int data, int bytes)
12387384Simp{
12487384Simp	int port;
12554156Speter
12654156Speter	port = pci_cfgenable(cfg->bus, cfg->slot, cfg->func, reg, bytes);
12754156Speter	if (port != 0) {
128130585Sphk		switch (bytes) {
1295897Sjmz		case 1:
13087384Simp			outb(port, data);
131191054Sed			break;
1325897Sjmz		case 2:
13387384Simp			outw(port, data);
13487384Simp			break;
13587384Simp		case 4:
13687384Simp			outl(port, data);
13787384Simp			break;
1385897Sjmz		}
13954156Speter		pci_cfgdisable();
14054156Speter	}
141130585Sphk}
1425897Sjmz
14387384Simp/* check whether the configuration mechanism has been correct identified */
144191054Sed
1455897Sjmzstatic int
14687384Simppci_cfgcheck(int maxdev)
14787384Simp{
1485897Sjmz	u_char device;
1495897Sjmz
15054156Speter	if (bootverbose)
151130585Sphk		printf("pci_cfgcheck:\tdevice ");
1525897Sjmz
153191054Sed	for (device = 0; device < maxdev; device++) {
15487384Simp		unsigned id, class, header;
15587384Simp		if (bootverbose)
15687384Simp			printf("%d ", device);
15787384Simp
15887384Simp		id = inl(pci_cfgenable(0, device, 0, 0, 4));
15987384Simp		if (id == 0 || id == -1)
16097554Salfred			continue;
16187384Simp
1628876Srgrimes		class = inl(pci_cfgenable(0, device, 0, 8, 4)) >> 8;
16387384Simp		if (bootverbose)
16454156Speter			printf("[class=%06x] ", class);
16587384Simp		if (class == 0 || (class & 0xf8f0ff) != 0)
16654156Speter			continue;
167152249Sjylefort
168152249Sjylefort		header = inb(pci_cfgenable(0, device, 0, 14, 1));
169152249Sjylefort		if (bootverbose)
170152249Sjylefort			printf("[hdr=%02x] ", header);
171152249Sjylefort		if ((header & 0x7e) != 0)
172152249Sjylefort			continue;
17387384Simp
17487384Simp		if (bootverbose)
17587384Simp			printf("is there (id=%08x)\n", id);
17687384Simp
17787384Simp		pci_cfgdisable();
17887384Simp		return (1);
17987384Simp	}
18087384Simp	if (bootverbose)
18187384Simp		printf("-- nothing found\n");
18287384Simp
18387384Simp	pci_cfgdisable();
18487384Simp	return (0);
18587384Simp}
18687384Simp
18787384Simpint
18887384Simppci_cfgopen(void)
18987384Simp{
19087384Simp	unsigned long mode1res,oldval1;
19187384Simp	unsigned char mode2res,oldval2;
19287384Simp
19397554Salfred	oldval1 = inl(CONF1_ADDR_PORT);
19487384Simp
19554156Speter	if (bootverbose) {
19687384Simp		printf("pci_open(1):\tmode 1 addr port (0x0cf8) is 0x%08lx\n",
19754156Speter		       oldval1);
19887384Simp	}
19987384Simp
20087384Simp	if ((oldval1 & CONF1_ENABLE_MSK) == 0) {
20187384Simp
20287384Simp		cfgmech = 1;
20387384Simp		devmax = 32;
20487384Simp
20587384Simp		outl(CONF1_ADDR_PORT, CONF1_ENABLE_CHK);
20687384Simp		outb(CONF1_ADDR_PORT +3, 0);
20787384Simp		mode1res = inl(CONF1_ADDR_PORT);
20887384Simp		outl(CONF1_ADDR_PORT, oldval1);
20987384Simp
21087384Simp		if (bootverbose)
21187384Simp			printf("pci_open(1a):\tmode1res=0x%08lx (0x%08lx)\n",
2125897Sjmz			       mode1res, CONF1_ENABLE_CHK);
21312675Sjulian
21454156Speter		if (mode1res) {
215130585Sphk			if (pci_cfgcheck(32))
2165897Sjmz				return (cfgmech);
217191054Sed		}
21887384Simp
21987384Simp		outl(CONF1_ADDR_PORT, CONF1_ENABLE_CHK1);
2205897Sjmz		mode1res = inl(CONF1_ADDR_PORT);
22187384Simp		outl(CONF1_ADDR_PORT, oldval1);
22287384Simp
22387384Simp		if (bootverbose)
22487384Simp			printf("pci_open(1b):\tmode1res=0x%08lx (0x%08lx)\n",
22587384Simp			       mode1res, CONF1_ENABLE_CHK1);
22687384Simp
22787384Simp		if ((mode1res & CONF1_ENABLE_MSK1) == CONF1_ENABLE_RES1) {
22887384Simp			if (pci_cfgcheck(32))
22987384Simp				return (cfgmech);
23087384Simp		}
23187384Simp	}
23287384Simp
23387384Simp	oldval2 = inb(CONF2_ENABLE_PORT);
23487384Simp
23587384Simp	if (bootverbose) {
23687384Simp		printf("pci_open(2):\tmode 2 enable port (0x0cf8) is 0x%02x\n",
23787384Simp		       oldval2);
23887384Simp	}
23987384Simp
24087384Simp	if ((oldval2 & 0xf0) == 0) {
24187384Simp
24287384Simp		cfgmech = 2;
24387384Simp		devmax = 16;
24487384Simp
24587384Simp		outb(CONF2_ENABLE_PORT, CONF2_ENABLE_CHK);
24687384Simp		mode2res = inb(CONF2_ENABLE_PORT);
2475897Sjmz		outb(CONF2_ENABLE_PORT, oldval2);
248
249		if (bootverbose)
250			printf("pci_open(2a):\tmode2res=0x%02x (0x%02x)\n",
251			       mode2res, CONF2_ENABLE_CHK);
252
253		if (mode2res == CONF2_ENABLE_RES) {
254			if (bootverbose)
255				printf("pci_open(2a):\tnow trying mechanism 2\n");
256
257			if (pci_cfgcheck(16))
258				return (cfgmech);
259		}
260	}
261
262	cfgmech = 0;
263	devmax = 0;
264	return (cfgmech);
265}
266