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