1 /*- 2 * Copyright (c) 1997, Stefan Esser <se@freebsd.org> 3 * Copyright (c) 2000, Michael Smith <msmith@freebsd.org> 4 * Copyright (c) 2000, BSDi 5 * All rights reserved. 6 * 7 * Redistribution and use in source and binary forms, with or without 8 * modification, are permitted provided that the following conditions 9 * are met: 10 * 1. Redistributions of source code must retain the above copyright 11 * notice unmodified, this list of conditions, and the following 12 * disclaimer. 13 * 2. Redistributions in binary form must reproduce the above copyright 14 * notice, this list of conditions and the following disclaimer in the 15 * documentation and/or other materials provided with the distribution. 16 * 17 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 18 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 19 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 20 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 21 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 22 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 23 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 24 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 25 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 26 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 27 */ 28 29 #include <sys/cdefs.h> 30 __FBSDID("$FreeBSD$"); 31 32 #include <sys/param.h> 33 #include <sys/systm.h> 34 #include <sys/bus.h> 35 #include <sys/lock.h> 36 #include <sys/kernel.h> 37 #include <sys/mutex.h> 38 #include <dev/pci/pcivar.h> 39 #include <dev/pci/pcireg.h> 40 #include <vm/vm.h> 41 #include <vm/pmap.h> 42 #include <machine/pci_cfgreg.h> 43 44 enum { 45 CFGMECH_NONE = 0, 46 CFGMECH_1, 47 CFGMECH_PCIE, 48 }; 49 50 static uint32_t pci_docfgregread(int bus, int slot, int func, int reg, 51 int bytes); 52 static int pciereg_cfgread(int bus, unsigned slot, unsigned func, 53 unsigned reg, unsigned bytes); 54 static void pciereg_cfgwrite(int bus, unsigned slot, unsigned func, 55 unsigned reg, int data, unsigned bytes); 56 static int pcireg_cfgread(int bus, int slot, int func, int reg, int bytes); 57 static void pcireg_cfgwrite(int bus, int slot, int func, int reg, int data, int bytes); 58 59 static int cfgmech; 60 static vm_offset_t pcie_base; 61 static int pcie_minbus, pcie_maxbus; 62 static uint32_t pcie_badslots; 63 static struct mtx pcicfg_mtx; 64 static int mcfg_enable = 1; 65 TUNABLE_INT("hw.pci.mcfg", &mcfg_enable); 66 67 /* 68 * Initialise access to PCI configuration space 69 */ 70 int 71 pci_cfgregopen(void) 72 { 73 static int once = 0; 74 uint64_t pciebar; 75 uint16_t did, vid; 76 77 if (!once) { 78 mtx_init(&pcicfg_mtx, "pcicfg", NULL, MTX_SPIN); 79 once = 1; 80 } 81 82 if (cfgmech != CFGMECH_NONE) 83 return (1); 84 cfgmech = CFGMECH_1; 85 86 /* 87 * Grope around in the PCI config space to see if this is a 88 * chipset that is capable of doing memory-mapped config cycles. 89 * This also implies that it can do PCIe extended config cycles. 90 */ 91 92 /* Check for supported chipsets */ 93 vid = pci_cfgregread(0, 0, 0, PCIR_VENDOR, 2); 94 did = pci_cfgregread(0, 0, 0, PCIR_DEVICE, 2); 95 switch (vid) { 96 case 0x8086: 97 switch (did) { 98 case 0x3590: 99 case 0x3592: 100 /* Intel 7520 or 7320 */ 101 pciebar = pci_cfgregread(0, 0, 0, 0xce, 2) << 16; 102 pcie_cfgregopen(pciebar, 0, 255); 103 break; 104 case 0x2580: 105 case 0x2584: 106 case 0x2590: 107 /* Intel 915, 925, or 915GM */ 108 pciebar = pci_cfgregread(0, 0, 0, 0x48, 4); 109 pcie_cfgregopen(pciebar, 0, 255); 110 break; 111 } 112 } 113 114 return (1); 115 } 116 117 static uint32_t 118 pci_docfgregread(int bus, int slot, int func, int reg, int bytes) 119 { 120 121 if (cfgmech == CFGMECH_PCIE && 122 (bus >= pcie_minbus && bus <= pcie_maxbus) && 123 (bus != 0 || !(1 << slot & pcie_badslots))) 124 return (pciereg_cfgread(bus, slot, func, reg, bytes)); 125 else 126 return (pcireg_cfgread(bus, slot, func, reg, bytes)); 127 } 128 129 /* 130 * Read configuration space register 131 */ 132 u_int32_t 133 pci_cfgregread(int bus, int slot, int func, int reg, int bytes) 134 { 135 uint32_t line; 136 137 /* 138 * Some BIOS writers seem to want to ignore the spec and put 139 * 0 in the intline rather than 255 to indicate none. Some use 140 * numbers in the range 128-254 to indicate something strange and 141 * apparently undocumented anywhere. Assume these are completely bogus 142 * and map them to 255, which the rest of the PCI code recognizes as 143 * as an invalid IRQ. 144 */ 145 if (reg == PCIR_INTLINE && bytes == 1) { 146 line = pci_docfgregread(bus, slot, func, PCIR_INTLINE, 1); 147 if (line == 0 || line >= 128) 148 line = PCI_INVALID_IRQ; 149 return (line); 150 } 151 return (pci_docfgregread(bus, slot, func, reg, bytes)); 152 } 153 154 /* 155 * Write configuration space register 156 */ 157 void 158 pci_cfgregwrite(int bus, int slot, int func, int reg, u_int32_t data, int bytes) 159 { 160 161 if (cfgmech == CFGMECH_PCIE && 162 (bus >= pcie_minbus && bus <= pcie_maxbus) && 163 (bus != 0 || !(1 << slot & pcie_badslots))) 164 pciereg_cfgwrite(bus, slot, func, reg, data, bytes); 165 else 166 pcireg_cfgwrite(bus, slot, func, reg, data, bytes); 167 } 168 169 /* 170 * Configuration space access using direct register operations 171 */ 172 173 /* enable configuration space accesses and return data port address */ 174 static int 175 pci_cfgenable(unsigned bus, unsigned slot, unsigned func, int reg, int bytes) 176 { 177 int dataport = 0; 178 179 if (bus <= PCI_BUSMAX && slot < 32 && func <= PCI_FUNCMAX && 180 reg <= PCI_REGMAX && bytes != 3 && (unsigned) bytes <= 4 && 181 (reg & (bytes - 1)) == 0) { 182 outl(CONF1_ADDR_PORT, (1 << 31) | (bus << 16) | (slot << 11) 183 | (func << 8) | (reg & ~0x03)); 184 dataport = CONF1_DATA_PORT + (reg & 0x03); 185 } 186 return (dataport); 187 } 188 189 /* disable configuration space accesses */ 190 static void 191 pci_cfgdisable(void) 192 { 193 194 /* 195 * Do nothing. Writing a 0 to the address port can apparently 196 * confuse some bridges and cause spurious access failures. 197 */ 198 } 199 200 static int 201 pcireg_cfgread(int bus, int slot, int func, int reg, int bytes) 202 { 203 int data = -1; 204 int port; 205 206 mtx_lock_spin(&pcicfg_mtx); 207 port = pci_cfgenable(bus, slot, func, reg, bytes); 208 if (port != 0) { 209 switch (bytes) { 210 case 1: 211 data = inb(port); 212 break; 213 case 2: 214 data = inw(port); 215 break; 216 case 4: 217 data = inl(port); 218 break; 219 } 220 pci_cfgdisable(); 221 } 222 mtx_unlock_spin(&pcicfg_mtx); 223 return (data); 224 } 225 226 static void 227 pcireg_cfgwrite(int bus, int slot, int func, int reg, int data, int bytes) 228 { 229 int port; 230 231 mtx_lock_spin(&pcicfg_mtx); 232 port = pci_cfgenable(bus, slot, func, reg, bytes); 233 if (port != 0) { 234 switch (bytes) { 235 case 1: 236 outb(port, data); 237 break; 238 case 2: 239 outw(port, data); 240 break; 241 case 4: 242 outl(port, data); 243 break; 244 } 245 pci_cfgdisable(); 246 } 247 mtx_unlock_spin(&pcicfg_mtx); 248 } 249 250 int 251 pcie_cfgregopen(uint64_t base, uint8_t minbus, uint8_t maxbus) 252 { 253 uint32_t val1, val2; 254 int slot; 255 256 if (!mcfg_enable) 257 return (0); 258 259 if (minbus != 0) 260 return (0); 261 262 if (bootverbose) 263 printf("PCIe: Memory Mapped configuration base @ 0x%lx\n", 264 base); 265 266 /* XXX: We should make sure this really fits into the direct map. */ 267 pcie_base = (vm_offset_t)pmap_mapdev(base, (maxbus + 1) << 20); 268 pcie_minbus = minbus; 269 pcie_maxbus = maxbus; 270 cfgmech = CFGMECH_PCIE; 271 272 /* 273 * On some AMD systems, some of the devices on bus 0 are 274 * inaccessible using memory-mapped PCI config access. Walk 275 * bus 0 looking for such devices. For these devices, we will 276 * fall back to using type 1 config access instead. 277 */ 278 if (pci_cfgregopen() != 0) { 279 for (slot = 0; slot < 32; slot++) { 280 val1 = pcireg_cfgread(0, slot, 0, 0, 4); 281 if (val1 == 0xffffffff) 282 continue; 283 284 val2 = pciereg_cfgread(0, slot, 0, 0, 4); 285 if (val2 != val1) 286 pcie_badslots |= (1 << slot); 287 } 288 } 289 290 return (1); 291 } 292 293 #define PCIE_VADDR(base, reg, bus, slot, func) \ 294 ((base) + \ 295 ((((bus) & 0xff) << 20) | \ 296 (((slot) & 0x1f) << 15) | \ 297 (((func) & 0x7) << 12) | \ 298 ((reg) & 0xfff))) 299 300 static int 301 pciereg_cfgread(int bus, unsigned slot, unsigned func, unsigned reg, 302 unsigned bytes) 303 { 304 volatile vm_offset_t va; 305 int data = -1; 306 307 if (bus < pcie_minbus || bus > pcie_maxbus || slot >= 32 || 308 func > PCI_FUNCMAX || reg >= 0x1000) 309 return (-1); 310 311 va = PCIE_VADDR(pcie_base, reg, bus, slot, func); 312 313 switch (bytes) { 314 case 4: 315 data = *(volatile uint32_t *)(va); 316 break; 317 case 2: 318 data = *(volatile uint16_t *)(va); 319 break; 320 case 1: 321 data = *(volatile uint8_t *)(va); 322 break; 323 } 324 325 return (data); 326 } 327 328 static void 329 pciereg_cfgwrite(int bus, unsigned slot, unsigned func, unsigned reg, int data, 330 unsigned bytes) 331 { 332 volatile vm_offset_t va; 333 334 if (bus < pcie_minbus || bus > pcie_maxbus || slot >= 32 || 335 func > PCI_FUNCMAX || reg >= 0x1000) 336 return; 337 338 va = PCIE_VADDR(pcie_base, reg, bus, slot, func); 339 340 switch (bytes) { 341 case 4: 342 *(volatile uint32_t *)(va) = data; 343 break; 344 case 2: 345 *(volatile uint16_t *)(va) = data; 346 break; 347 case 1: 348 *(volatile uint8_t *)(va) = data; 349 break; 350 } 351 } 352