linux/arch/i386/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 __devinit pci_bios_find_device (unsigned short vendor, unsigned short device_id,
 156                                        unsigned short index, unsigned char *bus, unsigned char *device_fn)
 157{
 158        unsigned short bx;
 159        unsigned short ret;
 160
 161        __asm__("lcall *(%%edi); cld\n\t"
 162                "jc 1f\n\t"
 163                "xor %%ah, %%ah\n"
 164                "1:"
 165                : "=b" (bx),
 166                  "=a" (ret)
 167                : "1" (PCIBIOS_FIND_PCI_DEVICE),
 168                  "c" (device_id),
 169                  "d" (vendor),
 170                  "S" ((int) index),
 171                  "D" (&pci_indirect));
 172        *bus = (bx >> 8) & 0xff;
 173        *device_fn = bx & 0xff;
 174        return (int) (ret & 0xff00) >> 8;
 175}
 176
 177static int pci_bios_read(unsigned int seg, unsigned int bus,
 178                         unsigned int devfn, int reg, int len, u32 *value)
 179{
 180        unsigned long result = 0;
 181        unsigned long flags;
 182        unsigned long bx = (bus << 8) | devfn;
 183
 184        if (!value || (bus > 255) || (devfn > 255) || (reg > 255))
 185                return -EINVAL;
 186
 187        spin_lock_irqsave(&pci_config_lock, flags);
 188
 189        switch (len) {
 190        case 1:
 191                __asm__("lcall *(%%esi); cld\n\t"
 192                        "jc 1f\n\t"
 193                        "xor %%ah, %%ah\n"
 194                        "1:"
 195                        : "=c" (*value),
 196                          "=a" (result)
 197                        : "1" (PCIBIOS_READ_CONFIG_BYTE),
 198                          "b" (bx),
 199                          "D" ((long)reg),
 200                          "S" (&pci_indirect));
 201                break;
 202        case 2:
 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_WORD),
 210                          "b" (bx),
 211                          "D" ((long)reg),
 212                          "S" (&pci_indirect));
 213                break;
 214        case 4:
 215                __asm__("lcall *(%%esi); cld\n\t"
 216                        "jc 1f\n\t"
 217                        "xor %%ah, %%ah\n"
 218                        "1:"
 219                        : "=c" (*value),
 220                          "=a" (result)
 221                        : "1" (PCIBIOS_READ_CONFIG_DWORD),
 222                          "b" (bx),
 223                          "D" ((long)reg),
 224                          "S" (&pci_indirect));
 225                break;
 226        }
 227
 228        spin_unlock_irqrestore(&pci_config_lock, flags);
 229
 230        return (int)((result & 0xff00) >> 8);
 231}
 232
 233static int pci_bios_write(unsigned int seg, unsigned int bus,
 234                          unsigned int devfn, int reg, int len, u32 value)
 235{
 236        unsigned long result = 0;
 237        unsigned long flags;
 238        unsigned long bx = (bus << 8) | devfn;
 239
 240        if ((bus > 255) || (devfn > 255) || (reg > 255)) 
 241                return -EINVAL;
 242
 243        spin_lock_irqsave(&pci_config_lock, flags);
 244
 245        switch (len) {
 246        case 1:
 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_BYTE),
 253                          "c" (value),
 254                          "b" (bx),
 255                          "D" ((long)reg),
 256                          "S" (&pci_indirect));
 257                break;
 258        case 2:
 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_WORD),
 265                          "c" (value),
 266                          "b" (bx),
 267                          "D" ((long)reg),
 268                          "S" (&pci_indirect));
 269                break;
 270        case 4:
 271                __asm__("lcall *(%%esi); cld\n\t"
 272                        "jc 1f\n\t"
 273                        "xor %%ah, %%ah\n"
 274                        "1:"
 275                        : "=a" (result)
 276                        : "0" (PCIBIOS_WRITE_CONFIG_DWORD),
 277                          "c" (value),
 278                          "b" (bx),
 279                          "D" ((long)reg),
 280                          "S" (&pci_indirect));
 281                break;
 282        }
 283
 284        spin_unlock_irqrestore(&pci_config_lock, flags);
 285
 286        return (int)((result & 0xff00) >> 8);
 287}
 288
 289
 290/*
 291 * Function table for BIOS32 access
 292 */
 293
 294static struct pci_raw_ops pci_bios_access = {
 295        .read =         pci_bios_read,
 296        .write =        pci_bios_write
 297};
 298
 299/*
 300 * Try to find PCI BIOS.
 301 */
 302
 303static struct pci_raw_ops * __devinit pci_find_bios(void)
 304{
 305        union bios32 *check;
 306        unsigned char sum;
 307        int i, length;
 308
 309        /*
 310         * Follow the standard procedure for locating the BIOS32 Service
 311         * directory by scanning the permissible address range from
 312         * 0xe0000 through 0xfffff for a valid BIOS32 structure.
 313         */
 314
 315        for (check = (union bios32 *) __va(0xe0000);
 316             check <= (union bios32 *) __va(0xffff0);
 317             ++check) {
 318                long sig;
 319                if (probe_kernel_address(&check->fields.signature, sig))
 320                        continue;
 321
 322                if (check->fields.signature != BIOS32_SIGNATURE)
 323                        continue;
 324                length = check->fields.length * 16;
 325                if (!length)
 326                        continue;
 327                sum = 0;
 328                for (i = 0; i < length ; ++i)
 329                        sum += check->chars[i];
 330                if (sum != 0)
 331                        continue;
 332                if (check->fields.revision != 0) {
 333                        printk("PCI: unsupported BIOS32 revision %d at 0x%p\n",
 334                                check->fields.revision, check);
 335                        continue;
 336                }
 337                DBG("PCI: BIOS32 Service Directory structure at 0x%p\n", check);
 338                if (check->fields.entry >= 0x100000) {
 339                        printk("PCI: BIOS32 entry (0x%p) in high memory, "
 340                                        "cannot use.\n", check);
 341                        return NULL;
 342                } else {
 343                        unsigned long bios32_entry = check->fields.entry;
 344                        DBG("PCI: BIOS32 Service Directory entry at 0x%lx\n",
 345                                        bios32_entry);
 346                        bios32_indirect.address = bios32_entry + PAGE_OFFSET;
 347                        if (check_pcibios())
 348                                return &pci_bios_access;
 349                }
 350                break;  /* Hopefully more than one BIOS32 cannot happen... */
 351        }
 352
 353        return NULL;
 354}
 355
 356/*
 357 * Sort the device list according to PCI BIOS. Nasty hack, but since some
 358 * fool forgot to define the `correct' device order in the PCI BIOS specs
 359 * and we want to be (possibly bug-to-bug ;-]) compatible with older kernels
 360 * which used BIOS ordering, we are bound to do this...
 361 */
 362
 363void __devinit pcibios_sort(void)
 364{
 365        LIST_HEAD(sorted_devices);
 366        struct list_head *ln;
 367        struct pci_dev *dev, *d;
 368        int idx, found;
 369        unsigned char bus, devfn;
 370
 371        DBG("PCI: Sorting device list...\n");
 372        while (!list_empty(&pci_devices)) {
 373                ln = pci_devices.next;
 374                dev = pci_dev_g(ln);
 375                idx = found = 0;
 376                while (pci_bios_find_device(dev->vendor, dev->device, idx, &bus, &devfn) == PCIBIOS_SUCCESSFUL) {
 377                        idx++;
 378                        list_for_each(ln, &pci_devices) {
 379                                d = pci_dev_g(ln);
 380                                if (d->bus->number == bus && d->devfn == devfn) {
 381                                        list_move_tail(&d->global_list, &sorted_devices);
 382                                        if (d == dev)
 383                                                found = 1;
 384                                        break;
 385                                }
 386                        }
 387                        if (ln == &pci_devices) {
 388                                printk(KERN_WARNING "PCI: BIOS reporting unknown device %02x:%02x\n", bus, devfn);
 389                                /*
 390                                 * We must not continue scanning as several buggy BIOSes
 391                                 * return garbage after the last device. Grr.
 392                                 */
 393                                break;
 394                        }
 395                }
 396                if (!found) {
 397                        printk(KERN_WARNING "PCI: Device %s not found by BIOS\n",
 398                                pci_name(dev));
 399                        list_move_tail(&dev->global_list, &sorted_devices);
 400                }
 401        }
 402        list_splice(&sorted_devices, &pci_devices);
 403}
 404
 405/*
 406 *  BIOS Functions for IRQ Routing
 407 */
 408
 409struct irq_routing_options {
 410        u16 size;
 411        struct irq_info *table;
 412        u16 segment;
 413} __attribute__((packed));
 414
 415struct irq_routing_table * __devinit pcibios_get_irq_routing_table(void)
 416{
 417        struct irq_routing_options opt;
 418        struct irq_routing_table *rt = NULL;
 419        int ret, map;
 420        unsigned long page;
 421
 422        if (!pci_bios_present)
 423                return NULL;
 424        page = __get_free_page(GFP_KERNEL);
 425        if (!page)
 426                return NULL;
 427        opt.table = (struct irq_info *) page;
 428        opt.size = PAGE_SIZE;
 429        opt.segment = __KERNEL_DS;
 430
 431        DBG("PCI: Fetching IRQ routing table... ");
 432        __asm__("push %%es\n\t"
 433                "push %%ds\n\t"
 434                "pop  %%es\n\t"
 435                "lcall *(%%esi); cld\n\t"
 436                "pop %%es\n\t"
 437                "jc 1f\n\t"
 438                "xor %%ah, %%ah\n"
 439                "1:"
 440                : "=a" (ret),
 441                  "=b" (map),
 442                  "=m" (opt)
 443                : "0" (PCIBIOS_GET_ROUTING_OPTIONS),
 444                  "1" (0),
 445                  "D" ((long) &opt),
 446                  "S" (&pci_indirect),
 447                  "m" (opt)
 448                : "memory");
 449        DBG("OK  ret=%d, size=%d, map=%x\n", ret, opt.size, map);
 450        if (ret & 0xff00)
 451                printk(KERN_ERR "PCI: Error %02x when fetching IRQ routing table.\n", (ret >> 8) & 0xff);
 452        else if (opt.size) {
 453                rt = kmalloc(sizeof(struct irq_routing_table) + opt.size, GFP_KERNEL);
 454                if (rt) {
 455                        memset(rt, 0, sizeof(struct irq_routing_table));
 456                        rt->size = opt.size + sizeof(struct irq_routing_table);
 457                        rt->exclusive_irqs = map;
 458                        memcpy(rt->slots, (void *) page, opt.size);
 459                        printk(KERN_INFO "PCI: Using BIOS Interrupt Routing Table\n");
 460                }
 461        }
 462        free_page(page);
 463        return rt;
 464}
 465EXPORT_SYMBOL(pcibios_get_irq_routing_table);
 466
 467int pcibios_set_irq_routing(struct pci_dev *dev, int pin, int irq)
 468{
 469        int ret;
 470
 471        __asm__("lcall *(%%esi); cld\n\t"
 472                "jc 1f\n\t"
 473                "xor %%ah, %%ah\n"
 474                "1:"
 475                : "=a" (ret)
 476                : "0" (PCIBIOS_SET_PCI_HW_INT),
 477                  "b" ((dev->bus->number << 8) | dev->devfn),
 478                  "c" ((irq << 8) | (pin + 10)),
 479                  "S" (&pci_indirect));
 480        return !(ret & 0xff00);
 481}
 482EXPORT_SYMBOL(pcibios_set_irq_routing);
 483
 484void __init pci_pcbios_init(void)
 485{
 486        if ((pci_probe & PCI_PROBE_BIOS) 
 487                && ((raw_pci_ops = pci_find_bios()))) {
 488                pci_probe |= PCI_BIOS_SORT;
 489                pci_bios_present = 1;
 490        }
 491}
 492
 493
lxr.linux.no kindly hosted by Redpill Linpro AS, provider of Linux consulting and operations services since 1995.