Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 72e1e868 authored by Bjorn Helgaas's avatar Bjorn Helgaas
Browse files

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
parents edb1daab f9a37be0
Loading
Loading
Loading
Loading
+118 −0
Original line number Original line Diff line number Diff line
@@ -8,6 +8,7 @@
 * ----------------------------------------------------------------------- */
 * ----------------------------------------------------------------------- */


#include <linux/efi.h>
#include <linux/efi.h>
#include <linux/pci.h>
#include <asm/efi.h>
#include <asm/efi.h>
#include <asm/setup.h>
#include <asm/setup.h>
#include <asm/desc.h>
#include <asm/desc.h>
@@ -243,6 +244,121 @@ static void find_bits(unsigned long mask, u8 *pos, u8 *size)
	*size = len;
	*size = len;
}
}


static efi_status_t setup_efi_pci(struct boot_params *params)
{
	efi_pci_io_protocol *pci;
	efi_status_t status;
	void **pci_handle;
	efi_guid_t pci_proto = EFI_PCI_IO_PROTOCOL_GUID;
	unsigned long nr_pci, size = 0;
	int i;
	struct setup_data *data;

	data = (struct setup_data *)params->hdr.setup_data;

	while (data && data->next)
		data = (struct setup_data *)data->next;

	status = efi_call_phys5(sys_table->boottime->locate_handle,
				EFI_LOCATE_BY_PROTOCOL, &pci_proto,
				NULL, &size, pci_handle);

	if (status == EFI_BUFFER_TOO_SMALL) {
		status = efi_call_phys3(sys_table->boottime->allocate_pool,
					EFI_LOADER_DATA, size, &pci_handle);

		if (status != EFI_SUCCESS)
			return status;

		status = efi_call_phys5(sys_table->boottime->locate_handle,
					EFI_LOCATE_BY_PROTOCOL, &pci_proto,
					NULL, &size, pci_handle);
	}

	if (status != EFI_SUCCESS)
		goto free_handle;

	nr_pci = size / sizeof(void *);
	for (i = 0; i < nr_pci; i++) {
		void *h = pci_handle[i];
		uint64_t attributes;
		struct pci_setup_rom *rom;

		status = efi_call_phys3(sys_table->boottime->handle_protocol,
					h, &pci_proto, &pci);

		if (status != EFI_SUCCESS)
			continue;

		if (!pci)
			continue;

		status = efi_call_phys4(pci->attributes, pci,
					EfiPciIoAttributeOperationGet, 0,
					&attributes);

		if (status != EFI_SUCCESS)
			continue;

		if (!attributes & EFI_PCI_IO_ATTRIBUTE_EMBEDDED_ROM)
			continue;

		if (!pci->romimage || !pci->romsize)
			continue;

		size = pci->romsize + sizeof(*rom);

		status = efi_call_phys3(sys_table->boottime->allocate_pool,
				EFI_LOADER_DATA, size, &rom);

		if (status != EFI_SUCCESS)
			continue;

		rom->data.type = SETUP_PCI;
		rom->data.len = size - sizeof(struct setup_data);
		rom->data.next = 0;
		rom->pcilen = pci->romsize;

		status = efi_call_phys5(pci->pci.read, pci,
					EfiPciIoWidthUint16, PCI_VENDOR_ID,
					1, &(rom->vendor));

		if (status != EFI_SUCCESS)
			goto free_struct;

		status = efi_call_phys5(pci->pci.read, pci,
					EfiPciIoWidthUint16, PCI_DEVICE_ID,
					1, &(rom->devid));

		if (status != EFI_SUCCESS)
			goto free_struct;

		status = efi_call_phys5(pci->get_location, pci,
					&(rom->segment), &(rom->bus),
					&(rom->device), &(rom->function));

		if (status != EFI_SUCCESS)
			goto free_struct;

		memcpy(rom->romdata, pci->romimage, pci->romsize);

		if (data)
			data->next = (uint64_t)rom;
		else
			params->hdr.setup_data = (uint64_t)rom;

		data = (struct setup_data *)rom;

		continue;
	free_struct:
		efi_call_phys1(sys_table->boottime->free_pool, rom);
	}

free_handle:
	efi_call_phys1(sys_table->boottime->free_pool, pci_handle);
	return status;
}

