pci_cfgreg.c revision 11378
143939Sabial/**************************************************************************
246493Sabial**
343939Sabial**  $Id: pcibus.c,v 1.15 1995/09/22 19:10:54 se Exp $
443939Sabial**
543939Sabial**  pci bus subroutines for i386 architecture.
643939Sabial**
746493Sabial**  FreeBSD
846493Sabial**
943939Sabial**-------------------------------------------------------------------------
1043939Sabial**
1143939Sabial** Copyright (c) 1994 Wolfgang Stanglmeier.  All rights reserved.
1243939Sabial**
1343939Sabial** Redistribution and use in source and binary forms, with or without
1443939Sabial** modification, are permitted provided that the following conditions
1543939Sabial** are met:
1643939Sabial** 1. Redistributions of source code must retain the above copyright
1743939Sabial**    notice, this list of conditions and the following disclaimer.
1843939Sabial** 2. Redistributions in binary form must reproduce the above copyright
1943939Sabial**    notice, this list of conditions and the following disclaimer in the
2043939Sabial**    documentation and/or other materials provided with the distribution.
2143939Sabial** 3. The name of the author may not be used to endorse or promote products
2243939Sabial**    derived from this software without specific prior written permission.
2343939Sabial**
2443939Sabial** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
2543939Sabial** IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
2643939Sabial** OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
2743939Sabial** IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
2843939Sabial** INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
2943939Sabial** NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
3050479Speter** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
3138589Sabial** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
3238589Sabial** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
3338589Sabial** THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
3438589Sabial**
3538589Sabial***************************************************************************
3638589Sabial*/
3746493Sabial
3838589Sabial#include <sys/param.h>
3938589Sabial#include <sys/systm.h>
4046493Sabial#include <sys/kernel.h>
4146493Sabial
4238589Sabial#include <machine/cpu.h> /* bootverbose */
4346493Sabial
4446493Sabial#include <i386/isa/icu.h>
4546493Sabial#include <i386/isa/isa.h>
4638589Sabial#include <i386/isa/isa_device.h>
4746493Sabial
4846493Sabial#include <pci/pcivar.h>
4938589Sabial#include <pci/pcireg.h>
5046493Sabial#include <pci/pcibus.h>
5146493Sabial
5246493Sabial/*-----------------------------------------------------------------
5338589Sabial**
5446493Sabial**	The following functions are provided by the pci bios.
55113126Sdwmalone**	They are used only by the pci configuration.
5646493Sabial**
5746493Sabial**	pcibus_setup():
58113126Sdwmalone**		Probes for a pci system.
59113126Sdwmalone**		Sets pci_maxdevice and pci_mechanism.
60113126Sdwmalone**
61113126Sdwmalone**	pcibus_tag():
62113126Sdwmalone**		Creates a handle for pci configuration space access.
63113126Sdwmalone**		This handle is given to the read/write functions.
64113126Sdwmalone**
6546493Sabial**	pcibus_ftag():
6638589Sabial**		Creates a modified handle.
6746493Sabial**
6838589Sabial**	pcibus_read():
6946493Sabial**		Read a long word from the pci configuration space.
7046493Sabial**		Requires a tag (from pcitag) and the register
7146493Sabial**		number (should be a long word alligned one).
7246493Sabial**
7346493Sabial**	pcibus_write():
7446493Sabial**		Writes a long word to the pci configuration space.
75113126Sdwmalone**		Requires a tag (from pcitag), the register number
7646493Sabial**		(should be a long word alligned one), and a value.
7746493Sabial**
7846493Sabial**	pcibus_regirq():
7946493Sabial**		Register an interupt handler for a pci device.
8046493Sabial**		Requires a tag (from pcitag), the register number
81113126Sdwmalone**		(should be a long word alligned one), and a value.
8246493Sabial**
8346493Sabial**-----------------------------------------------------------------
8446493Sabial*/
8546493Sabial
8646493Sabialstatic int
8746493Sabialpcibus_check (void);
8846493Sabial
8946493Sabialstatic void
9038589Sabialpcibus_setup (void);
9138589Sabial
9238589Sabialstatic pcici_t
9338589Sabialpcibus_tag (u_char bus, u_char device, u_char func);
9438589Sabial
9538589Sabialstatic pcici_t
9638589Sabialpcibus_ftag (pcici_t tag, u_char func);
9738589Sabial
9838589Sabialstatic u_long
9938589Sabialpcibus_read (pcici_t tag, u_long reg);
10038589Sabial
10138589Sabialstatic void
10238589Sabialpcibus_write (pcici_t tag, u_long reg, u_long data);
10338589Sabial
10438589Sabialstatic int
10538589Sabialpcibus_ihandler_attach (int irq, void(*ihandler)(), int arg, unsigned* maskp);
10638589Sabial
10738589Sabialstatic int
10894130Sasmodaipcibus_ihandler_detach (int irq, void(*handler)());
10938589Sabial
11038589Sabialstatic int
11146493Sabialpcibus_imask_include (int irq, unsigned* maskptr);
11246493Sabial
11346493Sabialstatic int
11494134Sasmodaipcibus_imask_exclude (int irq, unsigned* maskptr);
11546493Sabial
11638589Sabialstruct pcibus i386pci = {
117113126Sdwmalone	"pci",
11838589Sabial	pcibus_setup,
11938589Sabial	pcibus_tag,
12038589Sabial	pcibus_ftag,
12138589Sabial	pcibus_read,
12238589Sabial	pcibus_write,
12338589Sabial	ICU_LEN,
12438589Sabial	pcibus_ihandler_attach,
12538589Sabial	pcibus_ihandler_detach,
12638589Sabial	pcibus_imask_include,
12738589Sabial	pcibus_imask_exclude,
12846493Sabial};
12946493Sabial
13046493Sabial/*
13194134Sasmodai**	Announce structure to generic driver
13294134Sasmodai*/
13338589Sabial
13438589SabialDATA_SET (pcibus_set, i386pci);
13538589Sabial
13638589Sabial/*--------------------------------------------------------------------
13738589Sabial**
13838589Sabial**      Determine configuration mode
13938589Sabial**
140113126Sdwmalone**--------------------------------------------------------------------
14138589Sabial*/
14238589Sabial
14346493Sabial
14446493Sabial#define CONF1_ADDR_PORT    0x0cf8
14546493Sabial#define CONF1_DATA_PORT    0x0cfc
14694134Sasmodai
147113126Sdwmalone#define CONF1_ENABLE       0x80000000ul
14846493Sabial#define CONF1_ENABLE_CHK   0x80000000ul
14946493Sabial#define CONF1_ENABLE_CHK1  0xFF000001ul
15046493Sabial#define CONF1_ENABLE_MSK1  0x80000000ul
15146493Sabial#define CONF1_ENABLE_RES1  0x80000000ul
15238589Sabial
15338589Sabial#define CONF2_ENABLE_PORT  0x0cf8
15446493Sabial#define CONF2_FORWARD_PORT 0x0cfa
15546493Sabial
15646493Sabial#define CONF2_ENABLE_CHK   0x0e
15746493Sabial#define CONF2_ENABLE_RES   0x0e
15894134Sasmodai
15946493Sabialstatic int
16038589Sabialpcibus_check (void)
16146493Sabial{
16246493Sabial	u_char device;
16346493Sabial
16446493Sabial	if (bootverbose) printf ("pcibus_check:\tdevice ");
16546493Sabial
16638589Sabial	for (device = 0; device < pci_maxdevice; device++) {
16746493Sabial		unsigned long id;
16846493Sabial		if (bootverbose)
16946493Sabial			printf ("%d ", device);
17046493Sabial		id = pcibus_read (pcibus_tag (0,device,0), 0);
17146493Sabial		if (id != 0xfffffffful) {
17246493Sabial			if (bootverbose) printf ("is there (id=%08lx)\n", id);
17346493Sabial			return 1;
17446493Sabial		}
17546493Sabial	}
17646493Sabial	if (bootverbose)
17746493Sabial		printf ("-- nothing found\n");
17846493Sabial	return 0;
17946493Sabial}
18038589Sabial
18146493Sabialstatic void
18246493Sabialpcibus_setup (void)
18346493Sabial{
18446493Sabial	unsigned long mode1res,oldval;
18546493Sabial	unsigned char mode2res;
18646493Sabial
18746493Sabial	oldval = inl (CONF1_ADDR_PORT);
18846493Sabial	outl (CONF1_ADDR_PORT, CONF1_ENABLE_CHK);
18946493Sabial	outb (CONF2_ENABLE_PORT, CONF2_ENABLE_CHK);
19046493Sabial	mode1res = inl(CONF1_ADDR_PORT);
19146493Sabial	mode2res = inb(CONF2_ENABLE_PORT);
19246493Sabial	outb (CONF2_ENABLE_PORT, 0);
19346493Sabial	outl (CONF1_ADDR_PORT, oldval);
19446493Sabial
19546493Sabial	if (bootverbose) {
19638589Sabial		printf ("pcibus_setup(1):\tmode1res=0x%08lx (0x%08lx), "
19738589Sabial			"mode2res=0x%02x (0x%02x)\n",
19846493Sabial			mode1res,CONF1_ENABLE_CHK,
19946493Sabial			(int)mode2res,CONF2_ENABLE_CHK);
20046493Sabial	}
20146493Sabial
20294134Sasmodai	/*---------------------------------------
20394135Sasmodai	**	No PCI, if neither mode1res nor mode2res could be read back
20438589Sabial	**---------------------------------------
20594132Sasmodai	*/
20646493Sabial
20746493Sabial	if ((mode1res != CONF1_ENABLE_CHK) && (mode2res != CONF2_ENABLE_CHK)) {
208113126Sdwmalone		return;
20946493Sabial	}
21038589Sabial
21146493Sabial	/*---------------------------------------
21238589Sabial	**      Assume configuration mechanism 1 for now ...
21338589Sabial	**---------------------------------------
21438589Sabial	*/
215113126Sdwmalone
216113126Sdwmalone	pci_mechanism = 1;
21738589Sabial	pci_maxdevice = 32;
21846493Sabial
21938589Sabial	outl (CONF1_ADDR_PORT, CONF1_ENABLE_CHK);
22046493Sabial	outb (CONF1_ADDR_PORT +3, 0);
22138589Sabial	mode1res = inl (CONF1_ADDR_PORT);
22246493Sabial	outl (CONF1_ADDR_PORT, oldval);
22346493Sabial
22446493Sabial	if (bootverbose)
22546493Sabial		printf ("pcibus_setup(2):\tmode1res=0x%08lx (0x%08lx)\n",
22646493Sabial			mode1res, CONF1_ENABLE_CHK);
22746493Sabial
22838589Sabial	if (mode1res) {
22946493Sabial		if (pcibus_check())
23046493Sabial			return;
23138589Sabial	};
23246493Sabial
23346493Sabial	outl (CONF1_ADDR_PORT, CONF1_ENABLE_CHK1);
23446493Sabial	outl (CONF1_DATA_PORT, 0);
23546493Sabial	mode1res = inl(CONF1_ADDR_PORT);
23646493Sabial	outl (CONF1_ADDR_PORT, oldval);
23738589Sabial
23838589Sabial	if (bootverbose)
23938589Sabial		printf ("pcibus_setup(3):\tmode1res=0x%08lx (0x%08lx)\n",
24038589Sabial			mode1res, CONF1_ENABLE_CHK1);
24138589Sabial
242113126Sdwmalone	if ((mode1res & CONF1_ENABLE_MSK1) == CONF1_ENABLE_RES1) {
24338589Sabial		if (pcibus_check())
24438589Sabial			return;
24538589Sabial	};
24646493Sabial
24746493Sabial	/*---------------------------------------
24846493Sabial	**      Try configuration mechanism 2 ...
24938589Sabial	**---------------------------------------
25038589Sabial	*/
25138589Sabial
252113126Sdwmalone	if (bootverbose)
25338589Sabial		printf ("pcibus_setup(4):\tnow trying mechanism 2\n");
25438589Sabial
25538589Sabial	pci_mechanism = 2;
25638589Sabial	pci_maxdevice = 16;
25738589Sabial
25846493Sabial	if (pcibus_check())
259112205Sdwmalone	    return;
260112205Sdwmalone
26138589Sabial	/*---------------------------------------
26238589Sabial	**      No PCI bus host bridge found
26338589Sabial	**---------------------------------------
26438589Sabial	*/
265113126Sdwmalone
26646493Sabial	pci_mechanism = 0;
26746493Sabial	pci_maxdevice = 0;
26846493Sabial}
26946493Sabial
27079452Sbrian/*--------------------------------------------------------------------
27138589Sabial**
27238589Sabial**      Build a pcitag from bus, device and function number
273112205Sdwmalone**
27438589Sabial**--------------------------------------------------------------------
27538589Sabial*/
27638589Sabial
27746493Sabialstatic pcici_t
27846493Sabialpcibus_tag (unsigned char bus, unsigned char device, unsigned char func)
27946493Sabial{
28038589Sabial	pcici_t tag;
28146493Sabial
28246493Sabial	tag.cfg1 = 0;
28346493Sabial	if (func   >=  8) return tag;
28438589Sabial
28538589Sabial	switch (pci_mechanism) {
28646493Sabial
28746493Sabial	case 1:
28846493Sabial		if (device < 32) {
28946493Sabial			tag.cfg1 = CONF1_ENABLE
29046493Sabial				| (((u_long) bus   ) << 16ul)
29146493Sabial				| (((u_long) device) << 11ul)
29246493Sabial				| (((u_long) func  ) <<  8ul);
29346493Sabial		}
29438589Sabial		break;
29538589Sabial	case 2:
29646493Sabial		if (device < 16) {
29746493Sabial			tag.cfg2.port    = 0xc000 | (device << 8ul);
29846493Sabial			tag.cfg2.enable  = 0xf0 | (func << 1ul);
29938589Sabial			tag.cfg2.forward = bus;
30046493Sabial		}
30146493Sabial		break;
30246493Sabial	};
30346493Sabial	return tag;
30446493Sabial}
305113126Sdwmalone
30638589Sabialstatic pcici_t
30746493Sabialpcibus_ftag (pcici_t tag, u_char func)
30846493Sabial{
30946493Sabial	switch (pci_mechanism) {
31046493Sabial
31146493Sabial	case 1:
312113126Sdwmalone		tag.cfg1 &= ~0x700ul;
31346493Sabial		tag.cfg1 |= (((u_long) func) << 8ul);
31438589Sabial		break;
31546493Sabial	case 2:
31646493Sabial		tag.cfg2.enable  = 0xf0 | (func << 1ul);
31746493Sabial		break;
31846493Sabial	};
31946493Sabial	return tag;
32038589Sabial}
32194133Sasmodai
322113129Sdwmalone/*--------------------------------------------------------------------
32338589Sabial**
32446493Sabial**      Read register from configuration space.
32546493Sabial**
32646493Sabial**--------------------------------------------------------------------
32746493Sabial*/
32846493Sabial
32946493Sabialstatic u_long
33046493Sabialpcibus_read (pcici_t tag, u_long reg)
33146493Sabial{
33246493Sabial	u_long addr, data = 0;
33346493Sabial
33446493Sabial	if (!tag.cfg1) return (0xfffffffful);
33546493Sabial
33646493Sabial	switch (pci_mechanism) {
33746493Sabial
33846493Sabial	case 1:
33946493Sabial		addr = tag.cfg1 | (reg & 0xfc);
34046493Sabial#ifdef PCI_DEBUG
34146493Sabial		printf ("pci_conf_read(1): addr=%x ", addr);
34238589Sabial#endif
34346493Sabial		outl (CONF1_ADDR_PORT, addr);
34438589Sabial		data = inl (CONF1_DATA_PORT);
345113126Sdwmalone		outl (CONF1_ADDR_PORT, 0   );
34646493Sabial		break;
34738589Sabial
34838589Sabial	case 2:
349113126Sdwmalone		addr = tag.cfg2.port | (reg & 0xfc);
350113126Sdwmalone#ifdef PCI_DEBUG
35146493Sabial		printf ("pci_conf_read(2): addr=%x ", addr);
35238589Sabial#endif
35338589Sabial		outb (CONF2_ENABLE_PORT , tag.cfg2.enable );
35438589Sabial		outb (CONF2_FORWARD_PORT, tag.cfg2.forward);
35538589Sabial
35646493Sabial		data = inl ((u_short) addr);
35746493Sabial
35846493Sabial		outb (CONF2_ENABLE_PORT,  0);
35946493Sabial		outb (CONF2_FORWARD_PORT, 0);
36046493Sabial		break;
36194134Sasmodai	};
36246493Sabial
36338589Sabial#ifdef PCI_DEBUG
36494132Sasmodai	printf ("data=%x\n", data);
36546493Sabial#endif
36646493Sabial
36746493Sabial	return (data);
36846493Sabial}
36938589Sabial
37038589Sabial/*--------------------------------------------------------------------
37138589Sabial**
37238589Sabial**      Write register into configuration space.
37346493Sabial**
37446493Sabial**--------------------------------------------------------------------
37546493Sabial*/
37646493Sabial
37746493Sabialstatic void
37846493Sabialpcibus_write (pcici_t tag, u_long reg, u_long data)
37946493Sabial{
38038589Sabial	u_long addr;
38146493Sabial
38246493Sabial	if (!tag.cfg1) return;
38346493Sabial
38446493Sabial	switch (pci_mechanism) {
38546493Sabial
38646493Sabial	case 1:
38746493Sabial		addr = tag.cfg1 | (reg & 0xfc);
38846493Sabial#ifdef PCI_DEBUG
38946493Sabial		printf ("pci_conf_write(1): addr=%x data=%x\n",
390113126Sdwmalone			addr, data);
39146493Sabial#endif
39246493Sabial		outl (CONF1_ADDR_PORT, addr);
39346493Sabial		outl (CONF1_DATA_PORT, data);
39446493Sabial		outl (CONF1_ADDR_PORT,   0 );
39546493Sabial		break;
39646493Sabial
39746493Sabial	case 2:
39846493Sabial		addr = tag.cfg2.port | (reg & 0xfc);
39946493Sabial#ifdef PCI_DEBUG
40046493Sabial		printf ("pci_conf_write(2): addr=%x data=%x\n",
40146493Sabial			addr, data);
40246493Sabial#endif
40346493Sabial		outb (CONF2_ENABLE_PORT,  tag.cfg2.enable);
40446493Sabial		outb (CONF2_FORWARD_PORT, tag.cfg2.forward);
40546493Sabial
40646493Sabial		outl ((u_short) addr, data);
40746493Sabial
40846493Sabial		outb (CONF2_ENABLE_PORT,  0);
40946493Sabial		outb (CONF2_FORWARD_PORT, 0);
41046493Sabial		break;
41146493Sabial	};
41246493Sabial}
41346493Sabial
41446493Sabial/*-----------------------------------------------------------------------
41546493Sabial**
41646493Sabial**	Register an interupt handler for a pci device.
41746493Sabial**
41846493Sabial**-----------------------------------------------------------------------
41946493Sabial*/
42046493Sabial
421113126Sdwmalonestatic int
42246493Sabialpcibus_ihandler_attach (int irq, void(*func)(), int arg, unsigned * maskptr)
42346493Sabial{
42446493Sabial	int result;
42546493Sabial	result = register_intr(
42646493Sabial		irq,		    /* isa irq	    */
42746493Sabial		0,		    /* deviced??    */
42846493Sabial		0,		    /* flags?	    */
42946493Sabial		(inthand2_t*) func, /* handler	    */
43046493Sabial		maskptr,	    /* mask pointer */
43146493Sabial		arg);		    /* handler arg  */
43246493Sabial
43346493Sabial	if (result) {
43446493Sabial		printf ("@@@ pcibus_ihandler_attach: result=%d\n", result);
43546493Sabial		return (result);
43638589Sabial	};
43738589Sabial	update_intr_masks();
43846493Sabial
43946493Sabial	INTREN ((1ul<<irq));
44046493Sabial	return (0);
441113126Sdwmalone}
44246493Sabial
44346493Sabialstatic int
44438589Sabialpcibus_ihandler_detach (int irq, void(*func)())
44546493Sabial{
44646493Sabial	int result;
447113126Sdwmalone
44846493Sabial	INTRDIS ((1ul<<irq));
44946493Sabial
45046493Sabial	result = unregister_intr (irq, (inthand2_t*) func);
45146493Sabial
45246493Sabial	if (result)
45346493Sabial		printf ("@@@ pcibus_ihandler_detach: result=%d\n", result);
45438589Sabial
455113126Sdwmalone	update_intr_masks();
45646493Sabial
45746493Sabial	return (result);
45846493Sabial}
45946493Sabial
46046493Sabialstatic int
46146493Sabialpcibus_imask_include (int irq, unsigned* maskptr)
46238589Sabial{
46346493Sabial	unsigned mask;
46446493Sabial
46546493Sabial	if (!maskptr) return (0);
46646493Sabial
46746493Sabial	mask = 1ul << irq;
46846493Sabial
46946493Sabial	if (*maskptr & mask)
47046493Sabial		return (-1);
47146493Sabial
47246493Sabial	INTRMASK (*maskptr, mask);
47346493Sabial	update_intr_masks();
47446493Sabial
47538589Sabial	return (0);
47638589Sabial}
47738589Sabial
478113126Sdwmalonestatic int
479113126Sdwmalonepcibus_imask_exclude (int irq, unsigned* maskptr)
48038589Sabial{
48138589Sabial	unsigned mask;
482112205Sdwmalone
48338589Sabial	if (!maskptr) return (0);
48438589Sabial
48538589Sabial	mask = 1ul << irq;
48643939Sabial
48743939Sabial	if (! (*maskptr & mask))
48843939Sabial		return (-1);
48938589Sabial
49038589Sabial	*maskptr &= ~mask;
491	update_intr_masks();
492
493	return (0);
494}
495