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