linux/drivers/pci/rom.c
<<
>>
Prefs
   1/*
   2 * drivers/pci/rom.c
   3 *
   4 * (C) Copyright 2004 Jon Smirl <jonsmirl@yahoo.com>
   5 * (C) Copyright 2004 Silicon Graphics, Inc. Jesse Barnes <jbarnes@sgi.com>
   6 *
   7 * PCI ROM access routines
   8 */
   9#include <linux/kernel.h>
  10#include <linux/pci.h>
  11#include <linux/slab.h>
  12
  13#include "pci.h"
  14
  15/**
  16 * pci_enable_rom - enable ROM decoding for a PCI device
  17 * @pdev: PCI device to enable
  18 *
  19 * Enable ROM decoding on @dev.  This involves simply turning on the last
  20 * bit of the PCI ROM BAR.  Note that some cards may share address decoders
  21 * between the ROM and other resources, so enabling it may disable access
  22 * to MMIO registers or other card memory.
  23 */
  24int pci_enable_rom(struct pci_dev *pdev)
  25{
  26        struct resource *res = pdev->resource + PCI_ROM_RESOURCE;
  27        struct pci_bus_region region;
  28        u32 rom_addr;
  29
  30        if (!res->flags)
  31                return -1;
  32
  33        pcibios_resource_to_bus(pdev, &region, res);
  34        pci_read_config_dword(pdev, pdev->rom_base_reg, &rom_addr);
  35        rom_addr &= ~PCI_ROM_ADDRESS_MASK;
  36        rom_addr |= region.start | PCI_ROM_ADDRESS_ENABLE;
  37        pci_write_config_dword(pdev, pdev->rom_base_reg, rom_addr);
  38        return 0;
  39}
  40
  41/**
  42 * pci_disable_rom - disable ROM decoding for a PCI device
  43 * @pdev: PCI device to disable
  44 *
  45 * Disable ROM decoding on a PCI device by turning off the last bit in the
  46 * ROM BAR.
  47 */
  48void pci_disable_rom(struct pci_dev *pdev)
  49{
  50        u32 rom_addr;
  51        pci_read_config_dword(pdev, pdev->rom_base_reg, &rom_addr);
  52        rom_addr &= ~PCI_ROM_ADDRESS_ENABLE;
  53        pci_write_config_dword(pdev, pdev->rom_base_reg, rom_addr);
  54}
  55
  56/**
  57 * pci_get_rom_size - obtain the actual size of the ROM image
  58 * @pdev: target PCI device
  59 * @rom: kernel virtual pointer to image of ROM
  60 * @size: size of PCI window
  61 *  return: size of actual ROM image
  62 *
  63 * Determine the actual length of the ROM image.
  64 * The PCI window size could be much larger than the
  65 * actual image size.
  66 */
  67size_t pci_get_rom_size(struct pci_dev *pdev, void __iomem *rom, size_t size)
  68{
  69        void __iomem *image;
  70        int last_image;
  71
  72        image = rom;
  73        do {
  74                void __iomem *pds;
  75                /* Standard PCI ROMs start out with these bytes 55 AA */
  76                if (readb(image) != 0x55) {
  77                        dev_err(&pdev->dev, "Invalid ROM contents\n");
  78                        break;
  79                }
  80                if (readb(image + 1) != 0xAA)
  81                        break;
  82                /* get the PCI data structure and check its signature */
  83                pds = image + readw(image + 24);
  84                if (readb(pds) != 'P')
  85                        break;
  86                if (readb(pds + 1) != 'C')
  87                        break;
  88                if (readb(pds + 2) != 'I')
  89                        break;
  90                if (readb(pds + 3) != 'R')
  91                        break;
  92                last_image = readb(pds + 21) & 0x80;
  93                /* this length is reliable */
  94                image += readw(pds + 16) * 512;
  95        } while (!last_image);
  96
  97        /* never return a size larger than the PCI resource window */
  98        /* there are known ROMs that get the size wrong */
  99        return min((size_t)(image - rom), size);
 100}
 101
 102/**
 103 * pci_map_rom - map a PCI ROM to kernel space
 104 * @pdev: pointer to pci device struct
 105 * @size: pointer to receive size of pci window over ROM
 106 *
 107 * Return: kernel virtual pointer to image of ROM
 108 *
 109 * Map a PCI ROM into kernel space. If ROM is boot video ROM,
 110 * the shadow BIOS copy will be returned instead of the
 111 * actual ROM.
 112 */
 113void __iomem *pci_map_rom(struct pci_dev *pdev, size_t *size)
 114{
 115        struct resource *res = &pdev->resource[PCI_ROM_RESOURCE];
 116        loff_t start;
 117        void __iomem *rom;
 118
 119        /*
 120         * IORESOURCE_ROM_SHADOW set on x86, x86_64 and IA64 supports legacy
 121         * memory map if the VGA enable bit of the Bridge Control register is
 122         * set for embedded VGA.
 123         */
 124        if (res->flags & IORESOURCE_ROM_SHADOW) {
 125                /* primary video rom always starts here */
 126                start = (loff_t)0xC0000;
 127                *size = 0x20000; /* cover C000:0 through E000:0 */
 128        } else {
 129                if (res->flags &
 130                        (IORESOURCE_ROM_COPY | IORESOURCE_ROM_BIOS_COPY)) {
 131                        *size = pci_resource_len(pdev, PCI_ROM_RESOURCE);
 132                        return (void __iomem *)(unsigned long)
 133                                pci_resource_start(pdev, PCI_ROM_RESOURCE);
 134                } else {
 135                        /* assign the ROM an address if it doesn't have one */
 136                        if (res->parent == NULL &&
 137                            pci_assign_resource(pdev,PCI_ROM_RESOURCE))
 138                                return NULL;
 139                        start = pci_resource_start(pdev, PCI_ROM_RESOURCE);
 140                        *size = pci_resource_len(pdev, PCI_ROM_RESOURCE);
 141                        if (*size == 0)
 142                                return NULL;
 143
 144                        /* Enable ROM space decodes */
 145                        if (pci_enable_rom(pdev))
 146                                return NULL;
 147                }
 148        }
 149
 150        rom = ioremap(start, *size);
 151        if (!rom) {
 152                /* restore enable if ioremap fails */
 153                if (!(res->flags & (IORESOURCE_ROM_ENABLE |
 154                                    IORESOURCE_ROM_SHADOW |
 155                                    IORESOURCE_ROM_COPY)))
 156                        pci_disable_rom(pdev);
 157                return NULL;
 158        }
 159
 160        /*
 161         * Try to find the true size of the ROM since sometimes the PCI window
 162         * size is much larger than the actual size of the ROM.
 163         * True size is important if the ROM is going to be copied.
 164         */
 165        *size = pci_get_rom_size(pdev, rom, *size);
 166        return rom;
 167}
 168
 169#if 0
 170/**
 171 * pci_map_rom_copy - map a PCI ROM to kernel space, create a copy
 172 * @pdev: pointer to pci device struct
 173 * @size: pointer to receive size of pci window over ROM
 174 *
 175 * Return: kernel virtual pointer to image of ROM
 176 *
 177 * Map a PCI ROM into kernel space. If ROM is boot video ROM,
 178 * the shadow BIOS copy will be returned instead of the
 179 * actual ROM.
 180 */
 181void __iomem *pci_map_rom_copy(struct pci_dev *pdev, size_t *size)
 182{
 183        struct resource *res = &pdev->resource[PCI_ROM_RESOURCE];
 184        void __iomem *rom;
 185
 186        rom = pci_map_rom(pdev, size);
 187        if (!rom)
 188                return NULL;
 189
 190        if (res->flags & (IORESOURCE_ROM_COPY | IORESOURCE_ROM_SHADOW |
 191                          IORESOURCE_ROM_BIOS_COPY))
 192                return rom;
 193
 194        res->start = (unsigned long)kmalloc(*size, GFP_KERNEL);
 195        if (!res->start)
 196                return rom;
 197
 198        res->end = res->start + *size;
 199        memcpy_fromio((void*)(unsigned long)res->start, rom, *size);
 200        pci_unmap_rom(pdev, rom);
 201        res->flags |= IORESOURCE_ROM_COPY;
 202
 203        return (void __iomem *)(unsigned long)res->start;
 204}
 205#endif  /*  0  */
 206
 207/**
 208 * pci_unmap_rom - unmap the ROM from kernel space
 209 * @pdev: pointer to pci device struct
 210 * @rom: virtual address of the previous mapping
 211 *
 212 * Remove a mapping of a previously mapped ROM
 213 */
 214void pci_unmap_rom(struct pci_dev *pdev, void __iomem *rom)
 215{
 216        struct resource *res = &pdev->resource[PCI_ROM_RESOURCE];
 217
 218        if (res->flags & (IORESOURCE_ROM_COPY | IORESOURCE_ROM_BIOS_COPY))
 219                return;
 220
 221        iounmap(rom);
 222
 223        /* Disable again before continuing, leave enabled if pci=rom */
 224        if (!(res->flags & (IORESOURCE_ROM_ENABLE | IORESOURCE_ROM_SHADOW)))
 225                pci_disable_rom(pdev);
 226}
 227
 228#if 0
 229/**
 230 * pci_remove_rom - disable the ROM and remove its sysfs attribute
 231 * @pdev: pointer to pci device struct
 232 *
 233 * Remove the rom file in sysfs and disable ROM decoding.
 234 */
 235void pci_remove_rom(struct pci_dev *pdev)
 236{
 237        struct resource *res = &pdev->resource[PCI_ROM_RESOURCE];
 238
 239        if (pci_resource_len(pdev, PCI_ROM_RESOURCE))
 240                sysfs_remove_bin_file(&pdev->dev.kobj, pdev->rom_attr);
 241        if (!(res->flags & (IORESOURCE_ROM_ENABLE |
 242                            IORESOURCE_ROM_SHADOW |
 243                            IORESOURCE_ROM_BIOS_COPY |
 244                            IORESOURCE_ROM_COPY)))
 245                pci_disable_rom(pdev);
 246}
 247#endif  /*  0  */
 248
 249/**
 250 * pci_cleanup_rom - free the ROM copy created by pci_map_rom_copy
 251 * @pdev: pointer to pci device struct
 252 *
 253 * Free the copied ROM if we allocated one.
 254 */
 255void pci_cleanup_rom(struct pci_dev *pdev)
 256{
 257        struct resource *res = &pdev->resource[PCI_ROM_RESOURCE];
 258        if (res->flags & IORESOURCE_ROM_COPY) {
 259                kfree((void*)(unsigned long)res->start);
 260                res->flags &= ~IORESOURCE_ROM_COPY;
 261                res->start = 0;
 262                res->end = 0;
 263        }
 264}
 265
 266EXPORT_SYMBOL(pci_map_rom);
 267EXPORT_SYMBOL(pci_unmap_rom);
 268EXPORT_SYMBOL_GPL(pci_enable_rom);
 269EXPORT_SYMBOL_GPL(pci_disable_rom);
 270
lxr.linux.no kindly hosted by Redpill Linpro AS, provider of Linux consulting and operations services since 1995.