1 /* $OpenBSD: mpbios_intr_fixup.c,v 1.6 2008/09/17 16:48:44 naddy 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 }; 50 51 const struct mpbios_icu_table * 52 mpbios_icu_lookup(pcireg_t id) 53 { 54 const struct mpbios_icu_table *mpit; 55 56 for (mpit = mpbios_icu_table; mpit->mpit_mpbios_fixup != NULL; mpit++) 57 if (PCI_VENDOR(id) == mpit->mpit_vendor && 58 PCI_PRODUCT(id) == mpit->mpit_product) 59 return (mpit); 60 61 return (NULL); 62 } 63 64 /* 65 * NVIDIA nForce4 PCI-ISA bridge. 66 */ 67 68 #define NFORCE4_PNPIRQ1 0x7c 69 #define NFORCE4_PNPIRQ2 0x80 70 #define NFORCE4_USB2_SHIFT 12 71 #define NFORCE4_USB2_MASK (0xf << NFORCE4_USB2_SHIFT) 72 #define NFORCE4_SATA1_SHIFT 28 73 #define NFORCE4_SATA1_MASK (0xf << NFORCE4_SATA1_SHIFT) 74 #define NFORCE4_SATA2_SHIFT 24 75 #define NFORCE4_SATA2_MASK (0xf << NFORCE4_SATA2_SHIFT) 76 #define NFORCE4_PNPIRQ3 0x84 77 #define NFORCE4_USB1_SHIFT 0 78 #define NFORCE4_USB1_MASK (0xf << NFORCE4_USB1_SHIFT) 79 #define NFORCE4_LAN_SHIFT 8 80 #define NFORCE4_LAN_MASK (0xf << NFORCE4_LAN_SHIFT) 81 82 void 83 nforce4_mpbios_fixup(pci_chipset_tag_t pc, pcitag_t tag) 84 { 85 pcireg_t reg; 86 int bus, pin; 87 88 pci_decompose_tag (pc, tag, &bus, NULL, NULL); 89 90 reg = pci_conf_read(pc, tag, NFORCE4_PNPIRQ2); 91 pin = (reg & NFORCE4_USB2_MASK) >> NFORCE4_USB2_SHIFT; 92 if (pin != 0) 93 mpbios_pin_fixup(bus, 2, PCI_INTERRUPT_PIN_B, pin); 94 pin = (reg & NFORCE4_SATA1_MASK) >> NFORCE4_SATA1_SHIFT; 95 if (pin != 0) 96 mpbios_pin_fixup(bus, 7, PCI_INTERRUPT_PIN_A, pin); 97 pin = (reg & NFORCE4_SATA2_MASK) >> NFORCE4_SATA2_SHIFT; 98 if (pin != 0) 99 mpbios_pin_fixup(bus, 8, PCI_INTERRUPT_PIN_A, pin); 100 101 reg = pci_conf_read(pc, tag, NFORCE4_PNPIRQ3); 102 pin = (reg & NFORCE4_USB1_MASK) >> NFORCE4_USB1_SHIFT; 103 if (pin != 0) 104 mpbios_pin_fixup(bus, 2, PCI_INTERRUPT_PIN_A, pin); 105 pin = (reg & NFORCE4_LAN_MASK) >> NFORCE4_LAN_SHIFT; 106 if (pin != 0) 107 mpbios_pin_fixup(bus, 10, PCI_INTERRUPT_PIN_A, pin); 108 } 109 110 /* 111 * NVIDIA MCP04 PCI-ISA bridge. 112 */ 113 114 void 115 mcp04_mpbios_fixup(pci_chipset_tag_t pc, pcitag_t tag) 116 { 117 pcireg_t reg; 118 int bus, pin; 119 120 pci_decompose_tag (pc, tag, &bus, NULL, NULL); 121 122 reg = pci_conf_read(pc, tag, NFORCE4_PNPIRQ2); 123 pin = (reg & NFORCE4_SATA1_MASK) >> NFORCE4_SATA1_SHIFT; 124 if (pin != 0) 125 mpbios_pin_fixup(bus, 16, PCI_INTERRUPT_PIN_A, pin); 126 pin = (reg & NFORCE4_SATA2_MASK) >> NFORCE4_SATA2_SHIFT; 127 if (pin != 0) 128 mpbios_pin_fixup(bus, 17, PCI_INTERRUPT_PIN_A, pin); 129 } 130 131 /* 132 * VIA VT8237 PCI-ISA bridge. 133 */ 134 135 void 136 via8237_mpbios_fixup(pci_chipset_tag_t pc, pcitag_t tag) 137 { 138 int bus; 139 140 pci_decompose_tag (pc, tag, &bus, NULL, NULL); 141 142 /* SATA is hardwired to APIC pin 20. */ 143 mpbios_pin_fixup(bus, 15, 2, 20); 144 } 145 146 void 147 mpbios_pin_fixup(int bus, int dev, int rawpin, int pin) 148 { 149 struct mp_bus *mpb = &mp_busses[bus]; 150 struct mp_intr_map *mip; 151 152 for (mip = mpb->mb_intrs; mip != NULL; mip = mip->next) { 153 if (mip->bus_pin == ((dev << 2) | (rawpin - 1)) && 154 mip->ioapic_pin != pin) { 155 156 if (mp_verbose) { 157 158 printf("%s: int%d attached to %s", 159 mip->ioapic->sc_pic.pic_dev.dv_xname, 160 pin, mpb->mb_name); 161 162 if (mpb->mb_idx != -1) 163 printf("%d", mpb->mb_idx); 164 165 (*(mpb->mb_intr_print))(mip->bus_pin); 166 167 printf(" (fixup)\n"); 168 } 169 170 mip->ioapic_pin = pin; 171 mip->ioapic_ih &= ~APIC_INT_PIN_MASK; 172 mip->ioapic_ih |= (pin << APIC_INT_PIN_SHIFT); 173 if (mip->ioapic->sc_pins[pin].ip_map == NULL) 174 mip->ioapic->sc_pins[pin].ip_map = mip; 175 } 176 } 177 } 178 179 void 180 mpbios_intr_fixup(void) 181 { 182 const struct mpbios_icu_table *mpit = NULL; 183 pci_chipset_tag_t pc = NULL; 184 pcitag_t icutag; 185 int device, maxdevs = pci_bus_maxdevs(pc, 0); 186 187 /* Search configuration space for a known interrupt router. */ 188 for (device = 0; device < maxdevs; device++) { 189 const struct pci_quirkdata *qd; 190 int function, nfuncs; 191 pcireg_t icuid; 192 pcireg_t bhlcr; 193 194 icutag = pci_make_tag(pc, 0, device, 0); 195 icuid = pci_conf_read(pc, icutag, PCI_ID_REG); 196 197 /* Invalid vendor ID value? */ 198 if (PCI_VENDOR(icuid) == PCI_VENDOR_INVALID) 199 continue; 200 201 qd = pci_lookup_quirkdata(PCI_VENDOR(icuid), 202 PCI_PRODUCT(icuid)); 203 204 bhlcr = pci_conf_read(pc, icutag, PCI_BHLC_REG); 205 if (PCI_HDRTYPE_MULTIFN(bhlcr) || (qd != NULL && 206 (qd->quirks & PCI_QUIRK_MULTIFUNCTION) != 0)) 207 nfuncs = 8; 208 else 209 nfuncs = 1; 210 211 for (function = 0; function < nfuncs; function++) { 212 icutag = pci_make_tag(pc, 0, device, function); 213 icuid = pci_conf_read(pc, icutag, PCI_ID_REG); 214 215 /* Invalid vendor ID value? */ 216 if (PCI_VENDOR(icuid) == PCI_VENDOR_INVALID) 217 continue; 218 219 if ((mpit = mpbios_icu_lookup(icuid))) 220 break; 221 } 222 223 if (mpit != NULL) 224 break; 225 } 226 227 if (mpit) 228 mpit->mpit_mpbios_fixup(pc, icutag); 229 } 230