aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorBjorn Helgaas <bhelgaas@google.com>2012-12-06 16:37:32 -0500
committerBjorn Helgaas <bhelgaas@google.com>2012-12-06 16:37:32 -0500
commit72e1e868ca8f14ef34c95e0e8b73f64b6acf5934 (patch)
treed3bc99f121693ab8f09c03ea555254c9314ff98d
parentedb1daab8e91338b7e2a6c41faec695891ccda35 (diff)
parentf9a37be0f02a943d63e3346b19f9c9d8d91826cb (diff)
Merge branch 'pci/mjg-pci-roms-from-efi' into next
* pci/mjg-pci-roms-from-efi: x86: Use PCI setup data PCI: Add support for non-BAR ROMs PCI: Add pcibios_add_device EFI: Stash ROMs if they're not in the PCI BAR
-rw-r--r--arch/x86/boot/compressed/eboot.c118
-rw-r--r--arch/x86/include/asm/bootparam.h1
-rw-r--r--arch/x86/include/asm/pci.h12
-rw-r--r--arch/x86/kernel/setup.c4
-rw-r--r--arch/x86/pci/common.c30
-rw-r--r--drivers/pci/bus.c5
-rw-r--r--drivers/pci/pci.c13
-rw-r--r--drivers/pci/rom.c11
-rw-r--r--include/linux/efi.h71
-rw-r--r--include/linux/pci.h3
10 files changed, 262 insertions, 6 deletions
diff --git a/arch/x86/boot/compressed/eboot.c b/arch/x86/boot/compressed/eboot.c
index c760e073963e..8a54313bc7dc 100644
--- a/arch/x86/boot/compressed/eboot.c
+++ b/arch/x86/boot/compressed/eboot.c
@@ -8,6 +8,7 @@
8 * ----------------------------------------------------------------------- */ 8 * ----------------------------------------------------------------------- */
9 9
10#include <linux/efi.h> 10#include <linux/efi.h>
11#include <linux/pci.h>
11#include <asm/efi.h> 12#include <asm/efi.h>
12#include <asm/setup.h> 13#include <asm/setup.h>
13#include <asm/desc.h> 14#include <asm/desc.h>
@@ -243,6 +244,121 @@ static void find_bits(unsigned long mask, u8 *pos, u8 *size)
243 *size = len; 244 *size = len;
244} 245}
245 246
247static efi_status_t setup_efi_pci(struct boot_params *params)
248{
249 efi_pci_io_protocol *pci;
250 efi_status_t status;
251 void **pci_handle;
252 efi_guid_t pci_proto = EFI_PCI_IO_PROTOCOL_GUID;
253 unsigned long nr_pci, size = 0;
254 int i;
255 struct setup_data *data;
256
257 data = (struct setup_data *)params->hdr.setup_data;
258
259 while (data && data->next)
260 data = (struct setup_data *)data->next;
261
262 status = efi_call_phys5(sys_table->boottime->locate_handle,
263 EFI_LOCATE_BY_PROTOCOL, &pci_proto,
264 NULL, &size, pci_handle);
265
266 if (status == EFI_BUFFER_TOO_SMALL) {
267 status = efi_call_phys3(sys_table->boottime->allocate_pool,
268 EFI_LOADER_DATA, size, &pci_handle);
269
270 if (status != EFI_SUCCESS)
271 return status;
272
273 status = efi_call_phys5(sys_table->boottime->locate_handle,
274 EFI_LOCATE_BY_PROTOCOL, &pci_proto,
275 NULL, &size, pci_handle);
276 }
277
278 if (status != EFI_SUCCESS)
279 goto free_handle;
280
281 nr_pci = size / sizeof(void *);
282 for (i = 0; i < nr_pci; i++) {
283 void *h = pci_handle[i];
284 uint64_t attributes;
285 struct pci_setup_rom *rom;
286
287 status = efi_call_phys3(sys_table->boottime->handle_protocol,
288 h, &pci_proto, &pci);
289
290 if (status != EFI_SUCCESS)
291 continue;
292
293 if (!pci)
294 continue;
295
296 status = efi_call_phys4(pci->attributes, pci,
297 EfiPciIoAttributeOperationGet, 0,
298 &attributes);
299
300 if (status != EFI_SUCCESS)
301 continue;
302
303 if (!attributes & EFI_PCI_IO_ATTRIBUTE_EMBEDDED_ROM)
304 continue;
305
306 if (!pci->romimage || !pci->romsize)
307 continue;
308
309 size = pci->romsize + sizeof(*rom);
310
311 status = efi_call_phys3(sys_table->boottime->allocate_pool,
312 EFI_LOADER_DATA, size, &rom);
313
314 if (status != EFI_SUCCESS)
315 continue;
316
317 rom->data.type = SETUP_PCI;
318 rom->data.len = size - sizeof(struct setup_data);
319 rom->data.next = 0;
320 rom->pcilen = pci->romsize;
321
322 status = efi_call_phys5(pci->pci.read, pci,
323 EfiPciIoWidthUint16, PCI_VENDOR_ID,
324 1, &(rom->vendor));
325
326 if (status != EFI_SUCCESS)
327 goto free_struct;
328
329 status = efi_call_phys5(pci->pci.read, pci,
330 EfiPciIoWidthUint16, PCI_DEVICE_ID,
331 1, &(rom->devid));
332
333 if (status != EFI_SUCCESS)
334 goto free_struct;
335
336 status = efi_call_phys5(pci->get_location, pci,
337 &(rom->segment), &(rom->bus),
338 &(rom->device), &(rom->function));
339
340 if (status != EFI_SUCCESS)
341 goto free_struct;
342
343 memcpy(rom->romdata, pci->romimage, pci->romsize);
344
345 if (data)
346 data->next = (uint64_t)rom;
347 else
348 params->hdr.setup_data = (uint64_t)rom;
349
350 data = (struct setup_data *)rom;
351
352 continue;
353 free_struct:
354 efi_call_phys1(sys_table->boottime->free_pool, rom);
355 }
356
357free_handle:
358 efi_call_phys1(sys_table->boottime->free_pool, pci_handle);
359 return status;
360}
361
246/* 362/*
247 * See if we have Graphics Output Protocol 363 * See if we have Graphics Output Protocol
248 */ 364 */
@@ -1026,6 +1142,8 @@ struct boot_params *efi_main(void *handle, efi_system_table_t *_table,
1026 1142
1027 setup_graphics(boot_params); 1143 setup_graphics(boot_params);
1028 1144
1145 setup_efi_pci(boot_params);
1146
1029 status = efi_call_phys3(sys_table->boottime->allocate_pool, 1147 status = efi_call_phys3(sys_table->boottime->allocate_pool,
1030 EFI_LOADER_DATA, sizeof(*gdt), 1148 EFI_LOADER_DATA, sizeof(*gdt),
1031 (void **)&gdt); 1149 (void **)&gdt);
diff --git a/arch/x86/include/asm/bootparam.h b/arch/x86/include/asm/bootparam.h
index 2ad874cb661c..92862cd90201 100644
--- a/arch/x86/include/asm/bootparam.h
+++ b/arch/x86/include/asm/bootparam.h
@@ -13,6 +13,7 @@
13#define SETUP_NONE 0 13#define SETUP_NONE 0
14#define SETUP_E820_EXT 1 14#define SETUP_E820_EXT 1
15#define SETUP_DTB 2 15#define SETUP_DTB 2
16#define SETUP_PCI 3
16 17
17/* extensible setup data list node */ 18/* extensible setup data list node */
18struct setup_data { 19struct setup_data {
diff --git a/arch/x86/include/asm/pci.h b/arch/x86/include/asm/pci.h
index 6e41b9343928..dba7805176bf 100644
--- a/arch/x86/include/asm/pci.h
+++ b/arch/x86/include/asm/pci.h
@@ -171,4 +171,16 @@ cpumask_of_pcibus(const struct pci_bus *bus)
171} 171}
172#endif 172#endif
173 173
174struct pci_setup_rom {
175 struct setup_data data;
176 uint16_t vendor;
177 uint16_t devid;
178 uint64_t pcilen;
179 unsigned long segment;
180 unsigned long bus;
181 unsigned long device;
182 unsigned long function;
183 uint8_t romdata[0];
184};
185
174#endif /* _ASM_X86_PCI_H */ 186#endif /* _ASM_X86_PCI_H */
diff --git a/arch/x86/kernel/setup.c b/arch/x86/kernel/setup.c
index ca45696f30fb..c228322ca180 100644
--- a/arch/x86/kernel/setup.c
+++ b/arch/x86/kernel/setup.c
@@ -143,11 +143,7 @@ int default_check_phys_apicid_present(int phys_apicid)
143} 143}
144#endif 144#endif
145 145
146#ifndef CONFIG_DEBUG_BOOT_PARAMS
147struct boot_params __initdata boot_params;
148#else
149struct boot_params boot_params; 146struct boot_params boot_params;
150#endif
151 147
152/* 148/*
153 * Machine setup.. 149 * Machine setup..
diff --git a/arch/x86/pci/common.c b/arch/x86/pci/common.c
index 52dbf1aeeb63..6a6b01778dab 100644
--- a/arch/x86/pci/common.c
+++ b/arch/x86/pci/common.c
@@ -17,6 +17,7 @@
17#include <asm/io.h> 17#include <asm/io.h>
18#include <asm/smp.h> 18#include <asm/smp.h>
19#include <asm/pci_x86.h> 19#include <asm/pci_x86.h>
20#include <asm/setup.h>
20 21
21unsigned int pci_probe = PCI_PROBE_BIOS | PCI_PROBE_CONF1 | PCI_PROBE_CONF2 | 22unsigned int pci_probe = PCI_PROBE_BIOS | PCI_PROBE_CONF1 | PCI_PROBE_CONF2 |
22 PCI_PROBE_MMCONF; 23 PCI_PROBE_MMCONF;
@@ -608,6 +609,35 @@ unsigned int pcibios_assign_all_busses(void)
608 return (pci_probe & PCI_ASSIGN_ALL_BUSSES) ? 1 : 0; 609 return (pci_probe & PCI_ASSIGN_ALL_BUSSES) ? 1 : 0;
609} 610}
610 611
612int pcibios_add_device(struct pci_dev *dev)
613{
614 struct setup_data *data;
615 struct pci_setup_rom *rom;
616 u64 pa_data;
617
618 pa_data = boot_params.hdr.setup_data;
619 while (pa_data) {
620 data = phys_to_virt(pa_data);
621
622 if (data->type == SETUP_PCI) {
623 rom = (struct pci_setup_rom *)data;
624
625 if ((pci_domain_nr(dev->bus) == rom->segment) &&
626 (dev->bus->number == rom->bus) &&
627 (PCI_SLOT(dev->devfn) == rom->device) &&
628 (PCI_FUNC(dev->devfn) == rom->function) &&
629 (dev->vendor == rom->vendor) &&
630 (dev->device == rom->devid)) {
631 dev->rom = (void *)(unsigned long)(pa_data +
632 offsetof(struct pci_setup_rom, romdata));
633 dev->romlen = rom->pcilen;
634 }
635 }
636 pa_data = data->next;
637 }
638 return 0;
639}
640
611int pcibios_enable_device(struct pci_dev *dev, int mask) 641int pcibios_enable_device(struct pci_dev *dev, int mask)
612{ 642{
613 int err; 643 int err;
diff --git a/drivers/pci/bus.c b/drivers/pci/bus.c
index a543746fb354..ad6a8b635692 100644
--- a/drivers/pci/bus.c
+++ b/drivers/pci/bus.c
@@ -170,6 +170,11 @@ int pci_bus_add_device(struct pci_dev *dev)
170 int retval; 170 int retval;
171 171
172 pci_fixup_device(pci_fixup_final, dev); 172 pci_fixup_device(pci_fixup_final, dev);
173
174 retval = pcibios_add_device(dev);
175 if (retval)
176 return retval;
177
173 retval = device_add(&dev->dev); 178 retval = device_add(&dev->dev);
174 if (retval) 179 if (retval)
175 return retval; 180 return retval;
diff --git a/drivers/pci/pci.c b/drivers/pci/pci.c
index 5b862b1c93c6..7c2e25ee2c5a 100644
--- a/drivers/pci/pci.c
+++ b/drivers/pci/pci.c
@@ -1333,6 +1333,19 @@ void pcim_pin_device(struct pci_dev *pdev)
1333 dr->pinned = 1; 1333 dr->pinned = 1;
1334} 1334}
1335 1335
1336/*
1337 * pcibios_add_device - provide arch specific hooks when adding device dev
1338 * @dev: the PCI device being added
1339 *
1340 * Permits the platform to provide architecture specific functionality when
1341 * devices are added. This is the default implementation. Architecture
1342 * implementations can override this.
1343 */
1344int __weak pcibios_add_device (struct pci_dev *dev)
1345{
1346 return 0;
1347}
1348
1336/** 1349/**
1337 * pcibios_disable_device - disable arch specific PCI resources for device dev 1350 * pcibios_disable_device - disable arch specific PCI resources for device dev
1338 * @dev: the PCI device to disable 1351 * @dev: the PCI device to disable
diff --git a/drivers/pci/rom.c b/drivers/pci/rom.c
index 0b3037ab8b93..3a3828fbc879 100644
--- a/drivers/pci/rom.c
+++ b/drivers/pci/rom.c
@@ -118,11 +118,17 @@ void __iomem *pci_map_rom(struct pci_dev *pdev, size_t *size)
118 void __iomem *rom; 118 void __iomem *rom;
119 119
120 /* 120 /*
121 * Some devices may provide ROMs via a source other than the BAR
122 */
123 if (pdev->rom && pdev->romlen) {
124 *size = pdev->romlen;
125 return phys_to_virt((phys_addr_t)pdev->rom);
126 /*
121 * IORESOURCE_ROM_SHADOW set on x86, x86_64 and IA64 supports legacy 127 * IORESOURCE_ROM_SHADOW set on x86, x86_64 and IA64 supports legacy
122 * memory map if the VGA enable bit of the Bridge Control register is 128 * memory map if the VGA enable bit of the Bridge Control register is
123 * set for embedded VGA. 129 * set for embedded VGA.
124 */ 130 */
125 if (res->flags & IORESOURCE_ROM_SHADOW) { 131 } else if (res->flags & IORESOURCE_ROM_SHADOW) {
126 /* primary video rom always starts here */ 132 /* primary video rom always starts here */
127 start = (loff_t)0xC0000; 133 start = (loff_t)0xC0000;
128 *size = 0x20000; /* cover C000:0 through E000:0 */ 134 *size = 0x20000; /* cover C000:0 through E000:0 */
@@ -181,7 +187,8 @@ void pci_unmap_rom(struct pci_dev *pdev, void __iomem *rom)
181 if (res->flags & (IORESOURCE_ROM_COPY | IORESOURCE_ROM_BIOS_COPY)) 187 if (res->flags & (IORESOURCE_ROM_COPY | IORESOURCE_ROM_BIOS_COPY))
182 return; 188 return;
183 189
184 iounmap(rom); 190 if (!pdev->rom || !pdev->romlen)
191 iounmap(rom);
185 192
186 /* Disable again before continuing, leave enabled if pci=rom */ 193 /* Disable again before continuing, leave enabled if pci=rom */
187 if (!(res->flags & (IORESOURCE_ROM_ENABLE | IORESOURCE_ROM_SHADOW))) 194 if (!(res->flags & (IORESOURCE_ROM_ENABLE | IORESOURCE_ROM_SHADOW)))
diff --git a/include/linux/efi.h b/include/linux/efi.h
index 8670eb1eb8cd..8eb1be17c801 100644
--- a/include/linux/efi.h
+++ b/include/linux/efi.h
@@ -196,6 +196,77 @@ typedef struct {
196 void *create_event_ex; 196 void *create_event_ex;
197} efi_boot_services_t; 197} efi_boot_services_t;
198 198
199typedef enum {
200 EfiPciIoWidthUint8,
201 EfiPciIoWidthUint16,
202 EfiPciIoWidthUint32,
203 EfiPciIoWidthUint64,
204 EfiPciIoWidthFifoUint8,
205 EfiPciIoWidthFifoUint16,
206 EfiPciIoWidthFifoUint32,
207 EfiPciIoWidthFifoUint64,
208 EfiPciIoWidthFillUint8,
209 EfiPciIoWidthFillUint16,
210 EfiPciIoWidthFillUint32,
211 EfiPciIoWidthFillUint64,
212 EfiPciIoWidthMaximum
213} EFI_PCI_IO_PROTOCOL_WIDTH;
214
215typedef enum {
216 EfiPciIoAttributeOperationGet,
217 EfiPciIoAttributeOperationSet,
218 EfiPciIoAttributeOperationEnable,
219 EfiPciIoAttributeOperationDisable,
220 EfiPciIoAttributeOperationSupported,
221 EfiPciIoAttributeOperationMaximum
222} EFI_PCI_IO_PROTOCOL_ATTRIBUTE_OPERATION;
223
224
225typedef struct {
226 void *read;
227 void *write;
228} efi_pci_io_protocol_access_t;
229
230typedef struct {
231 void *poll_mem;
232 void *poll_io;
233 efi_pci_io_protocol_access_t mem;
234 efi_pci_io_protocol_access_t io;
235 efi_pci_io_protocol_access_t pci;
236 void *copy_mem;
237 void *map;
238 void *unmap;
239 void *allocate_buffer;
240 void *free_buffer;
241 void *flush;
242 void *get_location;
243 void *attributes;
244 void *get_bar_attributes;
245 void *set_bar_attributes;
246 uint64_t romsize;
247 void *romimage;
248} efi_pci_io_protocol;
249
250#define EFI_PCI_IO_ATTRIBUTE_ISA_MOTHERBOARD_IO 0x0001
251#define EFI_PCI_IO_ATTRIBUTE_ISA_IO 0x0002
252#define EFI_PCI_IO_ATTRIBUTE_VGA_PALETTE_IO 0x0004
253#define EFI_PCI_IO_ATTRIBUTE_VGA_MEMORY 0x0008
254#define EFI_PCI_IO_ATTRIBUTE_VGA_IO 0x0010
255#define EFI_PCI_IO_ATTRIBUTE_IDE_PRIMARY_IO 0x0020
256#define EFI_PCI_IO_ATTRIBUTE_IDE_SECONDARY_IO 0x0040
257#define EFI_PCI_IO_ATTRIBUTE_MEMORY_WRITE_COMBINE 0x0080
258#define EFI_PCI_IO_ATTRIBUTE_IO 0x0100
259#define EFI_PCI_IO_ATTRIBUTE_MEMORY 0x0200
260#define EFI_PCI_IO_ATTRIBUTE_BUS_MASTER 0x0400
261#define EFI_PCI_IO_ATTRIBUTE_MEMORY_CACHED 0x0800
262#define EFI_PCI_IO_ATTRIBUTE_MEMORY_DISABLE 0x1000
263#define EFI_PCI_IO_ATTRIBUTE_EMBEDDED_DEVICE 0x2000
264#define EFI_PCI_IO_ATTRIBUTE_EMBEDDED_ROM 0x4000
265#define EFI_PCI_IO_ATTRIBUTE_DUAL_ADDRESS_CYCLE 0x8000
266#define EFI_PCI_IO_ATTRIBUTE_ISA_IO_16 0x10000
267#define EFI_PCI_IO_ATTRIBUTE_VGA_PALETTE_IO_16 0x20000
268#define EFI_PCI_IO_ATTRIBUTE_VGA_IO_16 0x40000
269
199/* 270/*
200 * Types and defines for EFI ResetSystem 271 * Types and defines for EFI ResetSystem
201 */ 272 */
diff --git a/include/linux/pci.h b/include/linux/pci.h
index a98a5f9ac1d5..ea41a0a52a59 100644
--- a/include/linux/pci.h
+++ b/include/linux/pci.h
@@ -333,6 +333,8 @@ struct pci_dev {
333 }; 333 };
334 struct pci_ats *ats; /* Address Translation Service */ 334 struct pci_ats *ats; /* Address Translation Service */
335#endif 335#endif
336 void *rom; /* Physical pointer to ROM if it's not from the BAR */
337 size_t romlen; /* Length of ROM if it's not from the BAR */
336}; 338};
337 339
338static inline struct pci_dev *pci_physfn(struct pci_dev *dev) 340static inline struct pci_dev *pci_physfn(struct pci_dev *dev)
@@ -1599,6 +1601,7 @@ void pcibios_disable_device(struct pci_dev *dev);
1599void pcibios_set_master(struct pci_dev *dev); 1601void pcibios_set_master(struct pci_dev *dev);
1600int pcibios_set_pcie_reset_state(struct pci_dev *dev, 1602int pcibios_set_pcie_reset_state(struct pci_dev *dev,
1601 enum pcie_reset_state state); 1603 enum pcie_reset_state state);
1604int pcibios_add_device(struct pci_dev *dev);
1602 1605
1603#ifdef CONFIG_PCI_MMCONFIG 1606#ifdef CONFIG_PCI_MMCONFIG
1604extern void __init pci_mmcfg_early_init(void); 1607extern void __init pci_mmcfg_early_init(void);