pci_cfgreg.c revision 9360
167754Smsmith/**************************************************************************
267754Smsmith**
367754Smsmith**  $Id: pcibus.c,v 1.8 1995/03/22 21:35:39 se Exp $
467754Smsmith**
567754Smsmith**  pci bus subroutines for i386 architecture.
667754Smsmith**
767754Smsmith**  FreeBSD
867754Smsmith**
967754Smsmith**-------------------------------------------------------------------------
1067754Smsmith**
1167754Smsmith** Copyright (c) 1994 Wolfgang Stanglmeier.  All rights reserved.
1267754Smsmith**
1367754Smsmith** Redistribution and use in source and binary forms, with or without
1467754Smsmith** modification, are permitted provided that the following conditions
1567754Smsmith** are met:
1667754Smsmith** 1. Redistributions of source code must retain the above copyright
1767754Smsmith**    notice, this list of conditions and the following disclaimer.
1867754Smsmith** 2. Redistributions in binary form must reproduce the above copyright
1967754Smsmith**    notice, this list of conditions and the following disclaimer in the
2067754Smsmith**    documentation and/or other materials provided with the distribution.
2167754Smsmith** 3. The name of the author may not be used to endorse or promote products
2267754Smsmith**    derived from this software without specific prior written permission.
2367754Smsmith**
2467754Smsmith** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
2567754Smsmith** IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
2667754Smsmith** OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
2767754Smsmith** IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
2867754Smsmith** INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
2967754Smsmith** NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
3067754Smsmith** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
3167754Smsmith** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
3267754Smsmith** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
3367754Smsmith** THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
3467754Smsmith**
3567754Smsmith***************************************************************************
3667754Smsmith*/
3767754Smsmith
3867754Smsmith#define	__PCIBUS_C___	"pl4 95/03/21"
3967754Smsmith
4067754Smsmith#include <sys/param.h>
4167754Smsmith#include <sys/systm.h>
4267754Smsmith#include <sys/kernel.h>
4367754Smsmith
4467754Smsmith#include <i386/isa/icu.h>
4567754Smsmith#include <i386/isa/isa.h>
4667754Smsmith#include <i386/isa/isa_device.h>
4767754Smsmith
4867754Smsmith#include <pci/pcivar.h>
4967754Smsmith#include <pci/pcireg.h>
5067754Smsmith#include <pci/pcibus.h>
5167754Smsmith
5267754Smsmith/*-----------------------------------------------------------------
5367754Smsmith**
5467754Smsmith**	The following functions are provided by the pci bios.
5567754Smsmith**	They are used only by the pci configuration.
5667754Smsmith**
5767754Smsmith**	pcibus_setup():
5867754Smsmith**		Probes for a pci system.
5967754Smsmith**		Sets pci_maxdevice and pci_mechanism.
6067754Smsmith**
6167754Smsmith**	pcibus_tag():
6267754Smsmith**		Creates a handle for pci configuration space access.
6367754Smsmith**		This handle is given to the read/write functions.
6467754Smsmith**
6567754Smsmith**	pcibus_ftag():
6667754Smsmith**		Creates a modified handle.
6767754Smsmith**
6867754Smsmith**	pcibus_read():
6967754Smsmith**		Read a long word from the pci configuration space.
7067754Smsmith**		Requires a tag (from pcitag) and the register
7167754Smsmith**		number (should be a long word alligned one).
7267754Smsmith**
7367754Smsmith**	pcibus_write():
7467754Smsmith**		Writes a long word to the pci configuration space.
7567754Smsmith**		Requires a tag (from pcitag), the register number
7667754Smsmith**		(should be a long word alligned one), and a value.
7767754Smsmith**
7867754Smsmith**	pcibus_regirq():
7967754Smsmith**		Register an interupt handler for a pci device.
8067754Smsmith**		Requires a tag (from pcitag), the register number
8167754Smsmith**		(should be a long word alligned one), and a value.
8267754Smsmith**
8367754Smsmith**-----------------------------------------------------------------
8467754Smsmith*/
8567754Smsmith
8667754Smsmithstatic void
8767754Smsmithpcibus_setup (void);
8867754Smsmith
8967754Smsmithstatic pcici_t
9067754Smsmithpcibus_tag (u_char bus, u_char device, u_char func);
9167754Smsmith
9267754Smsmithstatic pcici_t
9367754Smsmithpcibus_ftag (pcici_t tag, u_char func);
9467754Smsmith
9567754Smsmithstatic u_long
9667754Smsmithpcibus_read (pcici_t tag, u_long reg);
9767754Smsmith
9867754Smsmithstatic void
9967754Smsmithpcibus_write (pcici_t tag, u_long reg, u_long data);
10067754Smsmith
10167754Smsmithstatic int
10267754Smsmithpcibus_ihandler_attach (int irq, void(*ihandler)(), int arg, unsigned* maskp);
10367754Smsmith
10467754Smsmithstatic int
10567754Smsmithpcibus_ihandler_detach (int irq, void(*handler)());
10667754Smsmith
10767754Smsmithstatic int
10867754Smsmithpcibus_imask_include (int irq, unsigned* maskptr);
10967754Smsmith
11067754Smsmithstatic int
11167754Smsmithpcibus_imask_exclude (int irq, unsigned* maskptr);
11267754Smsmith
11367754Smsmithstruct pcibus i386pci = {
11467754Smsmith	"pci",
11567754Smsmith	pcibus_setup,
11667754Smsmith	pcibus_tag,
11767754Smsmith	pcibus_ftag,
11867754Smsmith	pcibus_read,
11967754Smsmith	pcibus_write,
12067754Smsmith	ICU_LEN,
12167754Smsmith	pcibus_ihandler_attach,
12267754Smsmith	pcibus_ihandler_detach,
12367754Smsmith	pcibus_imask_include,
12467754Smsmith	pcibus_imask_exclude,
12567754Smsmith};
12667754Smsmith
12767754Smsmith/*
12867754Smsmith**	Announce structure to generic driver
12967754Smsmith*/
13067754Smsmith
13167754SmsmithDATA_SET (pcibus_set, i386pci);
13267754Smsmith
13367754Smsmith/*--------------------------------------------------------------------
13467754Smsmith**
13567754Smsmith**      Determine configuration mode
13667754Smsmith**
13767754Smsmith**--------------------------------------------------------------------
13867754Smsmith*/
13967754Smsmith
14067754Smsmith
14167754Smsmith#define CONF1_ENABLE       0x80000000ul
14267754Smsmith#define CONF1_ENABLE_CHK   0xF0000000ul
14367754Smsmith#define CONF1_ADDR_PORT    0x0cf8
14467754Smsmith#define CONF1_DATA_PORT    0x0cfc
14567754Smsmith
14667754Smsmith
14767754Smsmith#define CONF2_ENABLE_PORT  0x0cf8
14867754Smsmith#define CONF2_FORWARD_PORT 0x0cfa
14967754Smsmith
15067754Smsmith
15167754Smsmithstatic void
15267754Smsmithpcibus_setup (void)
15367754Smsmith{
15467754Smsmith	u_long result, oldval;
15567754Smsmith
15667754Smsmith	/*---------------------------------------
15767754Smsmith	**      Configuration mode 1 ?
15867754Smsmith	**---------------------------------------
15967754Smsmith	*/
16067754Smsmith
16167754Smsmith	oldval = inl (CONF1_ADDR_PORT);
16267754Smsmith	outl (CONF1_ADDR_PORT, CONF1_ENABLE_CHK);
16367754Smsmith	outb (CONF1_ADDR_PORT +3, 0);
16467754Smsmith	result = inl (CONF1_ADDR_PORT);
16567754Smsmith	outl (CONF1_ADDR_PORT, oldval);
16667754Smsmith
16767754Smsmith	if (result == CONF1_ENABLE) {
16867754Smsmith		pci_mechanism = 1;
16967754Smsmith		pci_maxdevice = 32;
17067754Smsmith		return;
17167754Smsmith	};
17267754Smsmith
17367754Smsmith	/*---------------------------------------
17467754Smsmith	**      Configuration mode 2 ?
17567754Smsmith	**---------------------------------------
17667754Smsmith	*/
17767754Smsmith
17867754Smsmith	outb (CONF2_ENABLE_PORT,  0);
17967754Smsmith	outb (CONF2_FORWARD_PORT, 0);
18067754Smsmith	if (!inb (CONF2_ENABLE_PORT) && !inb (CONF2_FORWARD_PORT)) {
18167754Smsmith		pci_mechanism = 2;
18267754Smsmith		pci_maxdevice = 16;
18367754Smsmith		return;
18467754Smsmith	};
18567754Smsmith
18667754Smsmith	/*---------------------------------------
18767754Smsmith	**      No PCI bus available.
18867754Smsmith	**---------------------------------------
18967754Smsmith	*/
19067754Smsmith}
19167754Smsmith
19267754Smsmith/*--------------------------------------------------------------------
19367754Smsmith**
19467754Smsmith**      Build a pcitag from bus, device and function number
19567754Smsmith**
19667754Smsmith**--------------------------------------------------------------------
19767754Smsmith*/
19867754Smsmith
19967754Smsmithstatic pcici_t
20067754Smsmithpcibus_tag (unsigned char bus, unsigned char device, unsigned char func)
20167754Smsmith{
20267754Smsmith	pcici_t tag;
20367754Smsmith
20467754Smsmith	tag.cfg1 = 0;
20567754Smsmith	if (device >= 32) return tag;
20667754Smsmith	if (func   >=  8) return tag;
20767754Smsmith
20867754Smsmith	switch (pci_mechanism) {
20967754Smsmith
21067754Smsmith	case 1:
21167754Smsmith		tag.cfg1 = CONF1_ENABLE
21267754Smsmith			| (((u_long) bus   ) << 16ul)
21367754Smsmith			| (((u_long) device) << 11ul)
21467754Smsmith			| (((u_long) func  ) <<  8ul);
21567754Smsmith		break;
21667754Smsmith	case 2:
21767754Smsmith		if (device >= 16) break;
21867754Smsmith		tag.cfg2.port    = 0xc000 | (device << 8ul);
21967754Smsmith		tag.cfg2.enable  = 0xf1 | (func << 1ul);
22067754Smsmith		tag.cfg2.forward = bus;
22167754Smsmith		break;
22267754Smsmith	};
22367754Smsmith	return tag;
22467754Smsmith}
22567754Smsmith
22667754Smsmithstatic pcici_t
22767754Smsmithpcibus_ftag (pcici_t tag, u_char func)
22867754Smsmith{
22967754Smsmith	switch (pci_mechanism) {
23067754Smsmith
23167754Smsmith	case 1:
23267754Smsmith		tag.cfg1 &= ~0x700ul;
23367754Smsmith		tag.cfg1 |= (((u_long) func) << 8ul);
23467754Smsmith		break;
23567754Smsmith	case 2:
23667754Smsmith		tag.cfg2.enable  = 0xf1 | (func << 1ul);
23767754Smsmith		break;
23867754Smsmith	};
23967754Smsmith	return tag;
24067754Smsmith}
24167754Smsmith
24267754Smsmith/*--------------------------------------------------------------------
24367754Smsmith**
24467754Smsmith**      Read register from configuration space.
24567754Smsmith**
24667754Smsmith**--------------------------------------------------------------------
24767754Smsmith*/
24867754Smsmith
24967754Smsmithstatic u_long
25067754Smsmithpcibus_read (pcici_t tag, u_long reg)
25167754Smsmith{
25267754Smsmith	u_long addr, data = 0;
25367754Smsmith
25467754Smsmith	if (!tag.cfg1) return (0xfffffffful);
25567754Smsmith
25667754Smsmith	switch (pci_mechanism) {
25767754Smsmith
25867754Smsmith	case 1:
25967754Smsmith		addr = tag.cfg1 | (reg & 0xfc);
26067754Smsmith#ifdef PCI_DEBUG
26167754Smsmith		printf ("pci_conf_read(1): addr=%x ", addr);
26267754Smsmith#endif
26367754Smsmith		outl (CONF1_ADDR_PORT, addr);
26467754Smsmith		data = inl (CONF1_DATA_PORT);
26567754Smsmith		outl (CONF1_ADDR_PORT, 0   );
26667754Smsmith		break;
26767754Smsmith
26867754Smsmith	case 2:
26967754Smsmith		addr = tag.cfg2.port | (reg & 0xfc);
27067754Smsmith#ifdef PCI_DEBUG
27167754Smsmith		printf ("pci_conf_read(2): addr=%x ", addr);
27267754Smsmith#endif
27367754Smsmith		outb (CONF2_ENABLE_PORT , tag.cfg2.enable );
27467754Smsmith		outb (CONF2_FORWARD_PORT, tag.cfg2.forward);
27567754Smsmith
27667754Smsmith		data = inl ((u_short) addr);
27767754Smsmith
27867754Smsmith		outb (CONF2_ENABLE_PORT,  0);
27967754Smsmith		outb (CONF2_FORWARD_PORT, 0);
28067754Smsmith		break;
28167754Smsmith	};
28267754Smsmith
28367754Smsmith#ifdef PCI_DEBUG
28467754Smsmith	printf ("data=%x\n", data);
28567754Smsmith#endif
28667754Smsmith
28767754Smsmith	return (data);
28867754Smsmith}
28967754Smsmith
29067754Smsmith/*--------------------------------------------------------------------
29167754Smsmith**
29267754Smsmith**      Write register into configuration space.
29367754Smsmith**
29467754Smsmith**--------------------------------------------------------------------
29567754Smsmith*/
29667754Smsmith
29767754Smsmithstatic void
29867754Smsmithpcibus_write (pcici_t tag, u_long reg, u_long data)
29967754Smsmith{
30067754Smsmith	u_long addr;
30167754Smsmith
30267754Smsmith	if (!tag.cfg1) return;
30367754Smsmith
30467754Smsmith	switch (pci_mechanism) {
30567754Smsmith
30667754Smsmith	case 1:
30767754Smsmith		addr = tag.cfg1 | (reg & 0xfc);
30867754Smsmith#ifdef PCI_DEBUG
30967754Smsmith		printf ("pci_conf_write(1): addr=%x data=%x\n",
31067754Smsmith			addr, data);
31167754Smsmith#endif
31267754Smsmith		outl (CONF1_ADDR_PORT, addr);
31367754Smsmith		outl (CONF1_DATA_PORT, data);
31467754Smsmith		outl (CONF1_ADDR_PORT,   0 );
31567754Smsmith		break;
31667754Smsmith
31767754Smsmith	case 2:
31867754Smsmith		addr = tag.cfg2.port | (reg & 0xfc);
31967754Smsmith#ifdef PCI_DEBUG
32067754Smsmith		printf ("pci_conf_write(2): addr=%x data=%x\n",
32167754Smsmith			addr, data);
32267754Smsmith#endif
32367754Smsmith		outb (CONF2_ENABLE_PORT,  tag.cfg2.enable);
32467754Smsmith		outb (CONF2_FORWARD_PORT, tag.cfg2.forward);
32567754Smsmith
32667754Smsmith		outl ((u_short) addr, data);
32767754Smsmith
32867754Smsmith		outb (CONF2_ENABLE_PORT,  0);
32967754Smsmith		outb (CONF2_FORWARD_PORT, 0);
33067754Smsmith		break;
33167754Smsmith	};
33267754Smsmith}
33367754Smsmith
33467754Smsmith/*-----------------------------------------------------------------------
33567754Smsmith**
33667754Smsmith**	Register an interupt handler for a pci device.
33767754Smsmith**
33867754Smsmith**-----------------------------------------------------------------------
33967754Smsmith*/
34067754Smsmith
34167754Smsmithstatic int
34267754Smsmithpcibus_ihandler_attach (int irq, void(*func)(), int arg, unsigned * maskptr)
34367754Smsmith{
34467754Smsmith	int result;
34567754Smsmith	result = register_intr(
34667754Smsmith		irq,		    /* isa irq	    */
34767754Smsmith		0,		    /* deviced??    */
34867754Smsmith		0,		    /* flags?	    */
34967754Smsmith		(inthand2_t*) func, /* handler	    */
35067754Smsmith		maskptr,	    /* mask pointer */
35167754Smsmith		arg);		    /* handler arg  */
35267754Smsmith
35367754Smsmith	if (result) {
35467754Smsmith		printf ("@@@ pcibus_ihandler_attach: result=%d\n", result);
35567754Smsmith		return (result);
35667754Smsmith	};
35767754Smsmith	update_intr_masks();
35867754Smsmith
35967754Smsmith	INTREN ((1ul<<irq));
36067754Smsmith	return (0);
36167754Smsmith}
36267754Smsmith
36367754Smsmithstatic int
36467754Smsmithpcibus_ihandler_detach (int irq, void(*func)())
36567754Smsmith{
36667754Smsmith	int result;
36767754Smsmith
36867754Smsmith	INTRDIS ((1ul<<irq));
36967754Smsmith
37067754Smsmith	result = unregister_intr (irq, (inthand2_t*) func);
37167754Smsmith
37267754Smsmith	if (result)
37367754Smsmith		printf ("@@@ pcibus_ihandler_detach: result=%d\n", result);
37467754Smsmith
37567754Smsmith	update_intr_masks();
37667754Smsmith
37767754Smsmith	return (result);
37867754Smsmith}
37967754Smsmith
38067754Smsmithstatic int
38167754Smsmithpcibus_imask_include (int irq, unsigned* maskptr)
38267754Smsmith{
38367754Smsmith	unsigned mask;
38467754Smsmith
38567754Smsmith	if (!maskptr) return (0);
38667754Smsmith
38767754Smsmith	mask = 1ul << irq;
38867754Smsmith
38967754Smsmith	if (*maskptr & mask)
39067754Smsmith		return (-1);
39167754Smsmith
39267754Smsmith	INTRMASK (*maskptr, mask);
39367754Smsmith	update_intr_masks();
39467754Smsmith
39567754Smsmith	return (0);
39667754Smsmith}
39767754Smsmith
39867754Smsmithstatic int
39967754Smsmithpcibus_imask_exclude (int irq, unsigned* maskptr)
40067754Smsmith{
40167754Smsmith	unsigned mask;
40267754Smsmith
40367754Smsmith	if (!maskptr) return (0);
40467754Smsmith
40567754Smsmith	mask = 1ul << irq;
40667754Smsmith
40767754Smsmith	if (! (*maskptr & mask))
40867754Smsmith		return (-1);
40967754Smsmith
41067754Smsmith	*maskptr &= ~mask;
41167754Smsmith	update_intr_masks();
41267754Smsmith
41367754Smsmith	return (0);
41467754Smsmith}
41567754Smsmith