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