| 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), port: 0xCF8); | 
|---|
| 34 |  | 
|---|
| 35 | switch (len) { | 
|---|
| 36 | case 1: | 
|---|
| 37 | *value = inb(port: 0xCFC + (reg & 3)); | 
|---|
| 38 | break; | 
|---|
| 39 | case 2: | 
|---|
| 40 | *value = inw(port: 0xCFC + (reg & 2)); | 
|---|
| 41 | break; | 
|---|
| 42 | case 4: | 
|---|
| 43 | *value = inl(port: 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), port: 0xCF8); | 
|---|
| 63 |  | 
|---|
| 64 | switch (len) { | 
|---|
| 65 | case 1: | 
|---|
| 66 | outb(value: (u8)value, port: 0xCFC + (reg & 3)); | 
|---|
| 67 | break; | 
|---|
| 68 | case 2: | 
|---|
| 69 | outw(value: (u16)value, port: 0xCFC + (reg & 2)); | 
|---|
| 70 | break; | 
|---|
| 71 | case 4: | 
|---|
| 72 | outl(value: (u32)value, port: 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(value: (u8)(0xF0 | (fn << 1)), port: 0xCF8); | 
|---|
| 116 | outb(value: (u8)bus, port: 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(value: 0, port: 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(value: (u8)(0xF0 | (fn << 1)), port: 0xCF8); | 
|---|
| 156 | outb(value: (u8)bus, port: 0xCFA); | 
|---|
| 157 |  | 
|---|
| 158 | switch (len) { | 
|---|
| 159 | case 1: | 
|---|
| 160 | outb(value: (u8)value, PCI_CONF2_ADDRESS(dev, reg)); | 
|---|
| 161 | break; | 
|---|
| 162 | case 2: | 
|---|
| 163 | outw(value: (u16)value, PCI_CONF2_ADDRESS(dev, reg)); | 
|---|
| 164 | break; | 
|---|
| 165 | case 4: | 
|---|
| 166 | outl(value: (u32)value, PCI_CONF2_ADDRESS(dev, reg)); | 
|---|
| 167 | break; | 
|---|
| 168 | } | 
|---|
| 169 |  | 
|---|
| 170 | outb(value: 0, port: 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(value: 0x01, port: 0xCFB); | 
|---|
| 232 | tmp = inl(port: 0xCF8); | 
|---|
| 233 | outl(value: 0x80000000, port: 0xCF8); | 
|---|
| 234 | if (inl(port: 0xCF8) == 0x80000000 && pci_sanity_check(o: &pci_direct_conf1)) { | 
|---|
| 235 | works = 1; | 
|---|
| 236 | } | 
|---|
| 237 | outl(value: tmp, port: 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(value: 0x00, port: 0xCFB); | 
|---|
| 251 | outb(value: 0x00, port: 0xCF8); | 
|---|
| 252 | outb(value: 0x00, port: 0xCFA); | 
|---|
| 253 | if (inb(port: 0xCF8) == 0x00 && inb(port: 0xCFA) == 0x00 && | 
|---|
| 254 | pci_sanity_check(o: &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 |  | 
|---|