This commit was manufactured by cvs2svn to create branch 'vserver'.
[linux-2.6.git] / drivers / pci / rom.c
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  */
10
11
12 #include <linux/config.h>
13 #include <linux/kernel.h>
14 #include <linux/pci.h>
15
16 #include "pci.h"
17
18 /**
19  * pci_enable_rom - enable ROM decoding for a PCI device
20  * @dev: PCI device to enable
21  *
22  * Enable ROM decoding on @dev.  This involves simply turning on the last
23  * bit of the PCI ROM BAR.  Note that some cards may share address decoders
24  * between the ROM and other resources, so enabling it may disable access
25  * to MMIO registers or other card memory.
26  */
27 static void
28 pci_enable_rom(struct pci_dev *pdev)
29 {
30         u32 rom_addr;
31         
32         pci_read_config_dword(pdev, pdev->rom_base_reg, &rom_addr);
33         rom_addr |= PCI_ROM_ADDRESS_ENABLE;
34         pci_write_config_dword(pdev, pdev->rom_base_reg, rom_addr);
35 }
36
37 /**
38  * pci_disable_rom - disable ROM decoding for a PCI device
39  * @dev: PCI device to disable
40  *
41  * Disable ROM decoding on a PCI device by turning off the last bit in the
42  * ROM BAR.
43  */
44 static void
45 pci_disable_rom(struct pci_dev *pdev)
46 {
47         u32 rom_addr;
48         pci_read_config_dword(pdev, pdev->rom_base_reg, &rom_addr);
49         rom_addr &= ~PCI_ROM_ADDRESS_ENABLE;
50         pci_write_config_dword(pdev, pdev->rom_base_reg, rom_addr);
51 }
52
53 /**
54  * pci_map_rom - map a PCI ROM to kernel space
55  * @dev: pointer to pci device struct
56  * @size: pointer to receive size of pci window over ROM
57  * @return: kernel virtual pointer to image of ROM
58  *
59  * Map a PCI ROM into kernel space. If ROM is boot video ROM,
60  * the shadow BIOS copy will be returned instead of the 
61  * actual ROM.
62  */
63 void __iomem *pci_map_rom(struct pci_dev *pdev, size_t *size)
64 {
65         struct resource *res = &pdev->resource[PCI_ROM_RESOURCE];
66         loff_t start;
67         void __iomem *rom;
68         void __iomem *image;
69         int last_image;
70         
71         if (res->flags & IORESOURCE_ROM_SHADOW) {       /* IORESOURCE_ROM_SHADOW only set on x86 */
72                 start = (loff_t)0xC0000;        /* primary video rom always starts here */
73                 *size = 0x20000;                /* cover C000:0 through E000:0 */
74         } else {
75                 if (res->flags & IORESOURCE_ROM_COPY) {
76                         *size = pci_resource_len(pdev, PCI_ROM_RESOURCE);
77                         return (void __iomem *)pci_resource_start(pdev, PCI_ROM_RESOURCE);
78                 } else {
79                         /* assign the ROM an address if it doesn't have one */
80                         if (res->parent == NULL)
81                                 pci_assign_resource(pdev, PCI_ROM_RESOURCE);
82         
83                         start = pci_resource_start(pdev, PCI_ROM_RESOURCE);
84                         *size = pci_resource_len(pdev, PCI_ROM_RESOURCE);
85                         if (*size == 0)
86                                 return NULL;
87                         
88                         /* Enable ROM space decodes */
89                         pci_enable_rom(pdev);
90                 }
91         }
92         
93         rom = ioremap(start, *size);
94         if (!rom) {
95                 /* restore enable if ioremap fails */
96                 if (!(res->flags & (IORESOURCE_ROM_ENABLE | IORESOURCE_ROM_SHADOW | IORESOURCE_ROM_COPY)))
97                         pci_disable_rom(pdev);
98                 return NULL;
99         }               
100
101         /* Try to find the true size of the ROM since sometimes the PCI window */
102         /* size is much larger than the actual size of the ROM. */
103         /* True size is important if the ROM is going to be copied. */
104         image = rom;
105         do {
106                 void __iomem *pds;
107                 /* Standard PCI ROMs start out with these bytes 55 AA */
108                 if (readb(image) != 0x55)
109                         break;
110                 if (readb(image + 1) != 0xAA)
111                         break;
112                 /* get the PCI data structure and check its signature */
113                 pds = image + readw(image + 24);
114                 if (readb(pds) != 'P')
115                         break;
116                 if (readb(pds + 1) != 'C')
117                         break;
118                 if (readb(pds + 2) != 'I')
119                         break;
120                 if (readb(pds + 3) != 'R')
121                         break;
122                 last_image = readb(pds + 21) & 0x80;
123                 /* this length is reliable */
124                 image += readw(pds + 16) * 512;
125         } while (!last_image);
126
127         *size = image - rom;
128
129         return rom;
130 }
131
132 /**
133  * pci_map_rom_copy - map a PCI ROM to kernel space, create a copy
134  * @dev: pointer to pci device struct
135  * @size: pointer to receive size of pci window over ROM
136  * @return: kernel virtual pointer to image of ROM
137  *
138  * Map a PCI ROM into kernel space. If ROM is boot video ROM,
139  * the shadow BIOS copy will be returned instead of the 
140  * actual ROM.
141  */
142 void __iomem *pci_map_rom_copy(struct pci_dev *pdev, size_t *size)
143 {
144         struct resource *res = &pdev->resource[PCI_ROM_RESOURCE];
145         void __iomem *rom;
146         
147         rom = pci_map_rom(pdev, size);
148         if (!rom)
149                 return NULL;
150                 
151         if (res->flags & (IORESOURCE_ROM_COPY | IORESOURCE_ROM_SHADOW))
152                 return rom;
153                 
154         res->start = (unsigned long)kmalloc(*size, GFP_KERNEL);
155         if (!res->start) 
156                 return rom;
157
158         res->end = res->start + *size; 
159         memcpy_fromio((void*)res->start, rom, *size);
160         pci_unmap_rom(pdev, rom);
161         res->flags |= IORESOURCE_ROM_COPY;
162         
163         return (void __iomem *)res->start;
164 }
165
166 /**
167  * pci_unmap_rom - unmap the ROM from kernel space
168  * @dev: pointer to pci device struct
169  * @rom: virtual address of the previous mapping
170  *
171  * Remove a mapping of a previously mapped ROM
172  */
173 void 
174 pci_unmap_rom(struct pci_dev *pdev, void __iomem *rom)
175 {
176         struct resource *res = &pdev->resource[PCI_ROM_RESOURCE];
177
178         if (res->flags & IORESOURCE_ROM_COPY)
179                 return;
180                 
181         iounmap(rom);
182                 
183         /* Disable again before continuing, leave enabled if pci=rom */
184         if (!(res->flags & (IORESOURCE_ROM_ENABLE | IORESOURCE_ROM_SHADOW)))
185                 pci_disable_rom(pdev);
186 }
187
188 /**
189  * pci_remove_rom - disable the ROM and remove its sysfs attribute
190  * @dev: pointer to pci device struct
191  *
192  */
193 void 
194 pci_remove_rom(struct pci_dev *pdev) 
195 {
196         struct resource *res = &pdev->resource[PCI_ROM_RESOURCE];
197         
198         if (pci_resource_len(pdev, PCI_ROM_RESOURCE))
199                 sysfs_remove_bin_file(&pdev->dev.kobj, pdev->rom_attr);
200         if (!(res->flags & (IORESOURCE_ROM_ENABLE | IORESOURCE_ROM_SHADOW | IORESOURCE_ROM_COPY)))
201                 pci_disable_rom(pdev);
202 }
203
204 /**
205  * pci_cleanup_rom - internal routine for freeing the ROM copy created 
206  * by pci_map_rom_copy called from remove.c
207  * @dev: pointer to pci device struct
208  *
209  */
210 void 
211 pci_cleanup_rom(struct pci_dev *pdev) 
212 {
213         struct resource *res = &pdev->resource[PCI_ROM_RESOURCE];
214         if (res->flags & IORESOURCE_ROM_COPY) {
215                 kfree((void*)res->start);
216                 res->flags &= ~IORESOURCE_ROM_COPY;
217                 res->start = 0;
218                 res->end = 0;
219         }
220 }
221
222 EXPORT_SYMBOL(pci_map_rom);
223 EXPORT_SYMBOL(pci_map_rom_copy);
224 EXPORT_SYMBOL(pci_unmap_rom);
225 EXPORT_SYMBOL(pci_remove_rom);