Blame view

drivers/pci/rom.c 7.25 KB
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1
2
3
4
5
6
7
8
  /*
   * drivers/pci/rom.c
   *
   * (C) Copyright 2004 Jon Smirl <jonsmirl@yahoo.com>
   * (C) Copyright 2004 Silicon Graphics, Inc. Jesse Barnes <jbarnes@sgi.com>
   *
   * PCI ROM access routines
   */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
9
10
  #include <linux/kernel.h>
  #include <linux/pci.h>
4e57b6817   Tim Schmielau   [PATCH] fix missi...
11
  #include <linux/slab.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
12
13
14
15
16
  
  #include "pci.h"
  
  /**
   * pci_enable_rom - enable ROM decoding for a PCI device
67be2dd1b   Martin Waitz   [PATCH] DocBook: ...
17
   * @pdev: PCI device to enable
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
18
19
20
21
22
23
   *
   * Enable ROM decoding on @dev.  This involves simply turning on the last
   * bit of the PCI ROM BAR.  Note that some cards may share address decoders
   * between the ROM and other resources, so enabling it may disable access
   * to MMIO registers or other card memory.
   */
e416de5e6   Alan Cox   Export the ROM en...
24
  int pci_enable_rom(struct pci_dev *pdev)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
25
  {
8085ce084   Benjamin Herrenschmidt   [PATCH] Fix PCI R...
26
27
  	struct resource *res = pdev->resource + PCI_ROM_RESOURCE;
  	struct pci_bus_region region;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
28
  	u32 rom_addr;
8085ce084   Benjamin Herrenschmidt   [PATCH] Fix PCI R...
29
30
31
32
  	if (!res->flags)
  		return -1;
  
  	pcibios_resource_to_bus(pdev, &region, res);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
33
  	pci_read_config_dword(pdev, pdev->rom_base_reg, &rom_addr);
8085ce084   Benjamin Herrenschmidt   [PATCH] Fix PCI R...
34
35
  	rom_addr &= ~PCI_ROM_ADDRESS_MASK;
  	rom_addr |= region.start | PCI_ROM_ADDRESS_ENABLE;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
36
  	pci_write_config_dword(pdev, pdev->rom_base_reg, rom_addr);
8085ce084   Benjamin Herrenschmidt   [PATCH] Fix PCI R...
37
  	return 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
38
39
40
41
  }
  
  /**
   * pci_disable_rom - disable ROM decoding for a PCI device
67be2dd1b   Martin Waitz   [PATCH] DocBook: ...
42
   * @pdev: PCI device to disable
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
43
44
45
46
   *
   * Disable ROM decoding on a PCI device by turning off the last bit in the
   * ROM BAR.
   */
e416de5e6   Alan Cox   Export the ROM en...
47
  void pci_disable_rom(struct pci_dev *pdev)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
48
49
50
51
52
53
54
55
  {
  	u32 rom_addr;
  	pci_read_config_dword(pdev, pdev->rom_base_reg, &rom_addr);
  	rom_addr &= ~PCI_ROM_ADDRESS_ENABLE;
  	pci_write_config_dword(pdev, pdev->rom_base_reg, rom_addr);
  }
  
  /**
d7ad2254f   John Keller   [IA64] SN: Correc...
56
   * pci_get_rom_size - obtain the actual size of the ROM image
4cc59c721   Randy Dunlap   PCI: fix rom.c ke...
57
   * @pdev: target PCI device
d7ad2254f   John Keller   [IA64] SN: Correc...
58
59
60
61
62
63
64
65
   * @rom: kernel virtual pointer to image of ROM
   * @size: size of PCI window
   *  return: size of actual ROM image
   *
   * Determine the actual length of the ROM image.
   * The PCI window size could be much larger than the
   * actual image size.
   */
97c44836c   Timothy S. Nelson   PCI: return error...
66
  size_t pci_get_rom_size(struct pci_dev *pdev, void __iomem *rom, size_t size)
