linux/arch/x86/pci/pcbios.c
<<
>>
Prefs
   1/*
   2 * BIOS32 and PCI BIOS handling.
   3 */
   4
   5#include <linux/pci.h>
   6#include <linux/init.h>
   7#include <linux/module.h>
   8#include <linux/uaccess.h>
   9#include "pci.h"
  10#include "pci-functions.h"
  11
  12
  13/* BIOS32 signature: "_32_" */
  14#define BIOS32_SIGNATURE        (('_' << 0) + ('3' << 8) + ('2' << 16) + ('_' << 24))
  15
  16/* PCI signature: "PCI " */
  17#define PCI_SIGNATURE           (('P' << 0) + ('C' << 8) + ('I' << 16) + (' ' << 24))
  18
  19/* PCI service signature: "$PCI" */
  20#define PCI_SERVICE             (('$' << 0) + ('P' << 8) + ('C' << 16) + ('I' << 24))
  21
  22/* PCI BIOS hardware mechanism flags */
  23#define PCIBIOS_HW_TYPE1                0x01
  24#define PCIBIOS_HW_TYPE2                0x02
  25#define PCIBIOS_HW_TYPE1_SPEC           0x10
  26#define PCIBIOS_HW_TYPE2_SPEC           0x20
  27
  28/*
  29 * This is the standard structure used to identify the entry point
  30 * to the BIOS32 Service Directory, as documented in
  31 *      Standard BIOS 32-bit Service Directory Proposal
  32 *      Revision 0.4 May 24, 1993
  33 *      Phoenix Technologies Ltd.
  34 *      Norwood, MA
  35 * and the PCI BIOS specification.
  36 */
  37
  38union bios32 {
  39        struct {
  40                unsigned long signature;        /* _32_ */
  41                unsigned long entry;            /* 32 bit physical address */
  42                unsigned char revision;         /* Revision level, 0 */
  43                unsigned char length;           /* Length in paragraphs should be 01 */
  44                unsigned char checksum;         /* All bytes must add up to zero */
  45                unsigned char reserved[5];      /* Must be zero */
  46        } fields;
  47        char chars[16];
  48};
  49
  50/*
  51 * Physical address of the service directory.  I don't know if we're
  52 * allowed to have more than one of these or not, so just in case
  53 * we'll make pcibios_present() take a memory start parameter and store
  54 * the array there.
  55 */
  56
  57static struct {
  58        unsigned long address;
  59        unsigned short segment;
  60} bios32_indirect = { 0, __KERNEL_CS };
  61
  62/*
  63 * Returns the entry point for the given service, NULL on error
  64 */
  65
  66static unsigned long bios32_service(unsigned long service)
  67{
  68        unsigned char return_code;      /* %al */
  69        unsigned long address;          /* %ebx */
  70        unsigned long length;           /* %ecx */
  71        unsigned long entry;            /* %edx */
  72        unsigned long flags;
  73
  74        local_irq_save(flags);
  75        __asm__("lcall *(%%edi); cld"
  76                : "=a" (return_code),
  77                  "=b" (address),
  78                  "=c" (length),
  79                  "=d" (entry)
  80                : "0" (service),
  81                  "1" (0),
  82                  "D" (&bios32_indirect));
  83        local_irq_restore(flags);
  84
  85        switch (return_code) {
  86                case 0:
  87                        return address + entry;
  88                case 0x80:      /* Not present */
  89                        printk(KERN_WARNING "bios32_service(0x%lx): not present\n", service);
  90                        return 0;
  91                default: /* Shouldn't happen */
  92                        printk(KERN_WARNING "bios32_service(0x%lx): returned 0x%x -- BIOS bug!\n",
  93                                service, return_code);
  94                        return 0;
  95        }
  96}
  97
  98static struct {
  99        unsigned long address;
 100        unsigned short segment;
 101} pci_indirect = { 0, __KERNEL_CS };
 102
 103static int pci_bios_present;
 104
 105static int __devinit check_pcibios(void)
 106{
 107        u32 signature, eax, ebx, ecx;
 108        u8 status, major_ver, minor_ver, hw_mech;
 109        unsigned long flags, pcibios_entry;
 110
 111        if ((pcibios_entry = bios32_service(PCI_SERVICE))) {
 112                pci_indirect.address = pcibios_entry + PAGE_OFFSET;
 113
 114                local_irq_save(flags);
 115                __asm__(
 116                        "lcall *(%%edi); cld\n\t"
 117                        "jc 1f\n\t"
 118                        "xor %%ah, %%ah\n"
 119                        "1:"
 120                        : "=d" (signature),
 121                          "=a" (eax),
 122                          "=b" (ebx),
 123                          "=c" (ecx)
 124                        : "1" (PCIBIOS_PCI_BIOS_PRESENT),
 125                          "D" (&pci_indirect)
 126                        : "memory");
 127                local_irq_restore(flags);
 128
 129                status = (eax >> 8) & 0xff;
 130                hw_mech = eax & 0xff;
 131                major_ver = (ebx >> 8) & 0xff;
 132                minor_ver = ebx & 0xff;
 133                if (pcibios_last_bus < 0)
 134                        pcibios_last_bus = ecx & 0xff;
 135                DBG("PCI: BIOS probe returned s=%02x hw=%02x ver=%02x.%02x l=%02x\n",
 136                        status, hw_mech, major_ver, minor_ver, pcibios_last_bus);
 137                if (status || signature != PCI_SIGNATURE) {
 138                        printk (KERN_ERR "PCI: BIOS BUG #%x[%08x] found\n",
 139                                status, signature);
 140                        return 0;
 141                }
 142                printk(KERN_INFO "PCI: PCI BIOS revision %x.%02x entry at 0x%lx, last bus=%d\n",
 143                        major_ver, minor_ver, pcibios_entry, pcibios_last_bus);
 144#ifdef CONFIG_PCI_DIRECT
 145                if (!(hw_mech & PCIBIOS_HW_TYPE1))
 146                        pci_probe &= ~PCI_PROBE_CONF1;
 147                if (!(hw_mech & PCIBIOS_HW_TYPE2))
 148                        pci_probe &= ~PCI_PROBE_CONF2;
 149#endif
 150                return 1;
 151        }
 152        return 0;
 153}
 154
 155static int pci_bios_read(unsigned int seg, unsigned int bus,
 156                         unsigned int devfn, int reg, int len, u32 *value)
 157{
 158        unsigned long result = 0;
 159        unsigned long flags;
 160        unsigned long bx = (bus << 8) | devfn;
 161
 162        if (!value || (bus > 255) || (devfn > 255) || (reg > 255))
 163                return -EINVAL;
 164
 165        spin_lock_irqsave(&pci_config_lock, flags);
 166
 167        switch (len) {
 168        case 1:
 169                __asm__("lcall *(%%esi); cld\n\t"
 170                        "jc 1f\n\t"
 171                        "xor %%ah, %%ah\n"
 172                        "1:"
 173                        : "=c" (*value),
 174                          "=a" (result)
 175                        : "1" (PCIBIOS_READ_CONFIG_BYTE),
 176                          "b" (bx),
 177                          "D" ((long)reg),
 178                          "S" (&pci_indirect));
 179                /*
 180                 * Zero-extend the result beyond 8 bits, do not trust the
 181                 * BIOS having done it:
 182                 */
 183                *value &= 0xff;
 184                break;
 185        case 2:
 186                __asm__("lcall *(%%esi); cld\n\t"
 187                        "jc 1f\n\t"
 188                        "xor %%ah, %%ah\n"
 189                        "1:"
 190                        : "=c" (*value),
 191                          "=a" (result)
 192                        : "1" (PCIBIOS_READ_CONFIG_WORD),
 193                          "b" (bx),
 194                          "D" ((long)reg),
 195                          "S" (&pci_indirect));
 196                /*
 197                 * Zero-extend the result beyond 16 bits, do not trust the
 198                 * BIOS having done it:
 199                 */
 200                *value &= 0xffff;
 201                break;
 202        case 4:
 203                __asm__("lcall *(%%esi); cld\n\t"
 204                        "jc 1f\n\t"
 205                        "xor %%ah, %%ah\n"
 206                        "1:"
 207                        : "=c" (*value),
 208                          "=a" (result)
 209                        : "1" (PCIBIOS_READ_CONFIG_DWORD),
 210                          "b" (bx),
 211                          "D" ((long)reg),
 212                          "S" (&pci_indirect));
 213                break;
 214        }
 215
 216        spin_unlock_irqrestore(&pci_config_lock, flags);
 217
 218        return (int)((result & 0xff00) >> 8);
 219}
 220
 221static int pci_bios_write(unsigned int seg, unsigned int bus,
 222                          unsigned int devfn, int reg, int len, u32 value)
 223{
 224        unsigned long result = 0;
 225        unsigned long flags;
 226        unsigned long bx = (bus << 8) | devfn;
 227
 228        if ((bus > 255) || (devfn > 255) || (reg > 255)) 
 229                return -EINVAL;
 230
 231        spin_lock_irqsave(&pci_config_lock, flags);
 232
 233        switch (len) {
 234        case 1:
 235                __asm__("lcall *(%%esi); cld\n\t"
 236                        "jc 1f\n\t"
 237                        "xor %%ah, %%ah\n"
 238                        "1:"
 239                        : "=a" (result)
 240                        : "0" (PCIBIOS_WRITE_CONFIG_BYTE),
 241                          "c" (value),
 242                          "b" (bx),
 243                          "D" ((long)reg),
 244                          "S" (&pci_indirect));
 245                break;
 246        case 2:
 247                __asm__("lcall *(%%esi); cld\n\t"
 248                        "jc 1f\n\t"
 249                        "xor %%ah, %%ah\n"
 250                        "1:"
 251                        : "=a" (result)
 252                        : "0" (PCIBIOS_WRITE_CONFIG_WORD),
 253                          "c" (value),
 254                          "b" (bx),
 255                          "D" ((long)reg),
 256                          "S" (&pci_indirect));
 257                break;
 258        case 4:
 259                __asm__("lcall *(%%esi); cld\n\t"
 260                        "jc 1f\n\t"
 261                        "xor %%ah, %%ah\n"
 262                        "1:"
 263                        : "=a" (result)
 264                        : "0" (PCIBIOS_WRITE_CONFIG_DWORD),
 265                          "c" (value),
 266                          "b" (bx),
 267                          "D" ((long)reg),
 268                          "S" (&pci_indirect));
 269                break;
 270        }
 271
 272        spin_unlock_irqrestore(&pci_config_lock, flags);
 273
 274        return (int)((result & 0xff00) >> 8);
 275}
 276
 277
 278/*
 279 * Function table for BIOS32 access
 280 */
 281
 282static struct pci_raw_ops pci_bios_access = {
 283        .read =         pci_bios_read,
 284        .write =        pci_bios_write
 285};
 286
 287/*
 288 * Try to find PCI BIOS.
 289 */
 290
 291static struct pci_raw_ops * __devinit pci_find_bios(void)
 292{
 293        union bios32 *check;
 294        unsigned char sum;
 295        int i, length;
 296
 297        /*
 298         * Follow the standard procedure for locating the BIOS32 Service
 299         * directory by scanning the permissible address range from
 300         * 0xe0000 through 0xfffff for a valid BIOS32 structure.
 301         */
 302
 303        for (check = (union bios32 *) __va(0xe0000);
 304             check <= (union bios32 *) __va(0xffff0);
 305             ++check) {
 306                long sig;
 307                if (probe_kernel_address(&check->fields.signature, sig))
 308                        continue;
 309
 310                if (check->fields.signature != BIOS32_SIGNATURE)
 311                        continue;
 312                length = check->fields.length * 16;
 313                if (!length)
 314                        continue;
 315                sum = 0;
 316                for (i = 0; i < length ; ++i)
 317                        sum += check->chars[i];
 318                if (sum != 0)
 319                        continue;
 320                if (check->fields.revision != 0) {
 321                        printk("PCI: unsupported BIOS32 revision %d at 0x%p\n",
 322                                check->fields.revision, check);
 323                        continue;
 324                }
 325                DBG("PCI: BIOS32 Service Directory structure at 0x%p\n", check);
 326                if (check->fields.entry >= 0x100000) {
 327                        printk("PCI: BIOS32 entry (0x%p) in high memory, "
 328                                        "cannot use.\n", check);
 329                        return NULL;
 330                } else {
 331                        unsigned long bios32_entry = check->fields.entry;
 332                        DBG("PCI: BIOS32 Service Directory entry at 0x%lx\n",
 333                                        bios32_entry);
 334                        bios32_indirect.address = bios32_entry + PAGE_OFFSET;
 335                        if (check_pcibios())
 336                                return &pci_bios_access;
 337                }
 338                break;  /* Hopefully more than one BIOS32 cannot happen... */
 339        }
 340
 341        return NULL;
 342}
 343
 344/*
 345 *  BIOS Functions for IRQ Routing
 346 */
 347
 348struct irq_routing_options {
 349        u16 size;
 350        struct irq_info *table;
 351        u16 segment;
 352} __attribute__((packed));
 353
 354struct irq_routing_table * pcibios_get_irq_routing_table(void)
 355{
 356        struct irq_routing_options opt;
 357        struct irq_routing_table *rt = NULL;
 358        int ret, map;
 359        unsigned long page;
 360
 361        if (!pci_bios_present)
 362                return NULL;
 363        page = __get_free_page(GFP_KERNEL);
 364        if (!page)
 365                return NULL;
 366        opt.table = (struct irq_info *) page;
 367        opt.size = PAGE_SIZE;
 368        opt.segment = __KERNEL_DS;
 369
 370        DBG("PCI: Fetching IRQ routing table... ");
 371        __asm__("push %%es\n\t"
 372                "push %%ds\n\t"
 373                "pop  %%es\n\t"
 374                "lcall *(%%esi); cld\n\t"
 375                "pop %%es\n\t"
 376                "jc 1f\n\t"
 377                "xor %%ah, %%ah\n"
 378                "1:"
 379                : "=a" (ret),
 380                  "=b" (map),
 381                  "=m" (opt)
 382                : "0" (PCIBIOS_GET_ROUTING_OPTIONS),
 383                  "1" (0),
 384                  "D" ((long) &opt),
 385                  "S" (&pci_indirect),
 386                  "m" (opt)
 387                : "memory");
 388        DBG("OK  ret=%d, size=%d, map=%x\n", ret, opt.size, map);
 389        if (ret & 0xff00)
 390                printk(KERN_ERR "PCI: Error %02x when fetching IRQ routing table.\n", (ret >> 8) & 0xff);
 391        else if (opt.size) {
 392                rt = kmalloc(sizeof(struct irq_routing_table) + opt.size, GFP_KERNEL);
 393                if (rt) {
 394                        memset(rt, 0, sizeof(struct irq_routing_table));
 395                        rt->size = opt.size + sizeof(struct irq_routing_table);
 396                        rt->exclusive_irqs = map;
 397                        memcpy(rt->slots, (void *) page, opt.size);
 398                        printk(KERN_INFO "PCI: Using BIOS Interrupt Routing Table\n");
 399                }
 400        }
 401        free_page(page);
 402        return rt;
 403}
 404EXPORT_SYMBOL(pcibios_get_irq_routing_table);
 405
 406int pcibios_set_irq_routing(struct pci_dev *dev, int pin, int irq)
 407{
 408        int ret;
 409
 410        __asm__("lcall *(%%esi); cld\n\t"
 411                "jc 1f\n\t"
 412                "xor %%ah, %%ah\n"
 413                "1:"
 414                : "=a" (ret)
 415                : "0" (PCIBIOS_SET_PCI_HW_INT),
 416                  "b" ((dev->bus->number << 8) | dev->devfn),
 417                  "c" ((irq << 8) | (pin + 10)),
 418                  "S" (&pci_indirect));
 419        return !(ret & 0xff00);
 420}
 421EXPORT_SYMBOL(pcibios_set_irq_routing);
 422
 423void __init pci_pcbios_init(void)
 424{
 425        if ((pci_probe & PCI_PROBE_BIOS) 
 426                && ((raw_pci_ops = pci_find_bios()))) {
 427                pci_bios_present = 1;
 428        }
 429}
 430
 431
lxr.linux.no kindly hosted by Redpill Linpro AS, provider of Linux consulting and operations services since 1995.