diff options
Diffstat (limited to 'arch/x86/boot/compressed/eboot.c')
-rw-r--r-- | arch/x86/boot/compressed/eboot.c | 118 |
1 files changed, 118 insertions, 0 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 | ||
247 | static 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 | |||
357 | free_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); |