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