d7ad2254f   John Keller   [IA64] SN: Correc...
67
68
69
70
71
72
73
74
  {
  	void __iomem *image;
  	int last_image;
  
  	image = rom;
  	do {
  		void __iomem *pds;
  		/* Standard PCI ROMs start out with these bytes 55 AA */
97c44836c   Timothy S. Nelson   PCI: return error...
75
76
77
  		if (readb(image) != 0x55) {
  			dev_err(&pdev->dev, "Invalid ROM contents
  ");
d7ad2254f   John Keller   [IA64] SN: Correc...
78
  			break;
97c44836c   Timothy S. Nelson   PCI: return error...
79
  		}
d7ad2254f   John Keller   [IA64] SN: Correc...
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
  		if (readb(image + 1) != 0xAA)
  			break;
  		/* get the PCI data structure and check its signature */
  		pds = image + readw(image + 24);
  		if (readb(pds) != 'P')
  			break;
  		if (readb(pds + 1) != 'C')
  			break;
  		if (readb(pds + 2) != 'I')
  			break;
  		if (readb(pds + 3) != 'R')
  			break;
  		last_image = readb(pds + 21) & 0x80;
  		/* this length is reliable */
  		image += readw(pds + 16) * 512;
  	} while (!last_image);
  
  	/* never return a size larger than the PCI resource window */
  	/* there are known ROMs that get the size wrong */
  	return min((size_t)(image - rom), size);
  }
  
  /**
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
103
   * pci_map_rom - map a PCI ROM to kernel space
67be2dd1b   Martin Waitz   [PATCH] DocBook: ...
104
   * @pdev: pointer to pci device struct
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
105
   * @size: pointer to receive size of pci window over ROM
f5dafca52   Randy Dunlap   PCI: remove exces...
106
107
   *
   * Return: kernel virtual pointer to image of ROM
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
108
109
110
111
112
113
114
115
116
117
   *
   * Map a PCI ROM into kernel space. If ROM is boot video ROM,
   * the shadow BIOS copy will be returned instead of the
   * actual ROM.
   */
  void __iomem *pci_map_rom(struct pci_dev *pdev, size_t *size)
  {
  	struct resource *res = &pdev->resource[PCI_ROM_RESOURCE];
  	loff_t start;
  	void __iomem *rom;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
118

b5e4efe7e   eiichiro.oiwa.nm@hitachi.com   PCI: Turn pci_fix...
119
  	/*
6b5c76b8e   Eiichiro Oiwa   PCI: fix pci_fixu...
120
121
122
  	 * IORESOURCE_ROM_SHADOW set on x86, x86_64 and IA64 supports legacy
  	 * memory map if the VGA enable bit of the Bridge Control register is
  	 * set for embedded VGA.
b5e4efe7e   eiichiro.oiwa.nm@hitachi.com   PCI: Turn pci_fix...
123
  	 */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
124
125
126
127
128
  	if (res->flags & IORESOURCE_ROM_SHADOW) {
  		/* primary video rom always starts here */
  		start = (loff_t)0xC0000;
  		*size = 0x20000; /* cover C000:0 through E000:0 */
  	} else {
a2302c68d   John Keller   Altix: Initial AC...
129
130
  		if (res->flags &
  			(IORESOURCE_ROM_COPY | IORESOURCE_ROM_BIOS_COPY)) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
131
  			*size = pci_resource_len(pdev, PCI_ROM_RESOURCE);
e31dd6e45   Greg Kroah-Hartman   [PATCH] 64bit res...
132
133
  			return (void __iomem *)(unsigned long)
  				pci_resource_start(pdev, PCI_ROM_RESOURCE);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
134
135
  		} else {
  			/* assign the ROM an address if it doesn't have one */
8085ce084   Benjamin Herrenschmidt   [PATCH] Fix PCI R...
136
137
138
  			if (res->parent == NULL &&
  			    pci_assign_resource(pdev,PCI_ROM_RESOURCE))
  				return NULL;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
139
140
141
142
143
144
  			start = pci_resource_start(pdev, PCI_ROM_RESOURCE);
  			*size = pci_resource_len(pdev, PCI_ROM_RESOURCE);
  			if (*size == 0)
  				return NULL;
  
  			/* Enable ROM space decodes */
8085ce084   Benjamin Herrenschmidt   [PATCH] Fix PCI R...
145
146
  			if (pci_enable_rom(pdev))
  				return NULL;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
  		}
  	}
  
  	rom = ioremap(start, *size);
  	if (!rom) {
  		/* restore enable if ioremap fails */
  		if (!(res->flags & (IORESOURCE_ROM_ENABLE |
  				    IORESOURCE_ROM_SHADOW |
  				    IORESOURCE_ROM_COPY)))
  			pci_disable_rom(pdev);
  		return NULL;
  	}
  
  	/*
  	 * Try to find the true size of the ROM since sometimes the PCI window
  	 * size is much larger than the actual size of the ROM.
  	 * True size is important if the ROM is going to be copied.
  	 */
97c44836c   Timothy S. Nelson   PCI: return error...
165
  	*size = pci_get_rom_size(pdev, rom, *size);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
166
167
  	return rom;
  }
