xref: /openbmc/linux/drivers/pci/rom.c (revision 1da177e4)
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);
228