diff options
Diffstat (limited to 'drivers/pci/rom.c')
-rw-r--r-- | drivers/pci/rom.c | 227 |
1 files changed, 227 insertions, 0 deletions
diff --git a/drivers/pci/rom.c b/drivers/pci/rom.c new file mode 100644 index 000000000000..3e64ff64b38c --- /dev/null +++ b/drivers/pci/rom.c | |||
@@ -0,0 +1,227 @@ | |||
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/config.h> | ||
10 | #include <linux/kernel.h> | ||
11 | #include <linux/pci.h> | ||
12 | |||
13 | #include "pci.h" | ||
14 | |||
15 | /** | ||
16 | * pci_enable_rom - enable ROM decoding for a PCI device | ||
17 | * @dev: 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 | */ | ||
24 | static void pci_enable_rom(struct pci_dev *pdev) | ||
25 | { | ||
26 | u32 rom_addr; | ||
27 | |||
28 | pci_read_config_dword(pdev, pdev->rom_base_reg, &rom_addr); | ||
29 | rom_addr |= PCI_ROM_ADDRESS_ENABLE; | ||
30 | pci_write_config_dword(pdev, pdev->rom_base_reg, rom_addr); | ||
31 | } | ||
32 | |||
33 | /** | ||
34 | * pci_disable_rom - disable ROM decoding for a PCI device | ||
35 | * @dev: PCI device to disable | ||
36 | * | ||
37 | * Disable ROM decoding on a PCI device by turning off the last bit in the | ||
38 | * ROM BAR. | ||
39 | */ | ||
40 | static void pci_disable_rom(struct pci_dev *pdev) | ||
41 | { | ||
42 | u32 rom_addr; | ||
43 | pci_read_config_dword(pdev, pdev->rom_base_reg, &rom_addr); | ||
44 | rom_addr &= ~PCI_ROM_ADDRESS_ENABLE; | ||
45 | pci_write_config_dword(pdev, pdev->rom_base_reg, rom_addr); | ||
46 | } | ||
47 | |||
48 | /** | ||
49 | * pci_map_rom - map a PCI ROM to kernel space | ||
50 | * @dev: pointer to pci device struct | ||
51 | * @size: pointer to receive size of pci window over ROM | ||
52 | * @return: kernel virtual pointer to image of ROM | ||
53 | * | ||
54 | * Map a PCI ROM into kernel space. If ROM is boot video ROM, | ||
55 | * the shadow BIOS copy will be returned instead of the | ||
56 | * actual ROM. | ||
57 | */ | ||
58 | void __iomem *pci_map_rom(struct pci_dev *pdev, size_t *size) | ||
59 | { | ||
60 | struct resource *res = &pdev->resource[PCI_ROM_RESOURCE]; | ||
61 | loff_t start; | ||
62 | void __iomem *rom; | ||
63 | void __iomem *image; | ||
64 | int last_image; | ||
65 | |||
66 | /* IORESOURCE_ROM_SHADOW only set on x86 */ | ||
67 | if (res->flags & IORESOURCE_ROM_SHADOW) { | ||
68 | /* primary video rom always starts here */ | ||
69 | start = (loff_t)0xC0000; | ||
70 | *size = 0x20000; /* cover C000:0 through E000:0 */ | ||
71 | } else { | ||
72 | if (res->flags & IORESOURCE_ROM_COPY) { | ||
73 | *size = pci_resource_len(pdev, PCI_ROM_RESOURCE); | ||
74 | return (void __iomem *)pci_resource_start(pdev, PCI_ROM_RESOURCE); | ||
75 | } else { | ||
76 | /* assign the ROM an address if it doesn't have one */ | ||
77 | if (res->parent == NULL) | ||
78 | pci_assign_resource(pdev, PCI_ROM_RESOURCE); | ||
79 | |||
80 | start = pci_resource_start(pdev, PCI_ROM_RESOURCE); | ||
81 | *size = pci_resource_len(pdev, PCI_ROM_RESOURCE); | ||
82 | if (*size == 0) | ||
83 | return NULL; | ||
84 | |||
85 | /* Enable ROM space decodes */ | ||
86 | pci_enable_rom(pdev); | ||
87 | } | ||
88 | } | ||
89 | |||
90 | rom = ioremap(start, *size); | ||
91 | if (!rom) { | ||
92 | /* restore enable if ioremap fails */ | ||
93 | if (!(res->flags & (IORESOURCE_ROM_ENABLE | | ||
94 | IORESOURCE_ROM_SHADOW | | ||
95 | IORESOURCE_ROM_COPY))) | ||
96 | pci_disable_rom(pdev); | ||
97 | return NULL; | ||
98 | } | ||
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 | */ | ||
105 | image = rom; | ||
106 | do { | ||
107 | void __iomem *pds; | ||
108 | /* Standard PCI ROMs start out with these bytes 55 AA */ | ||
109 | if (readb(image) != 0x55) | ||
110 | break; | ||
111 | if (readb(image + 1) != 0xAA) | ||
112 | break; | ||
113 | /* get the PCI data structure and check its signature */ | ||
114 | pds = image + readw(image + 24); | ||
115 | if (readb(pds) != 'P') | ||
116 | break; | ||
117 | if (readb(pds + 1) != 'C') | ||
118 | break; | ||
119 | if (readb(pds + 2) != 'I') | ||
120 | break; | ||
121 | if (readb(pds + 3) != 'R') | ||
122 | break; | ||
123 | last_image = readb(pds + 21) & 0x80; | ||
124 | /* this length is reliable */ | ||
125 | image += readw(pds + 16) * 512; | ||
126 | } while (!last_image); | ||
127 | |||
128 | *size = image - rom; | ||
129 | |||
130 | return rom; | ||
131 | } | ||
132 | |||
133 | /** | ||
134 | * pci_map_rom_copy - map a PCI ROM to kernel space, create a copy | ||
135 | * @dev: pointer to pci device struct | ||
136 | * @size: pointer to receive size of pci window over ROM | ||
137 | * @return: kernel virtual pointer to image of ROM | ||
138 | * | ||
139 | * Map a PCI ROM into kernel space. If ROM is boot video ROM, | ||
140 | * the shadow BIOS copy will be returned instead of the | ||
141 | * actual ROM. | ||
142 | */ | ||
143 | void __iomem *pci_map_rom_copy(struct pci_dev *pdev, size_t *size) | ||
144 | { | ||
145 | struct resource *res = &pdev->resource[PCI_ROM_RESOURCE]; | ||
146 | void __iomem *rom; | ||
147 | |||
148 | rom = pci_map_rom(pdev, size); | ||
149 | if (!rom) | ||
150 | return NULL; | ||
151 | |||
152 | if (res->flags & (IORESOURCE_ROM_COPY | IORESOURCE_ROM_SHADOW)) | ||
153 | return rom; | ||
154 | |||
155 | res->start = (unsigned long)kmalloc(*size, GFP_KERNEL); | ||
156 | if (!res->start) | ||
157 | return rom; | ||
158 | |||
159 | res->end = res->start + *size; | ||
160 | memcpy_fromio((void*)res->start, rom, *size); | ||
161 | pci_unmap_rom(pdev, rom); | ||
162 | res->flags |= IORESOURCE_ROM_COPY; | ||
163 | |||
164 | return (void __iomem *)res->start; | ||
165 | } | ||
166 | |||
167 | /** | ||
168 | * pci_unmap_rom - unmap the ROM from kernel space | ||
169 | * @dev: pointer to pci device struct | ||
170 | * @rom: virtual address of the previous mapping | ||
171 | * | ||
172 | * Remove a mapping of a previously mapped ROM | ||
173 | */ | ||
174 | void 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 | * Remove the rom file in sysfs and disable ROM decoding. | ||
193 | */ | ||
194 | void 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 | | ||
201 | IORESOURCE_ROM_SHADOW | | ||
202 | IORESOURCE_ROM_COPY))) | ||
203 | pci_disable_rom(pdev); | ||
204 | } | ||
205 | |||
206 | /** | ||
207 | * pci_cleanup_rom - internal routine for freeing the ROM copy created | ||
208 | * by pci_map_rom_copy called from remove.c | ||
209 | * @dev: pointer to pci device struct | ||
210 | * | ||
211 | * Free the copied ROM if we allocated one. | ||
212 | */ | ||
213 | void pci_cleanup_rom(struct pci_dev *pdev) | ||
214 | { | ||
215 | struct resource *res = &pdev->resource[PCI_ROM_RESOURCE]; | ||
216 | if (res->flags & IORESOURCE_ROM_COPY) { | ||
217 | kfree((void*)res->start); | ||
218 | res->flags &= ~IORESOURCE_ROM_COPY; | ||
219 | res->start = 0; | ||
220 | res->end = 0; | ||
221 | } | ||
222 | } | ||
223 | |||
224 | EXPORT_SYMBOL(pci_map_rom); | ||
225 | EXPORT_SYMBOL(pci_map_rom_copy); | ||
226 | EXPORT_SYMBOL(pci_unmap_rom); | ||
227 | EXPORT_SYMBOL(pci_remove_rom); | ||