/*
/*
 * See if we have Graphics Output Protocol
 * See if we have Graphics Output Protocol
 */
 */
@@ -1026,6 +1142,8 @@ struct boot_params *efi_main(void *handle, efi_system_table_t *_table,


	setup_graphics(boot_params);
	setup_graphics(boot_params);


	setup_efi_pci(boot_params);

	status = efi_call_phys3(sys_table->boottime->allocate_pool,
	status = efi_call_phys3(sys_table->boottime->allocate_pool,
				EFI_LOADER_DATA, sizeof(*gdt),
				EFI_LOADER_DATA, sizeof(*gdt),
				(void **)&gdt);
				(void **)&gdt);
+1 −0
Original line number Original line Diff line number Diff line
@@ -13,6 +13,7 @@
#define SETUP_NONE			0
#define SETUP_NONE			0
#define SETUP_E820_EXT			1
#define SETUP_E820_EXT			1
#define SETUP_DTB			2
#define SETUP_DTB			2
#define SETUP_PCI			3


/* extensible setup data list node */
/* extensible setup data list node */
struct setup_data {
struct setup_data {
+12 −0
Original line number Original line Diff line number Diff line
@@ -171,4 +171,16 @@ cpumask_of_pcibus(const struct pci_bus *bus)
}
}
#endif
#endif


struct pci_setup_rom {
	struct setup_data data;
	uint16_t vendor;
	uint16_t devid;
	uint64_t pcilen;
	unsigned long segment;
	unsigned long bus;
	unsigned long device;
	unsigned long function;
	uint8_t romdata[0];
};

#endif /* _ASM_X86_PCI_H */
#endif /* _ASM_X86_PCI_H */
+0 −4
Original line number Original line Diff line number Diff line
@@ -143,11 +143,7 @@ int default_check_phys_apicid_present(int phys_apicid)
}
}
#endif
#endif


#ifndef CONFIG_DEBUG_BOOT_PARAMS
struct boot_params __initdata boot_params;
#else
struct boot_params boot_params;
struct boot_params boot_params;
#endif


/*
/*
 * Machine setup..
 * Machine setup..
+30 −0
Original line number Original line Diff line number Diff line
@@ -17,6 +17,7 @@
#include <asm/io.h>
#include <asm/io.h>
#include <asm/smp.h>
#include <asm/smp.h>
#include <asm/pci_x86.h>
#include <asm/pci_x86.h>
#include <asm/setup.h>


unsigned int pci_probe = PCI_PROBE_BIOS | PCI_PROBE_CONF1 | PCI_PROBE_CONF2 |
unsigned int pci_probe = PCI_PROBE_BIOS | PCI_PROBE_CONF1 | PCI_PROBE_CONF2 |
				PCI_PROBE_MMCONF;
				PCI_PROBE_MMCONF;
@@ -608,6 +609,35 @@ unsigned int pcibios_assign_all_busses(void)
	return (pci_probe & PCI_ASSIGN_ALL_BUSSES) ? 1 : 0;
	return (pci_probe & PCI_ASSIGN_ALL_BUSSES) ? 1 : 0;
}
}


int pcibios_add_device(struct pci_dev *dev)
{
	struct setup_data *data;
	struct pci_setup_rom *rom;
	u64 pa_data;

	pa_data = boot_params.hdr.setup_data;
	while (pa_data) {
		data = phys_to_virt(pa_data);

		if (data->type == SETUP_PCI) {
			rom = (struct pci_setup_rom *)data;

			if ((pci_domain_nr(dev->bus) == rom->segment) &&
			    (dev->bus->number == rom->bus) &&
			    (PCI_SLOT(dev->devfn) == rom->device) &&
			    (PCI_FUNC(dev->devfn) == rom->function) &&
			    (dev->vendor == rom->vendor) &&
			    (dev->device == rom->devid)) {
				dev->rom = (void *)(unsigned long)(pa_data +
				      offsetof(struct pci_setup_rom, romdata));
				dev->romlen = rom->pcilen;
			}
		}
		pa_data = data->next;
	}
	return 0;
}

int pcibios_enable_device(struct pci_dev *dev, int mask)
int pcibios_enable_device(struct pci_dev *dev, int mask)
{
{
	int err;
	int err;
Loading