b09549ef9   Adrian Bunk   PCI: drivers/pci/...
168
  #if 0
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
169
170
  /**
   * pci_map_rom_copy - map a PCI ROM to kernel space, create a copy
67be2dd1b   Martin Waitz   [PATCH] DocBook: ...
171
   * @pdev: pointer to pci device struct
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
172
   * @size: pointer to receive size of pci window over ROM
f5dafca52   Randy Dunlap   PCI: remove exces...
173
174
   *
   * Return: kernel virtual pointer to image of ROM
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
175
176
177
178
179
180
181
182
183
184
185
186
187
   *
   * Map a PCI ROM into kernel space. If ROM is boot video ROM,
   * the shadow BIOS copy will be returned instead of the
   * actual ROM.
   */
  void __iomem *pci_map_rom_copy(struct pci_dev *pdev, size_t *size)
  {
  	struct resource *res = &pdev->resource[PCI_ROM_RESOURCE];
  	void __iomem *rom;
  
  	rom = pci_map_rom(pdev, size);
  	if (!rom)
  		return NULL;
a2302c68d   John Keller   Altix: Initial AC...
188
189
  	if (res->flags & (IORESOURCE_ROM_COPY | IORESOURCE_ROM_SHADOW |
  			  IORESOURCE_ROM_BIOS_COPY))
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
190
191
192
193
194
195
196
  		return rom;
  
  	res->start = (unsigned long)kmalloc(*size, GFP_KERNEL);
  	if (!res->start)
  		return rom;
  
  	res->end = res->start + *size;
e31dd6e45   Greg Kroah-Hartman   [PATCH] 64bit res...
197
  	memcpy_fromio((void*)(unsigned long)res->start, rom, *size);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
198
199
  	pci_unmap_rom(pdev, rom);
  	res->flags |= IORESOURCE_ROM_COPY;
e31dd6e45   Greg Kroah-Hartman   [PATCH] 64bit res...
200
  	return (void __iomem *)(unsigned long)res->start;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
201
  }
b09549ef9   Adrian Bunk   PCI: drivers/pci/...
202
  #endif  /*  0  */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
203
204
205
  
  /**
   * pci_unmap_rom - unmap the ROM from kernel space
67be2dd1b   Martin Waitz   [PATCH] DocBook: ...
206
   * @pdev: pointer to pci device struct
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
207
208
209
210
211
212
213
   * @rom: virtual address of the previous mapping
   *
   * Remove a mapping of a previously mapped ROM
   */
  void pci_unmap_rom(struct pci_dev *pdev, void __iomem *rom)
  {
  	struct resource *res = &pdev->resource[PCI_ROM_RESOURCE];
a2302c68d   John Keller   Altix: Initial AC...
214
  	if (res->flags & (IORESOURCE_ROM_COPY | IORESOURCE_ROM_BIOS_COPY))
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
215
216
217
218
219
220
221
222
  		return;
  
  	iounmap(rom);
  
  	/* Disable again before continuing, leave enabled if pci=rom */
  	if (!(res->flags & (IORESOURCE_ROM_ENABLE | IORESOURCE_ROM_SHADOW)))
  		pci_disable_rom(pdev);
  }
b09549ef9   Adrian Bunk   PCI: drivers/pci/...
223
  #if 0
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
224
225
  /**
   * pci_remove_rom - disable the ROM and remove its sysfs attribute
67be2dd1b   Martin Waitz   [PATCH] DocBook: ...
226
   * @pdev: pointer to pci device struct
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
227
228
229
230
231
232
233
234
235
236
237
   *
   * Remove the rom file in sysfs and disable ROM decoding.
   */
  void pci_remove_rom(struct pci_dev *pdev)
  {
  	struct resource *res = &pdev->resource[PCI_ROM_RESOURCE];
  
  	if (pci_resource_len(pdev, PCI_ROM_RESOURCE))
  		sysfs_remove_bin_file(&pdev->dev.kobj, pdev->rom_attr);
  	if (!(res->flags & (IORESOURCE_ROM_ENABLE |
  			    IORESOURCE_ROM_SHADOW |
a2302c68d   John Keller   Altix: Initial AC...
238
  			    IORESOURCE_ROM_BIOS_COPY |
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
239
240
241
  			    IORESOURCE_ROM_COPY)))
  		pci_disable_rom(pdev);
  }
b09549ef9   Adrian Bunk   PCI: drivers/pci/...
242
  #endif  /*  0  */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
243
244
  
  /**
0643245f5   Randy Dunlap   docbook: fix kern...
245
   * pci_cleanup_rom - free the ROM copy created by pci_map_rom_copy
67be2dd1b   Martin Waitz   [PATCH] DocBook: ...
246
   * @pdev: pointer to pci device struct
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
247
248
249
250
251
252
253
   *
   * Free the copied ROM if we allocated one.
   */
  void pci_cleanup_rom(struct pci_dev *pdev)
  {
  	struct resource *res = &pdev->resource[PCI_ROM_RESOURCE];
  	if (res->flags & IORESOURCE_ROM_COPY) {
e31dd6e45   Greg Kroah-Hartman   [PATCH] 64bit res...
254
  		kfree((void*)(unsigned long)res->start);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
255
256
257
258
259
260
261
  		res->flags &= ~IORESOURCE_ROM_COPY;
  		res->start = 0;
  		res->end = 0;
  	}
  }
  
  EXPORT_SYMBOL(pci_map_rom);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
262
  EXPORT_SYMBOL(pci_unmap_rom);
e416de5e6   Alan Cox   Export the ROM en...
263
264
  EXPORT_SYMBOL_GPL(pci_enable_rom);
  EXPORT_SYMBOL_GPL(pci_disable_rom);