xref: /freebsd/sys/i386/pci/pci_cfgreg.c (revision 81cf5d7aaef6238a23cf7f1caaeaeb3778bb0326)
1ac19f918SStefan Eßer /**************************************************************************
2ac19f918SStefan Eßer **
381cf5d7aSStefan Eßer **  $Id: pcibus.c,v 1.31 1997/02/22 09:36:58 peter Exp $
4ac19f918SStefan Eßer **
5ac19f918SStefan Eßer **  pci bus subroutines for i386 architecture.
6ac19f918SStefan Eßer **
7ac19f918SStefan Eßer **  FreeBSD
8ac19f918SStefan Eßer **
9ac19f918SStefan Eßer **-------------------------------------------------------------------------
10ac19f918SStefan Eßer **
11ac19f918SStefan Eßer ** Copyright (c) 1994 Wolfgang Stanglmeier.  All rights reserved.
12ac19f918SStefan Eßer **
13ac19f918SStefan Eßer ** Redistribution and use in source and binary forms, with or without
14ac19f918SStefan Eßer ** modification, are permitted provided that the following conditions
15ac19f918SStefan Eßer ** are met:
16ac19f918SStefan Eßer ** 1. Redistributions of source code must retain the above copyright
17ac19f918SStefan Eßer **    notice, this list of conditions and the following disclaimer.
18ac19f918SStefan Eßer ** 2. Redistributions in binary form must reproduce the above copyright
19ac19f918SStefan Eßer **    notice, this list of conditions and the following disclaimer in the
20ac19f918SStefan Eßer **    documentation and/or other materials provided with the distribution.
21ac19f918SStefan Eßer ** 3. The name of the author may not be used to endorse or promote products
22ac19f918SStefan Eßer **    derived from this software without specific prior written permission.
23ac19f918SStefan Eßer **
24ac19f918SStefan Eßer ** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
25ac19f918SStefan Eßer ** IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
26ac19f918SStefan Eßer ** OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
27ac19f918SStefan Eßer ** IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
28ac19f918SStefan Eßer ** INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
29ac19f918SStefan Eßer ** NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
30ac19f918SStefan Eßer ** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
31ac19f918SStefan Eßer ** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
32ac19f918SStefan Eßer ** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
33ac19f918SStefan Eßer ** THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
34ac19f918SStefan Eßer **
35ac19f918SStefan Eßer ***************************************************************************
36ac19f918SStefan Eßer */
37ac19f918SStefan Eßer 
38a680ab75SBruce Evans #include "vector.h"
39a680ab75SBruce Evans 
40550f8550SBruce Evans #include <sys/param.h>
41550f8550SBruce Evans #include <sys/systm.h>
42550f8550SBruce Evans #include <sys/kernel.h>
43550f8550SBruce Evans 
44550f8550SBruce Evans #include <i386/isa/icu.h>
45ac19f918SStefan Eßer #include <i386/isa/isa_device.h>
46ac19f918SStefan Eßer 
47ac19f918SStefan Eßer #include <pci/pcivar.h>
48ac19f918SStefan Eßer #include <pci/pcireg.h>
49ac19f918SStefan Eßer #include <pci/pcibus.h>
50ac19f918SStefan Eßer 
51ac19f918SStefan Eßer /*-----------------------------------------------------------------
52ac19f918SStefan Eßer **
53ac19f918SStefan Eßer **	The following functions are provided by the pci bios.
54ac19f918SStefan Eßer **	They are used only by the pci configuration.
55ac19f918SStefan Eßer **
565b3f532eSStefan Eßer **	pcibus_setup():
57ac19f918SStefan Eßer **		Probes for a pci system.
585b3f532eSStefan Eßer **		Sets pci_maxdevice and pci_mechanism.
59ac19f918SStefan Eßer **
60ac19f918SStefan Eßer **	pcibus_tag():
615b3f532eSStefan Eßer **		Creates a handle for pci configuration space access.
625b3f532eSStefan Eßer **		This handle is given to the read/write functions.
635b3f532eSStefan Eßer **
645b3f532eSStefan Eßer **	pcibus_ftag():
655b3f532eSStefan Eßer **		Creates a modified handle.
66ac19f918SStefan Eßer **
67ac19f918SStefan Eßer **	pcibus_read():
68ac19f918SStefan Eßer **		Read a long word from the pci configuration space.
69ac19f918SStefan Eßer **		Requires a tag (from pcitag) and the register
70ac19f918SStefan Eßer **		number (should be a long word alligned one).
71ac19f918SStefan Eßer **
72ac19f918SStefan Eßer **	pcibus_write():
73ac19f918SStefan Eßer **		Writes a long word to the pci configuration space.
74ac19f918SStefan Eßer **		Requires a tag (from pcitag), the register number
75ac19f918SStefan Eßer **		(should be a long word alligned one), and a value.
76ac19f918SStefan Eßer **
77ac19f918SStefan Eßer **	pcibus_regirq():
78ac19f918SStefan Eßer **		Register an interupt handler for a pci device.
79ac19f918SStefan Eßer **		Requires a tag (from pcitag), the register number
80ac19f918SStefan Eßer **		(should be a long word alligned one), and a value.
81ac19f918SStefan Eßer **
82ac19f918SStefan Eßer **-----------------------------------------------------------------
83ac19f918SStefan Eßer */
84ac19f918SStefan Eßer 
85a3adc4f8SStefan Eßer static int
86a3adc4f8SStefan Eßer pcibus_check (void);
87a3adc4f8SStefan Eßer 
885b3f532eSStefan Eßer static void
895b3f532eSStefan Eßer pcibus_setup (void);
90ac19f918SStefan Eßer 
91ac19f918SStefan Eßer static pcici_t
92ac19f918SStefan Eßer pcibus_tag (u_char bus, u_char device, u_char func);
93ac19f918SStefan Eßer 
945b3f532eSStefan Eßer static pcici_t
955b3f532eSStefan Eßer pcibus_ftag (pcici_t tag, u_char func);
965b3f532eSStefan Eßer 
97ac19f918SStefan Eßer static u_long
98ac19f918SStefan Eßer pcibus_read (pcici_t tag, u_long reg);
99ac19f918SStefan Eßer 
100ac19f918SStefan Eßer static void
101ac19f918SStefan Eßer pcibus_write (pcici_t tag, u_long reg, u_long data);
102ac19f918SStefan Eßer 
103ac19f918SStefan Eßer static int
1046ea3e9d8SBruce Evans pcibus_ihandler_attach (int irq, inthand2_t *func, int arg, unsigned* maskptr);
1055b3f532eSStefan Eßer 
1065b3f532eSStefan Eßer static int
1076ea3e9d8SBruce Evans pcibus_ihandler_detach (int irq, inthand2_t *func);
1085b3f532eSStefan Eßer 
1095b3f532eSStefan Eßer static int
1105b3f532eSStefan Eßer pcibus_imask_include (int irq, unsigned* maskptr);
1115b3f532eSStefan Eßer 
1125b3f532eSStefan Eßer static int
1135b3f532eSStefan Eßer pcibus_imask_exclude (int irq, unsigned* maskptr);
114ac19f918SStefan Eßer 
1156f4e0bebSPoul-Henning Kamp static struct pcibus i386pci = {
116ac19f918SStefan Eßer 	"pci",
1175b3f532eSStefan Eßer 	pcibus_setup,
118ac19f918SStefan Eßer 	pcibus_tag,
1195b3f532eSStefan Eßer 	pcibus_ftag,
120ac19f918SStefan Eßer 	pcibus_read,
121ac19f918SStefan Eßer 	pcibus_write,
1225b3f532eSStefan Eßer 	pcibus_ihandler_attach,
1235b3f532eSStefan Eßer 	pcibus_ihandler_detach,
1245b3f532eSStefan Eßer 	pcibus_imask_include,
1255b3f532eSStefan Eßer 	pcibus_imask_exclude,
126ac19f918SStefan Eßer };
127ac19f918SStefan Eßer 
128ac19f918SStefan Eßer /*
129ac19f918SStefan Eßer **	Announce structure to generic driver
130ac19f918SStefan Eßer */
131ac19f918SStefan Eßer 
132ac19f918SStefan Eßer DATA_SET (pcibus_set, i386pci);
133ac19f918SStefan Eßer 
134ac19f918SStefan Eßer /*--------------------------------------------------------------------
135ac19f918SStefan Eßer **
136ac19f918SStefan Eßer **      Determine configuration mode
137ac19f918SStefan Eßer **
138ac19f918SStefan Eßer **--------------------------------------------------------------------
139ac19f918SStefan Eßer */
140ac19f918SStefan Eßer 
141ac19f918SStefan Eßer 
142ac19f918SStefan Eßer #define CONF1_ADDR_PORT    0x0cf8
143ac19f918SStefan Eßer #define CONF1_DATA_PORT    0x0cfc
144ac19f918SStefan Eßer 
1452d144186SStefan Eßer #define CONF1_ENABLE       0x80000000ul
14677b57314SStefan Eßer #define CONF1_ENABLE_CHK   0x80000000ul
14721219d21SStefan Eßer #define CONF1_ENABLE_MSK   0x7ff00000ul
1480e2f699bSStefan Eßer #define CONF1_ENABLE_CHK1  0xff000001ul
149287911bdSStefan Eßer #define CONF1_ENABLE_MSK1  0x80000001ul
150a3adc4f8SStefan Eßer #define CONF1_ENABLE_RES1  0x80000000ul
151ac19f918SStefan Eßer 
152ac19f918SStefan Eßer #define CONF2_ENABLE_PORT  0x0cf8
153e30f0011SSatoshi Asami #ifdef PC98
154e30f0011SSatoshi Asami #define CONF2_FORWARD_PORT 0x0cf9
155e30f0011SSatoshi Asami #else
156ac19f918SStefan Eßer #define CONF2_FORWARD_PORT 0x0cfa
157e30f0011SSatoshi Asami #endif
158ac19f918SStefan Eßer 
1592d144186SStefan Eßer #define CONF2_ENABLE_CHK   0x0e
1602d144186SStefan Eßer #define CONF2_ENABLE_RES   0x0e
161ac19f918SStefan Eßer 
162a3adc4f8SStefan Eßer static int
163a3adc4f8SStefan Eßer pcibus_check (void)
164a3adc4f8SStefan Eßer {
165a3adc4f8SStefan Eßer 	u_char device;
166a3adc4f8SStefan Eßer 
16777b57314SStefan Eßer 	if (bootverbose) printf ("pcibus_check:\tdevice ");
16877b57314SStefan Eßer 
169a3adc4f8SStefan Eßer 	for (device = 0; device < pci_maxdevice; device++) {
17081cf5d7aSStefan Eßer 		unsigned long id, class, header;
171c7483249SStefan Eßer 		if (bootverbose)
172c7483249SStefan Eßer 			printf ("%d ", device);
173c7483249SStefan Eßer 		id = pcibus_read (pcibus_tag (0,device,0), 0);
17481cf5d7aSStefan Eßer 		if ((id == 0) || (id == 0xfffffffful))
17581cf5d7aSStefan Eßer 			continue;
17681cf5d7aSStefan Eßer 
17781cf5d7aSStefan Eßer 		class = pcibus_read (pcibus_tag (0,device,0), 8);
17881cf5d7aSStefan Eßer 		if (bootverbose)
17981cf5d7aSStefan Eßer 			printf ("[class=%x] ", class >> 8);
18081cf5d7aSStefan Eßer 		if ((class & 0xfff0ff00) != 0x06000000)
18181cf5d7aSStefan Eßer 			continue;
18281cf5d7aSStefan Eßer 
18381cf5d7aSStefan Eßer 		header = pcibus_read (pcibus_tag (0,device,0), 12);
18481cf5d7aSStefan Eßer 		if (bootverbose)
18581cf5d7aSStefan Eßer 			printf ("[hdr=%x] ", (header >> 16) & 0xff);
18681cf5d7aSStefan Eßer 		if ((header & 0x007e0000) != 0)
18781cf5d7aSStefan Eßer 			continue;
18881cf5d7aSStefan Eßer 
189c7483249SStefan Eßer 		if (bootverbose) printf ("is there (id=%08lx)\n", id);
190a3adc4f8SStefan Eßer 		return 1;
191a3adc4f8SStefan Eßer 	}
192c7483249SStefan Eßer 	if (bootverbose)
193c7483249SStefan Eßer 		printf ("-- nothing found\n");
194a3adc4f8SStefan Eßer 	return 0;
195a3adc4f8SStefan Eßer }
196d7ea35fcSStefan Eßer 
1975b3f532eSStefan Eßer static void
1985b3f532eSStefan Eßer pcibus_setup (void)
199ac19f918SStefan Eßer {
200287911bdSStefan Eßer 	unsigned long mode1res,oldval1;
201287911bdSStefan Eßer 	unsigned char mode2res,oldval2;
2020847c06dSStefan Eßer 
203287911bdSStefan Eßer 	oldval1 = inl (CONF1_ADDR_PORT);
204a3adc4f8SStefan Eßer 
20577b57314SStefan Eßer 	if (bootverbose) {
206287911bdSStefan Eßer 		printf ("pcibus_setup(1):\tmode 1 addr port (0x0cf8) is 0x%08lx\n", oldval1);
207a3adc4f8SStefan Eßer 	}
208a3adc4f8SStefan Eßer 
209ac19f918SStefan Eßer 	/*---------------------------------------
21077b57314SStefan Eßer 	**      Assume configuration mechanism 1 for now ...
21177b57314SStefan Eßer 	**---------------------------------------
21277b57314SStefan Eßer 	*/
21377b57314SStefan Eßer 
2140e2f699bSStefan Eßer 	if ((oldval1 & CONF1_ENABLE_MSK) == 0) {
215287911bdSStefan Eßer 
21677b57314SStefan Eßer 		pci_mechanism = 1;
21777b57314SStefan Eßer 		pci_maxdevice = 32;
21877b57314SStefan Eßer 
21977b57314SStefan Eßer 		outl (CONF1_ADDR_PORT, CONF1_ENABLE_CHK);
22077b57314SStefan Eßer 		outb (CONF1_ADDR_PORT +3, 0);
22177b57314SStefan Eßer 		mode1res = inl (CONF1_ADDR_PORT);
222287911bdSStefan Eßer 		outl (CONF1_ADDR_PORT, oldval1);
22377b57314SStefan Eßer 
22477b57314SStefan Eßer 		if (bootverbose)
225287911bdSStefan Eßer 		    printf ("pcibus_setup(1a):\tmode1res=0x%08lx (0x%08lx)\n",
22677b57314SStefan Eßer 			    mode1res, CONF1_ENABLE_CHK);
22777b57314SStefan Eßer 
22877b57314SStefan Eßer 		if (mode1res) {
22977b57314SStefan Eßer 			if (pcibus_check())
23077b57314SStefan Eßer 				return;
23177b57314SStefan Eßer 		};
23277b57314SStefan Eßer 
23377b57314SStefan Eßer 		outl (CONF1_ADDR_PORT, CONF1_ENABLE_CHK1);
23477b57314SStefan Eßer 		mode1res = inl(CONF1_ADDR_PORT);
235287911bdSStefan Eßer 		outl (CONF1_ADDR_PORT, oldval1);
23677b57314SStefan Eßer 
23777b57314SStefan Eßer 		if (bootverbose)
238287911bdSStefan Eßer 		    printf ("pcibus_setup(1b):\tmode1res=0x%08lx (0x%08lx)\n",
23977b57314SStefan Eßer 			    mode1res, CONF1_ENABLE_CHK1);
24077b57314SStefan Eßer 
241c7483249SStefan Eßer 		if ((mode1res & CONF1_ENABLE_MSK1) == CONF1_ENABLE_RES1) {
24277b57314SStefan Eßer 			if (pcibus_check())
24377b57314SStefan Eßer 				return;
24477b57314SStefan Eßer 		};
245287911bdSStefan Eßer 	}
24677b57314SStefan Eßer 
24777b57314SStefan Eßer 	/*---------------------------------------
24877b57314SStefan Eßer 	**      Try configuration mechanism 2 ...
24977b57314SStefan Eßer 	**---------------------------------------
25077b57314SStefan Eßer 	*/
25177b57314SStefan Eßer 
252287911bdSStefan Eßer 	oldval2 = inb (CONF2_ENABLE_PORT);
253287911bdSStefan Eßer 
254287911bdSStefan Eßer 	if (bootverbose) {
255287911bdSStefan Eßer 		printf ("pcibus_setup(2):\tmode 2 enable port (0x0cf8) is 0x%02x\n", oldval2);
256287911bdSStefan Eßer 	}
257287911bdSStefan Eßer 
258287911bdSStefan Eßer 	if ((oldval2 & 0xf0) == 0) {
259c7483249SStefan Eßer 
26077b57314SStefan Eßer 		pci_mechanism = 2;
26177b57314SStefan Eßer 		pci_maxdevice = 16;
26277b57314SStefan Eßer 
263287911bdSStefan Eßer 		outb (CONF2_ENABLE_PORT, CONF2_ENABLE_CHK);
264287911bdSStefan Eßer 		mode2res = inb(CONF2_ENABLE_PORT);
265287911bdSStefan Eßer 		outb (CONF2_ENABLE_PORT, oldval2);
266287911bdSStefan Eßer 
267287911bdSStefan Eßer 		if (bootverbose)
268287911bdSStefan Eßer 		    printf ("pcibus_setup(2a):\tmode2res=0x%02x (0x%02x)\n",
269287911bdSStefan Eßer 			    mode2res, CONF2_ENABLE_CHK);
270287911bdSStefan Eßer 
271287911bdSStefan Eßer 		if (mode2res == CONF2_ENABLE_RES) {
272287911bdSStefan Eßer 		    if (bootverbose)
273287911bdSStefan Eßer 			printf ("pcibus_setup(2a):\tnow trying mechanism 2\n");
274287911bdSStefan Eßer 
27577b57314SStefan Eßer 			if (pcibus_check())
27677b57314SStefan Eßer 				return;
277287911bdSStefan Eßer 		}
278287911bdSStefan Eßer 	}
27977b57314SStefan Eßer 
28077b57314SStefan Eßer 	/*---------------------------------------
281cda67911SStefan Eßer 	**      No PCI bus host bridge found
282ac19f918SStefan Eßer 	**---------------------------------------
283ac19f918SStefan Eßer 	*/
284cda67911SStefan Eßer 
285cda67911SStefan Eßer 	pci_mechanism = 0;
286cda67911SStefan Eßer 	pci_maxdevice = 0;
287ac19f918SStefan Eßer }
2885b3f532eSStefan Eßer 
289ac19f918SStefan Eßer /*--------------------------------------------------------------------
290ac19f918SStefan Eßer **
291ac19f918SStefan Eßer **      Build a pcitag from bus, device and function number
292ac19f918SStefan Eßer **
293ac19f918SStefan Eßer **--------------------------------------------------------------------
294ac19f918SStefan Eßer */
295ac19f918SStefan Eßer 
296ac19f918SStefan Eßer static pcici_t
297ac19f918SStefan Eßer pcibus_tag (unsigned char bus, unsigned char device, unsigned char func)
298ac19f918SStefan Eßer {
299ac19f918SStefan Eßer 	pcici_t tag;
300ac19f918SStefan Eßer 
301ac19f918SStefan Eßer 	tag.cfg1 = 0;
302ac19f918SStefan Eßer 	if (func   >=  8) return tag;
303ac19f918SStefan Eßer 
3045b3f532eSStefan Eßer 	switch (pci_mechanism) {
305ac19f918SStefan Eßer 
306ac19f918SStefan Eßer 	case 1:
3072d144186SStefan Eßer 		if (device < 32) {
308ac19f918SStefan Eßer 			tag.cfg1 = CONF1_ENABLE
309ac19f918SStefan Eßer 				| (((u_long) bus   ) << 16ul)
310ac19f918SStefan Eßer 				| (((u_long) device) << 11ul)
311ac19f918SStefan Eßer 				| (((u_long) func  ) <<  8ul);
3122d144186SStefan Eßer 		}
313ac19f918SStefan Eßer 		break;
314ac19f918SStefan Eßer 	case 2:
3152d144186SStefan Eßer 		if (device < 16) {
316ac19f918SStefan Eßer 			tag.cfg2.port    = 0xc000 | (device << 8ul);
3172d144186SStefan Eßer 			tag.cfg2.enable  = 0xf0 | (func << 1ul);
318ac19f918SStefan Eßer 			tag.cfg2.forward = bus;
3192d144186SStefan Eßer 		}
320ac19f918SStefan Eßer 		break;
321ac19f918SStefan Eßer 	};
322ac19f918SStefan Eßer 	return tag;
323ac19f918SStefan Eßer }
3245b3f532eSStefan Eßer 
3255b3f532eSStefan Eßer static pcici_t
3265b3f532eSStefan Eßer pcibus_ftag (pcici_t tag, u_char func)
3275b3f532eSStefan Eßer {
3285b3f532eSStefan Eßer 	switch (pci_mechanism) {
3295b3f532eSStefan Eßer 
3305b3f532eSStefan Eßer 	case 1:
3315b3f532eSStefan Eßer 		tag.cfg1 &= ~0x700ul;
3325b3f532eSStefan Eßer 		tag.cfg1 |= (((u_long) func) << 8ul);
3335b3f532eSStefan Eßer 		break;
3345b3f532eSStefan Eßer 	case 2:
3352d144186SStefan Eßer 		tag.cfg2.enable  = 0xf0 | (func << 1ul);
3365b3f532eSStefan Eßer 		break;
3375b3f532eSStefan Eßer 	};
3385b3f532eSStefan Eßer 	return tag;
3395b3f532eSStefan Eßer }
3405b3f532eSStefan Eßer 
341ac19f918SStefan Eßer /*--------------------------------------------------------------------
342ac19f918SStefan Eßer **
343ac19f918SStefan Eßer **      Read register from configuration space.
344ac19f918SStefan Eßer **
345ac19f918SStefan Eßer **--------------------------------------------------------------------
346ac19f918SStefan Eßer */
347ac19f918SStefan Eßer 
348ac19f918SStefan Eßer static u_long
349ac19f918SStefan Eßer pcibus_read (pcici_t tag, u_long reg)
350ac19f918SStefan Eßer {
351ac19f918SStefan Eßer 	u_long addr, data = 0;
352ac19f918SStefan Eßer 
353ac19f918SStefan Eßer 	if (!tag.cfg1) return (0xfffffffful);
354ac19f918SStefan Eßer 
3555b3f532eSStefan Eßer 	switch (pci_mechanism) {
356ac19f918SStefan Eßer 
357ac19f918SStefan Eßer 	case 1:
358ac19f918SStefan Eßer 		addr = tag.cfg1 | (reg & 0xfc);
359ac19f918SStefan Eßer #ifdef PCI_DEBUG
360ac19f918SStefan Eßer 		printf ("pci_conf_read(1): addr=%x ", addr);
361ac19f918SStefan Eßer #endif
362ac19f918SStefan Eßer 		outl (CONF1_ADDR_PORT, addr);
363ac19f918SStefan Eßer 		data = inl (CONF1_DATA_PORT);
364ac19f918SStefan Eßer 		outl (CONF1_ADDR_PORT, 0   );
365ac19f918SStefan Eßer 		break;
366ac19f918SStefan Eßer 
367ac19f918SStefan Eßer 	case 2:
368ac19f918SStefan Eßer 		addr = tag.cfg2.port | (reg & 0xfc);
369ac19f918SStefan Eßer #ifdef PCI_DEBUG
370ac19f918SStefan Eßer 		printf ("pci_conf_read(2): addr=%x ", addr);
371ac19f918SStefan Eßer #endif
372ac19f918SStefan Eßer 		outb (CONF2_ENABLE_PORT , tag.cfg2.enable );
373ac19f918SStefan Eßer 		outb (CONF2_FORWARD_PORT, tag.cfg2.forward);
374ac19f918SStefan Eßer 
375ac19f918SStefan Eßer 		data = inl ((u_short) addr);
376ac19f918SStefan Eßer 
377ac19f918SStefan Eßer 		outb (CONF2_ENABLE_PORT,  0);
378ac19f918SStefan Eßer 		outb (CONF2_FORWARD_PORT, 0);
379ac19f918SStefan Eßer 		break;
380ac19f918SStefan Eßer 	};
381ac19f918SStefan Eßer 
382ac19f918SStefan Eßer #ifdef PCI_DEBUG
383ac19f918SStefan Eßer 	printf ("data=%x\n", data);
384ac19f918SStefan Eßer #endif
385ac19f918SStefan Eßer 
386ac19f918SStefan Eßer 	return (data);
387ac19f918SStefan Eßer }
3885b3f532eSStefan Eßer 
389ac19f918SStefan Eßer /*--------------------------------------------------------------------
390ac19f918SStefan Eßer **
391ac19f918SStefan Eßer **      Write register into configuration space.
392ac19f918SStefan Eßer **
393ac19f918SStefan Eßer **--------------------------------------------------------------------
394ac19f918SStefan Eßer */
395ac19f918SStefan Eßer 
396ac19f918SStefan Eßer static void
397ac19f918SStefan Eßer pcibus_write (pcici_t tag, u_long reg, u_long data)
398ac19f918SStefan Eßer {
399ac19f918SStefan Eßer 	u_long addr;
400ac19f918SStefan Eßer 
401ac19f918SStefan Eßer 	if (!tag.cfg1) return;
402ac19f918SStefan Eßer 
4035b3f532eSStefan Eßer 	switch (pci_mechanism) {
404ac19f918SStefan Eßer 
405ac19f918SStefan Eßer 	case 1:
406ac19f918SStefan Eßer 		addr = tag.cfg1 | (reg & 0xfc);
407ac19f918SStefan Eßer #ifdef PCI_DEBUG
408ac19f918SStefan Eßer 		printf ("pci_conf_write(1): addr=%x data=%x\n",
409ac19f918SStefan Eßer 			addr, data);
410ac19f918SStefan Eßer #endif
411ac19f918SStefan Eßer 		outl (CONF1_ADDR_PORT, addr);
412ac19f918SStefan Eßer 		outl (CONF1_DATA_PORT, data);
413ac19f918SStefan Eßer 		outl (CONF1_ADDR_PORT,   0 );
414ac19f918SStefan Eßer 		break;
415ac19f918SStefan Eßer 
416ac19f918SStefan Eßer 	case 2:
417ac19f918SStefan Eßer 		addr = tag.cfg2.port | (reg & 0xfc);
418ac19f918SStefan Eßer #ifdef PCI_DEBUG
419ac19f918SStefan Eßer 		printf ("pci_conf_write(2): addr=%x data=%x\n",
420ac19f918SStefan Eßer 			addr, data);
421ac19f918SStefan Eßer #endif
422ac19f918SStefan Eßer 		outb (CONF2_ENABLE_PORT,  tag.cfg2.enable);
423ac19f918SStefan Eßer 		outb (CONF2_FORWARD_PORT, tag.cfg2.forward);
424ac19f918SStefan Eßer 
425ac19f918SStefan Eßer 		outl ((u_short) addr, data);
426ac19f918SStefan Eßer 
427ac19f918SStefan Eßer 		outb (CONF2_ENABLE_PORT,  0);
428ac19f918SStefan Eßer 		outb (CONF2_FORWARD_PORT, 0);
429ac19f918SStefan Eßer 		break;
430ac19f918SStefan Eßer 	};
431ac19f918SStefan Eßer }
4325b3f532eSStefan Eßer 
433ac19f918SStefan Eßer /*-----------------------------------------------------------------------
434ac19f918SStefan Eßer **
435ac19f918SStefan Eßer **	Register an interupt handler for a pci device.
436ac19f918SStefan Eßer **
437ac19f918SStefan Eßer **-----------------------------------------------------------------------
438ac19f918SStefan Eßer */
439ac19f918SStefan Eßer 
440ac19f918SStefan Eßer static int
4416ea3e9d8SBruce Evans pcibus_ihandler_attach (int irq, inthand2_t *func, int arg, unsigned * maskptr)
442ac19f918SStefan Eßer {
443a680ab75SBruce Evans 	char buf[16];
444a680ab75SBruce Evans 	char *cp;
445a680ab75SBruce Evans 	int free_id, id, result;
446a680ab75SBruce Evans 
447a680ab75SBruce Evans 	sprintf(buf, "pci irq%d", irq);
448a680ab75SBruce Evans 	for (cp = intrnames, free_id = 0, id = 0; id < NR_DEVICES; id++) {
449a680ab75SBruce Evans 		if (strcmp(cp, buf) == 0)
450a680ab75SBruce Evans 			break;
451a680ab75SBruce Evans 		if (free_id <= 0 && strcmp(cp, "pci irqnn") == 0)
452a680ab75SBruce Evans 			free_id = id;
453a680ab75SBruce Evans 		while (*cp++ != '\0')
454a680ab75SBruce Evans 			;
455a680ab75SBruce Evans 	}
456a680ab75SBruce Evans 	if (id == NR_DEVICES) {
457a680ab75SBruce Evans 		id = free_id;
458a680ab75SBruce Evans 		if (id == 0) {
459a680ab75SBruce Evans 			/*
460a680ab75SBruce Evans 			 * All pci irq counters are in use, perhaps because
461a680ab75SBruce Evans 			 * config is old so there aren't any.  Abuse the
462a680ab75SBruce Evans 			 * clk0 counter.
463a680ab75SBruce Evans 			 */
464a680ab75SBruce Evans 			printf (
465a680ab75SBruce Evans 		"pcibus_ihandler_attach: counting pci irq%d's as clk0 irqs\n",
466a680ab75SBruce Evans 				irq);
467a680ab75SBruce Evans 		}
468a680ab75SBruce Evans 	}
4695b3f532eSStefan Eßer 	result = register_intr(
470ac19f918SStefan Eßer 		irq,		    /* isa irq	    */
471a680ab75SBruce Evans 		id,		    /* device id    */
472ac19f918SStefan Eßer 		0,		    /* flags?	    */
4736ea3e9d8SBruce Evans 		func,		    /* handler	    */
474ac19f918SStefan Eßer 		maskptr,	    /* mask pointer */
4755b3f532eSStefan Eßer 		arg);		    /* handler arg  */
476ac19f918SStefan Eßer 
4775b3f532eSStefan Eßer 	if (result) {
4785b3f532eSStefan Eßer 		printf ("@@@ pcibus_ihandler_attach: result=%d\n", result);
4795b3f532eSStefan Eßer 		return (result);
480ac19f918SStefan Eßer 	};
4815b3f532eSStefan Eßer 	update_intr_masks();
482ac19f918SStefan Eßer 
4835b3f532eSStefan Eßer 	INTREN ((1ul<<irq));
4845b3f532eSStefan Eßer 	return (0);
4855b3f532eSStefan Eßer }
486ac19f918SStefan Eßer 
4875b3f532eSStefan Eßer static int
4886ea3e9d8SBruce Evans pcibus_ihandler_detach (int irq, inthand2_t *func)
4895b3f532eSStefan Eßer {
4905b3f532eSStefan Eßer 	int result;
4915b3f532eSStefan Eßer 
4925b3f532eSStefan Eßer 	INTRDIS ((1ul<<irq));
4935b3f532eSStefan Eßer 
4946ea3e9d8SBruce Evans 	result = unregister_intr (irq, func);
4955b3f532eSStefan Eßer 
4965b3f532eSStefan Eßer 	if (result)
4975b3f532eSStefan Eßer 		printf ("@@@ pcibus_ihandler_detach: result=%d\n", result);
4985b3f532eSStefan Eßer 
4995b3f532eSStefan Eßer 	update_intr_masks();
5005b3f532eSStefan Eßer 
5015b3f532eSStefan Eßer 	return (result);
5025b3f532eSStefan Eßer }
5035b3f532eSStefan Eßer 
5045b3f532eSStefan Eßer static int
5055b3f532eSStefan Eßer pcibus_imask_include (int irq, unsigned* maskptr)
5065b3f532eSStefan Eßer {
5075b3f532eSStefan Eßer 	unsigned mask;
5085b3f532eSStefan Eßer 
5095b3f532eSStefan Eßer 	if (!maskptr) return (0);
5105b3f532eSStefan Eßer 
5115b3f532eSStefan Eßer 	mask = 1ul << irq;
5125b3f532eSStefan Eßer 
5135b3f532eSStefan Eßer 	if (*maskptr & mask)
5145b3f532eSStefan Eßer 		return (-1);
5155b3f532eSStefan Eßer 
5165b3f532eSStefan Eßer 	INTRMASK (*maskptr, mask);
5175b3f532eSStefan Eßer 	update_intr_masks();
5185b3f532eSStefan Eßer 
5195b3f532eSStefan Eßer 	return (0);
5205b3f532eSStefan Eßer }
5215b3f532eSStefan Eßer 
5225b3f532eSStefan Eßer static int
5235b3f532eSStefan Eßer pcibus_imask_exclude (int irq, unsigned* maskptr)
5245b3f532eSStefan Eßer {
5255b3f532eSStefan Eßer 	unsigned mask;
5265b3f532eSStefan Eßer 
5275b3f532eSStefan Eßer 	if (!maskptr) return (0);
5285b3f532eSStefan Eßer 
5295b3f532eSStefan Eßer 	mask = 1ul << irq;
5305b3f532eSStefan Eßer 
5315b3f532eSStefan Eßer 	if (! (*maskptr & mask))
5325b3f532eSStefan Eßer 		return (-1);
5335b3f532eSStefan Eßer 
53462ce633dSNate Williams 	INTRUNMASK (*maskptr, mask);
5355b3f532eSStefan Eßer 	update_intr_masks();
5365b3f532eSStefan Eßer 
5375b3f532eSStefan Eßer 	return (0);
538ac19f918SStefan Eßer }
539