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