1 // SPDX-License-Identifier: GPL-2.0 2 /* 3 * direct.c - Low-level direct PCI config space access 4 */ 5 6 #include <linux/pci.h> 7 #include <linux/init.h> 8 #include <linux/dmi.h> 9 #include <asm/pci_x86.h> 10 11 /* 12 * Functions for accessing PCI base (first 256 bytes) and extended 13 * (4096 bytes per PCI function) configuration space with type 1 14 * accesses. 15 */ 16 17 #define PCI_CONF1_ADDRESS(bus, devfn, reg) \ 18 (0x80000000 | ((reg & 0xF00) << 16) | (bus << 16) \ 19 | (devfn << 8) | (reg & 0xFC)) 20 21 static int pci_conf1_read(unsigned int seg, unsigned int bus, 22 unsigned int devfn, int reg, int len, u32 *value) 23 { 24 unsigned long flags; 25 26 if (seg || (bus > 255) || (devfn > 255) || (reg > 4095)) { 27 *value = -1; 28 return -EINVAL; 29 } 30 31 raw_spin_lock_irqsave(&pci_config_lock, flags); 32 33 outl(PCI_CONF1_ADDRESS(bus, devfn, reg), 0xCF8); 34 35 switch (len) { 36 case 1: 37 *value = inb(0xCFC + (reg & 3)); 38 break; 39 case 2: 40 *value = inw(0xCFC + (reg & 2)); 41 break; 42 case 4: 43 *value = inl(0xCFC); 44 break; 45 } 46 47 raw_spin_unlock_irqrestore(&pci_config_lock, flags); 48 49 return 0; 50 } 51 52 static int pci_conf1_write(unsigned int seg, unsigned int bus, 53 unsigned int devfn, int reg, int len, u32 value) 54 { 55 unsigned long flags; 56 57 if (seg || (bus > 255) || (devfn > 255) || (reg > 4095)) 58 return -EINVAL; 59 60 raw_spin_lock_irqsave(&pci_config_lock, flags); 61 62 outl(PCI_CONF1_ADDRESS(bus, devfn, reg), 0xCF8); 63 64 switch (len) { 65 case 1: 66 outb((u8)value, 0xCFC + (reg & 3)); 67 break; 68 case 2: 69 outw((u16)value, 0xCFC + (reg & 2)); 70 break; 71 case 4: 72 outl((u32)value, 0xCFC); 73 break; 74 } 75 76 raw_spin_unlock_irqrestore(&pci_config_lock, flags); 77 78 return 0; 79 } 80 81 #undef PCI_CONF1_ADDRESS 82 83 const struct pci_raw_ops pci_direct_conf1 = { 84 .read = pci_conf1_read, 85 .write = pci_conf1_write, 86 }; 87 88 89 /* 90 * Functions for accessing PCI configuration space with type 2 accesses 91 */ 92 93 #define PCI_CONF2_ADDRESS(dev, reg) (u16)(0xC000 | (dev << 8) | reg) 94 95 static int pci_conf2_read(unsigned int seg, unsigned int bus, 96 unsigned int devfn, int reg, int len, u32 *value) 97 { 98 unsigned long flags; 99 int dev, fn; 100 101 WARN_ON(seg); 102 if ((bus > 255) || (devfn > 255) || (reg > 255)) { 103 *value = -1; 104 return -EINVAL; 105 } 106 107 dev = PCI_SLOT(devfn); 108 fn = PCI_FUNC(devfn); 109 110 if (dev & 0x10) 111 return PCIBIOS_DEVICE_NOT_FOUND; 112 113 raw_spin_lock_irqsave(&pci_config_lock, flags); 114 115 outb((u8)(0xF0 | (fn << 1)), 0xCF8); 116 outb((u8)bus, 0xCFA); 117 118 switch (len) { 119 case 1: 120 *value = inb(PCI_CONF2_ADDRESS(dev, reg)); 121 break; 122 case 2: 123 *value = inw(PCI_CONF2_ADDRESS(dev, reg)); 124 break; 125 case 4: 126 *value = inl(PCI_CONF2_ADDRESS(dev, reg)); 127 break; 128 } 129 130 outb(0, 0xCF8); 131 132 raw_spin_unlock_irqrestore(&pci_config_lock, flags); 133 134 return 0; 135 } 136 137 static int pci_conf2_write(unsigned int seg, unsigned int bus, 138 unsigned int devfn, int reg, int len, u32 value) 139 { 140 unsigned long flags; 141 int dev, fn; 142 143 WARN_ON(seg); 144 if ((bus > 255) || (devfn > 255) || (reg > 255)) 145 return -EINVAL; 146 147 dev = PCI_SLOT(devfn); 148 fn = PCI_FUNC(devfn); 149 150 if (dev & 0x10) 151 return PCIBIOS_DEVICE_NOT_FOUND; 152 153 raw_spin_lock_irqsave(&pci_config_lock, flags); 154 155 outb((u8)(0xF0 | (fn << 1)), 0xCF8); 156 outb((u8)bus, 0xCFA); 157 158 switch (len) { 159 case 1: 160 outb((u8)value, PCI_CONF2_ADDRESS(dev, reg)); 161 break; 162 case 2: 163 outw((u16)value, PCI_CONF2_ADDRESS(dev, reg)); 164 break; 165 case 4: 166 outl((u32)value, PCI_CONF2_ADDRESS(dev, reg)); 167 break; 168 } 169 170 outb(0, 0xCF8); 171 172 raw_spin_unlock_irqrestore(&pci_config_lock, flags); 173 174 return 0; 175 } 176 177 #undef PCI_CONF2_ADDRESS 178 179 static const struct pci_raw_ops pci_direct_conf2 = { 180 .read = pci_conf2_read, 181 .write = pci_conf2_write, 182 }; 183 184 185 /* 186 * Before we decide to use direct hardware access mechanisms, we try to do some 187 * trivial checks to ensure it at least _seems_ to be working -- we just test 188 * whether bus 00 contains a host bridge (this is similar to checking 189 * techniques used in XFree86, but ours should be more reliable since we 190 * attempt to make use of direct access hints provided by the PCI BIOS). 191 * 192 * This should be close to trivial, but it isn't, because there are buggy 193 * chipsets (yes, you guessed it, by Intel and Compaq) that have no class ID. 194 */ 195 static int __init pci_sanity_check(const struct pci_raw_ops *o) 196 { 197 u32 x = 0; 198 int devfn; 199 200 if (pci_probe & PCI_NO_CHECKS) 201 return 1; 202 /* Assume Type 1 works for newer systems. 203 This handles machines that don't have anything on PCI Bus 0. */ 204 if (dmi_get_bios_year() >= 2001) 205 return 1; 206 207 for (devfn = 0; devfn < 0x100; devfn++) { 208 if (o->read(0, 0, devfn, PCI_CLASS_DEVICE, 2, &x)) 209 continue; 210 if (x == PCI_CLASS_BRIDGE_HOST || x == PCI_CLASS_DISPLAY_VGA) 211 return 1; 212 213 if (o->read(0, 0, devfn, PCI_VENDOR_ID, 2, &x)) 214 continue; 215 if (x == PCI_VENDOR_ID_INTEL || x == PCI_VENDOR_ID_COMPAQ) 216 return 1; 217 } 218 219 DBG(KERN_WARNING "PCI: Sanity check failed\n"); 220 return 0; 221 } 222 223 static int __init pci_check_type1(void) 224 { 225 unsigned long flags; 226 unsigned int tmp; 227 int works = 0; 228 229 local_irq_save(flags); 230 231 outb(0x01, 0xCFB); 232 tmp = inl(0xCF8); 233 outl(0x80000000, 0xCF8); 234 if (inl(0xCF8) == 0x80000000 && pci_sanity_check(&pci_direct_conf1)) { 235 works = 1; 236 } 237 outl(tmp, 0xCF8); 238 local_irq_restore(flags); 239 240 return works; 241 } 242 243 static int __init pci_check_type2(void) 244 { 245 unsigned long flags; 246 int works = 0; 247 248 local_irq_save(flags); 249 250 outb(0x00, 0xCFB); 251 outb(0x00, 0xCF8); 252 outb(0x00, 0xCFA); 253 if (inb(0xCF8) == 0x00 && inb(0xCFA) == 0x00 && 254 pci_sanity_check(&pci_direct_conf2)) { 255 works = 1; 256 } 257 258 local_irq_restore(flags); 259 260 return works; 261 } 262 263 void __init pci_direct_init(int type) 264 { 265 if (type == 0) 266 return; 267 printk(KERN_INFO "PCI: Using configuration type %d for base access\n", 268 type); 269 if (type == 1) { 270 raw_pci_ops = &pci_direct_conf1; 271 if (raw_pci_ext_ops) 272 return; 273 if (!(pci_probe & PCI_HAS_IO_ECS)) 274 return; 275 printk(KERN_INFO "PCI: Using configuration type 1 " 276 "for extended access\n"); 277 raw_pci_ext_ops = &pci_direct_conf1; 278 return; 279 } 280 raw_pci_ops = &pci_direct_conf2; 281 } 282 283 int __init pci_direct_probe(void) 284 { 285 if ((pci_probe & PCI_PROBE_CONF1) == 0) 286 goto type2; 287 if (!request_region(0xCF8, 8, "PCI conf1")) 288 goto type2; 289 290 if (pci_check_type1()) { 291 raw_pci_ops = &pci_direct_conf1; 292 port_cf9_safe = true; 293 return 1; 294 } 295 release_region(0xCF8, 8); 296 297 type2: 298 if ((pci_probe & PCI_PROBE_CONF2) == 0) 299 return 0; 300 if (!request_region(0xCF8, 4, "PCI conf2")) 301 return 0; 302 if (!request_region(0xC000, 0x1000, "PCI conf2")) 303 goto fail2; 304 305 if (pci_check_type2()) { 306 raw_pci_ops = &pci_direct_conf2; 307 port_cf9_safe = true; 308 return 2; 309 } 310 311 release_region(0xC000, 0x1000); 312 fail2: 313 release_region(0xCF8, 4); 314 return 0; 315 } 316
Linux® is a registered trademark of Linus Torvalds in the United States and other countries.
TOMOYO® is a registered trademark of NTT DATA CORPORATION.