xref: /openbsd-src/sys/arch/i386/i386/mpbios_intr_fixup.c (revision eb251e41d2921ab0b77eac152189478502c93420)
1*eb251e41Sderaadt /*	$OpenBSD: mpbios_intr_fixup.c,v 1.6 2015/08/10 12:12:42 deraadt Exp $	*/
2a8ae4dddSkettenis 
3a8ae4dddSkettenis /*
4a8ae4dddSkettenis  * Copyright (c) 2006 Mark Kettenis
5a8ae4dddSkettenis  *
6a8ae4dddSkettenis  * Permission to use, copy, modify, and distribute this software for any
7a8ae4dddSkettenis  * purpose with or without fee is hereby granted, provided that the above
8a8ae4dddSkettenis  * copyright notice and this permission notice appear in all copies.
9a8ae4dddSkettenis  *
10a8ae4dddSkettenis  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
11a8ae4dddSkettenis  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
12a8ae4dddSkettenis  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
13a8ae4dddSkettenis  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
14a8ae4dddSkettenis  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
15a8ae4dddSkettenis  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
16a8ae4dddSkettenis  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17a8ae4dddSkettenis  */
18a8ae4dddSkettenis 
19a8ae4dddSkettenis #include <sys/param.h>
20a8ae4dddSkettenis #include <sys/systm.h>
21a8ae4dddSkettenis 
22a8ae4dddSkettenis #include <dev/pci/pcireg.h>
23a8ae4dddSkettenis #include <dev/pci/pcivar.h>
24a8ae4dddSkettenis #include <dev/pci/pcidevs.h>
25a8ae4dddSkettenis 
26a8ae4dddSkettenis #include <machine/i82093var.h>
27a8ae4dddSkettenis #include <machine/mpbiosvar.h>
28a8ae4dddSkettenis 
29a8ae4dddSkettenis void mpbios_pin_fixup(int, int, int, int);
30a8ae4dddSkettenis const struct mpbios_icu_table *mpbios_icu_lookup(pcireg_t);
31a8ae4dddSkettenis 
32a8ae4dddSkettenis void via8237_mpbios_fixup(pci_chipset_tag_t, pcitag_t);
33a8ae4dddSkettenis void nforce4_mpbios_fixup(pci_chipset_tag_t, pcitag_t);
34f0a0739fSkettenis void mcp04_mpbios_fixup(pci_chipset_tag_t, pcitag_t);
35a8ae4dddSkettenis 
36a8ae4dddSkettenis const struct mpbios_icu_table {
37a8ae4dddSkettenis 	pci_vendor_id_t mpit_vendor;
38a8ae4dddSkettenis 	pci_product_id_t mpit_product;
39a8ae4dddSkettenis 	void (*mpit_mpbios_fixup)(pci_chipset_tag_t, pcitag_t);
40a8ae4dddSkettenis } mpbios_icu_table[] = {
41a8ae4dddSkettenis 	{ PCI_VENDOR_VIATECH,	PCI_PRODUCT_VIATECH_VT8237_ISA,
42a8ae4dddSkettenis 	  via8237_mpbios_fixup },
43de9c9519Sbrad 	{ PCI_VENDOR_NVIDIA,	PCI_PRODUCT_NVIDIA_NFORCE4_ISA1,
44a8ae4dddSkettenis 	  nforce4_mpbios_fixup },
45a8ae4dddSkettenis 	{ PCI_VENDOR_NVIDIA,	PCI_PRODUCT_NVIDIA_NFORCE4_ISA2,
46f0a0739fSkettenis 	  nforce4_mpbios_fixup },
47564255deSderaadt 	{ PCI_VENDOR_NVIDIA,	PCI_PRODUCT_NVIDIA_MCP04_ISA,
48*eb251e41Sderaadt 	  mcp04_mpbios_fixup },
49*eb251e41Sderaadt 	{ 0,			0,
50*eb251e41Sderaadt 	  NULL},
51a8ae4dddSkettenis };
52a8ae4dddSkettenis 
53a8ae4dddSkettenis const struct mpbios_icu_table *
mpbios_icu_lookup(pcireg_t id)54a8ae4dddSkettenis mpbios_icu_lookup(pcireg_t id)
55a8ae4dddSkettenis {
56a8ae4dddSkettenis 	const struct mpbios_icu_table *mpit;
57a8ae4dddSkettenis 
58a8ae4dddSkettenis 	for (mpit = mpbios_icu_table; mpit->mpit_mpbios_fixup != NULL; mpit++)
59a8ae4dddSkettenis 		if (PCI_VENDOR(id) == mpit->mpit_vendor &&
60a8ae4dddSkettenis 		    PCI_PRODUCT(id) == mpit->mpit_product)
61a8ae4dddSkettenis 			return (mpit);
62a8ae4dddSkettenis 
63a8ae4dddSkettenis 	return (NULL);
64a8ae4dddSkettenis }
65a8ae4dddSkettenis 
66a8ae4dddSkettenis /*
67a8ae4dddSkettenis  * NVIDIA nForce4 PCI-ISA bridge.
68a8ae4dddSkettenis  */
69a8ae4dddSkettenis 
70a8ae4dddSkettenis #define NFORCE4_PNPIRQ1	0x7c
71a8ae4dddSkettenis #define NFORCE4_PNPIRQ2	0x80
72a8ae4dddSkettenis #define  NFORCE4_USB2_SHIFT	12
73a8ae4dddSkettenis #define  NFORCE4_USB2_MASK	(0xf << NFORCE4_USB2_SHIFT)
74a8ae4dddSkettenis #define  NFORCE4_SATA1_SHIFT	28
75a8ae4dddSkettenis #define  NFORCE4_SATA1_MASK	(0xf << NFORCE4_SATA1_SHIFT)
76a8ae4dddSkettenis #define  NFORCE4_SATA2_SHIFT	24
77a8ae4dddSkettenis #define  NFORCE4_SATA2_MASK	(0xf << NFORCE4_SATA2_SHIFT)
78a8ae4dddSkettenis #define NFORCE4_PNPIRQ3	0x84
79a8ae4dddSkettenis #define  NFORCE4_USB1_SHIFT	0
80a8ae4dddSkettenis #define  NFORCE4_USB1_MASK	(0xf << NFORCE4_USB1_SHIFT)
81a8ae4dddSkettenis #define  NFORCE4_LAN_SHIFT	8
82a8ae4dddSkettenis #define  NFORCE4_LAN_MASK	(0xf << NFORCE4_LAN_SHIFT)
83a8ae4dddSkettenis 
84a8ae4dddSkettenis void
nforce4_mpbios_fixup(pci_chipset_tag_t pc,pcitag_t tag)85a8ae4dddSkettenis nforce4_mpbios_fixup(pci_chipset_tag_t pc, pcitag_t tag)
86a8ae4dddSkettenis {
87a8ae4dddSkettenis 	pcireg_t reg;
88a8ae4dddSkettenis 	int bus, pin;
89a8ae4dddSkettenis 
90a8ae4dddSkettenis 	pci_decompose_tag (pc, tag, &bus, NULL, NULL);
91a8ae4dddSkettenis 
92a8ae4dddSkettenis 	reg = pci_conf_read(pc, tag, NFORCE4_PNPIRQ2);
93a8ae4dddSkettenis 	pin = (reg & NFORCE4_USB2_MASK) >> NFORCE4_USB2_SHIFT;
94a8ae4dddSkettenis 	if (pin != 0)
95a8ae4dddSkettenis 		mpbios_pin_fixup(bus, 2, PCI_INTERRUPT_PIN_B, pin);
96a8ae4dddSkettenis 	pin = (reg & NFORCE4_SATA1_MASK) >> NFORCE4_SATA1_SHIFT;
97a8ae4dddSkettenis 	if (pin != 0)
98a8ae4dddSkettenis 		mpbios_pin_fixup(bus, 7, PCI_INTERRUPT_PIN_A, pin);
99a8ae4dddSkettenis 	pin = (reg & NFORCE4_SATA2_MASK) >> NFORCE4_SATA2_SHIFT;
100a8ae4dddSkettenis 	if (pin != 0)
101a8ae4dddSkettenis 		mpbios_pin_fixup(bus, 8, PCI_INTERRUPT_PIN_A, pin);
102a8ae4dddSkettenis 
103a8ae4dddSkettenis 	reg = pci_conf_read(pc, tag, NFORCE4_PNPIRQ3);
104a8ae4dddSkettenis 	pin = (reg & NFORCE4_USB1_MASK) >> NFORCE4_USB1_SHIFT;
105a8ae4dddSkettenis 	if (pin != 0)
106a8ae4dddSkettenis 		mpbios_pin_fixup(bus, 2, PCI_INTERRUPT_PIN_A, pin);
107a8ae4dddSkettenis 	pin = (reg & NFORCE4_LAN_MASK) >> NFORCE4_LAN_SHIFT;
108a8ae4dddSkettenis 	if (pin != 0)
109a8ae4dddSkettenis 		mpbios_pin_fixup(bus, 10, PCI_INTERRUPT_PIN_A, pin);
110a8ae4dddSkettenis }
111a8ae4dddSkettenis 
112a8ae4dddSkettenis /*
113f0a0739fSkettenis  * NVIDIA MCP04 PCI-ISA bridge.
114f0a0739fSkettenis  */
115f0a0739fSkettenis 
116f0a0739fSkettenis void
mcp04_mpbios_fixup(pci_chipset_tag_t pc,pcitag_t tag)117f0a0739fSkettenis mcp04_mpbios_fixup(pci_chipset_tag_t pc, pcitag_t tag)
118f0a0739fSkettenis {
119f0a0739fSkettenis 	pcireg_t reg;
120f0a0739fSkettenis 	int bus, pin;
121f0a0739fSkettenis 
122f0a0739fSkettenis 	pci_decompose_tag (pc, tag, &bus, NULL, NULL);
123f0a0739fSkettenis 
124f0a0739fSkettenis 	reg = pci_conf_read(pc, tag, NFORCE4_PNPIRQ2);
125f0a0739fSkettenis 	pin = (reg & NFORCE4_SATA1_MASK) >> NFORCE4_SATA1_SHIFT;
126f0a0739fSkettenis 	if (pin != 0)
127f0a0739fSkettenis 		mpbios_pin_fixup(bus, 16, PCI_INTERRUPT_PIN_A, pin);
128f0a0739fSkettenis 	pin = (reg & NFORCE4_SATA2_MASK) >> NFORCE4_SATA2_SHIFT;
129f0a0739fSkettenis 	if (pin != 0)
130f0a0739fSkettenis 		mpbios_pin_fixup(bus, 17, PCI_INTERRUPT_PIN_A, pin);
131f0a0739fSkettenis }
132f0a0739fSkettenis 
133f0a0739fSkettenis /*
134a8ae4dddSkettenis  * VIA VT8237 PCI-ISA bridge.
135a8ae4dddSkettenis  */
136a8ae4dddSkettenis 
137a8ae4dddSkettenis void
via8237_mpbios_fixup(pci_chipset_tag_t pc,pcitag_t tag)138a8ae4dddSkettenis via8237_mpbios_fixup(pci_chipset_tag_t pc, pcitag_t tag)
139a8ae4dddSkettenis {
140a8ae4dddSkettenis 	int bus;
141a8ae4dddSkettenis 
142a8ae4dddSkettenis 	pci_decompose_tag (pc, tag, &bus, NULL, NULL);
143a8ae4dddSkettenis 
144a8ae4dddSkettenis 	/* SATA is hardwired to APIC pin 20. */
145a8ae4dddSkettenis 	mpbios_pin_fixup(bus, 15, 2, 20);
146a8ae4dddSkettenis }
147a8ae4dddSkettenis 
148a8ae4dddSkettenis void
mpbios_pin_fixup(int bus,int dev,int rawpin,int pin)149a8ae4dddSkettenis mpbios_pin_fixup(int bus, int dev, int rawpin, int pin)
150a8ae4dddSkettenis {
151a8ae4dddSkettenis 	struct mp_bus *mpb = &mp_busses[bus];
152a8ae4dddSkettenis 	struct mp_intr_map *mip;
153a8ae4dddSkettenis 
154a8ae4dddSkettenis 	for (mip = mpb->mb_intrs; mip != NULL; mip = mip->next) {
155a8ae4dddSkettenis 		if (mip->bus_pin == ((dev << 2) | (rawpin - 1)) &&
156a8ae4dddSkettenis 		    mip->ioapic_pin != pin) {
157a8ae4dddSkettenis 
158a8ae4dddSkettenis 			if (mp_verbose) {
159a8ae4dddSkettenis 
160a8ae4dddSkettenis 				printf("%s: int%d attached to %s",
161329fe926Skettenis 				    mip->ioapic->sc_pic.pic_name,
162a8ae4dddSkettenis 				    pin, mpb->mb_name);
163a8ae4dddSkettenis 
164a8ae4dddSkettenis 				if (mpb->mb_idx != -1)
165a8ae4dddSkettenis 					printf("%d", mpb->mb_idx);
166a8ae4dddSkettenis 
167a8ae4dddSkettenis 				(*(mpb->mb_intr_print))(mip->bus_pin);
168a8ae4dddSkettenis 
169a8ae4dddSkettenis 				printf(" (fixup)\n");
170a8ae4dddSkettenis 			}
171a8ae4dddSkettenis 
172a8ae4dddSkettenis 			mip->ioapic_pin = pin;
173a8ae4dddSkettenis 			mip->ioapic_ih &= ~APIC_INT_PIN_MASK;
174a8ae4dddSkettenis 			mip->ioapic_ih |= (pin << APIC_INT_PIN_SHIFT);
175a8ae4dddSkettenis 			if (mip->ioapic->sc_pins[pin].ip_map == NULL)
176a8ae4dddSkettenis 				mip->ioapic->sc_pins[pin].ip_map = mip;
177a8ae4dddSkettenis 		}
178a8ae4dddSkettenis 	}
179a8ae4dddSkettenis }
180a8ae4dddSkettenis 
181a8ae4dddSkettenis void
mpbios_intr_fixup(void)182a8ae4dddSkettenis mpbios_intr_fixup(void)
183a8ae4dddSkettenis {
184a8ae4dddSkettenis 	const struct mpbios_icu_table *mpit = NULL;
185a8ae4dddSkettenis 	pci_chipset_tag_t pc = NULL;
186a8ae4dddSkettenis 	pcitag_t icutag;
187a8ae4dddSkettenis 	int device, maxdevs = pci_bus_maxdevs(pc, 0);
188a8ae4dddSkettenis 
189a8ae4dddSkettenis 	/* Search configuration space for a known interrupt router. */
190a8ae4dddSkettenis 	for (device = 0; device < maxdevs; device++) {
191a8ae4dddSkettenis 		const struct pci_quirkdata *qd;
192a8ae4dddSkettenis 		int function, nfuncs;
193a8ae4dddSkettenis 		pcireg_t icuid;
194a8ae4dddSkettenis 		pcireg_t bhlcr;
195a8ae4dddSkettenis 
196a8ae4dddSkettenis 		icutag = pci_make_tag(pc, 0, device, 0);
197a8ae4dddSkettenis 		icuid = pci_conf_read(pc, icutag, PCI_ID_REG);
198a8ae4dddSkettenis 
199a8ae4dddSkettenis 		/* Invalid vendor ID value? */
200a8ae4dddSkettenis 		if (PCI_VENDOR(icuid) == PCI_VENDOR_INVALID)
201a8ae4dddSkettenis 			continue;
202a8ae4dddSkettenis 
203a8ae4dddSkettenis 		qd = pci_lookup_quirkdata(PCI_VENDOR(icuid),
204a8ae4dddSkettenis 	       	    PCI_PRODUCT(icuid));
205a8ae4dddSkettenis 
206a8ae4dddSkettenis 		bhlcr = pci_conf_read(pc, icutag, PCI_BHLC_REG);
207a8ae4dddSkettenis 		if (PCI_HDRTYPE_MULTIFN(bhlcr) || (qd != NULL &&
208a8ae4dddSkettenis 		    (qd->quirks & PCI_QUIRK_MULTIFUNCTION) != 0))
209a8ae4dddSkettenis 			nfuncs = 8;
210a8ae4dddSkettenis 		else
211a8ae4dddSkettenis 			nfuncs = 1;
212a8ae4dddSkettenis 
213a8ae4dddSkettenis 		for (function = 0; function < nfuncs; function++) {
214a8ae4dddSkettenis 			icutag = pci_make_tag(pc, 0, device, function);
215a8ae4dddSkettenis 			icuid = pci_conf_read(pc, icutag, PCI_ID_REG);
216a8ae4dddSkettenis 
217a8ae4dddSkettenis 			/* Invalid vendor ID value? */
218a8ae4dddSkettenis 			if (PCI_VENDOR(icuid) == PCI_VENDOR_INVALID)
219a8ae4dddSkettenis 				continue;
220a8ae4dddSkettenis 
221a8ae4dddSkettenis 			if ((mpit = mpbios_icu_lookup(icuid)))
222a8ae4dddSkettenis 				break;
223a8ae4dddSkettenis 		}
224a8ae4dddSkettenis 
225a8ae4dddSkettenis 		if (mpit != NULL)
226a8ae4dddSkettenis 			break;
227a8ae4dddSkettenis 	}
228a8ae4dddSkettenis 
229a8ae4dddSkettenis 	if (mpit)
230a8ae4dddSkettenis 		mpit->mpit_mpbios_fixup(pc, icutag);
231a8ae4dddSkettenis }
232