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
This commit is contained in:
		
						commit
						72e1e868ca
					
				| @ -8,6 +8,7 @@ | ||||
|  * ----------------------------------------------------------------------- */ | ||||
| 
 | ||||
| #include <linux/efi.h> | ||||
| #include <linux/pci.h> | ||||
| #include <asm/efi.h> | ||||
| #include <asm/setup.h> | ||||
| #include <asm/desc.h> | ||||
| @ -243,6 +244,121 @@ static void find_bits(unsigned long mask, u8 *pos, u8 *size) | ||||
| 	*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 | ||||
|  */ | ||||
| @ -1026,6 +1142,8 @@ struct boot_params *efi_main(void *handle, efi_system_table_t *_table, | ||||
| 
 | ||||
| 	setup_graphics(boot_params); | ||||
| 
 | ||||
| 	setup_efi_pci(boot_params); | ||||
| 
 | ||||
| 	status = efi_call_phys3(sys_table->boottime->allocate_pool, | ||||
| 				EFI_LOADER_DATA, sizeof(*gdt), | ||||
| 				(void **)&gdt); | ||||
|  | ||||
| @ -13,6 +13,7 @@ | ||||
| #define SETUP_NONE			0 | ||||
| #define SETUP_E820_EXT			1 | ||||
| #define SETUP_DTB			2 | ||||
| #define SETUP_PCI			3 | ||||
| 
 | ||||
| /* extensible setup data list node */ | ||||
| struct setup_data { | ||||
|  | ||||
| @ -171,4 +171,16 @@ cpumask_of_pcibus(const struct pci_bus *bus) | ||||
| } | ||||
| #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 */ | ||||
|  | ||||
| @ -143,11 +143,7 @@ int default_check_phys_apicid_present(int phys_apicid) | ||||
| } | ||||
| #endif | ||||
| 
 | ||||
| #ifndef CONFIG_DEBUG_BOOT_PARAMS | ||||
| struct boot_params __initdata boot_params; | ||||
| #else | ||||
| struct boot_params boot_params; | ||||
| #endif | ||||
| 
 | ||||
| /*
 | ||||
|  * Machine setup.. | ||||
|  | ||||
| @ -17,6 +17,7 @@ | ||||
| #include <asm/io.h> | ||||
| #include <asm/smp.h> | ||||
| #include <asm/pci_x86.h> | ||||
| #include <asm/setup.h> | ||||
| 
 | ||||
| unsigned int pci_probe = PCI_PROBE_BIOS | PCI_PROBE_CONF1 | PCI_PROBE_CONF2 | | ||||
| 				PCI_PROBE_MMCONF; | ||||
| @ -608,6 +609,35 @@ unsigned int pcibios_assign_all_busses(void) | ||||
| 	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 err; | ||||
|  | ||||
| @ -170,6 +170,11 @@ int pci_bus_add_device(struct pci_dev *dev) | ||||
| 	int retval; | ||||
| 
 | ||||
| 	pci_fixup_device(pci_fixup_final, dev); | ||||
| 
 | ||||
| 	retval = pcibios_add_device(dev); | ||||
| 	if (retval) | ||||
| 		return retval; | ||||
| 
 | ||||
| 	retval = device_add(&dev->dev); | ||||
| 	if (retval) | ||||
| 		return retval; | ||||
|  | ||||
| @ -1333,6 +1333,19 @@ void pcim_pin_device(struct pci_dev *pdev) | ||||
| 		dr->pinned = 1; | ||||
| } | ||||
| 
 | ||||
| /*
 | ||||
|  * pcibios_add_device - provide arch specific hooks when adding device dev | ||||
|  * @dev: the PCI device being added | ||||
|  * | ||||
|  * Permits the platform to provide architecture specific functionality when | ||||
|  * devices are added. This is the default implementation. Architecture | ||||
|  * implementations can override this. | ||||
|  */ | ||||
| int __weak pcibios_add_device (struct pci_dev *dev) | ||||
| { | ||||
| 	return 0; | ||||
| } | ||||
| 
 | ||||
| /**
 | ||||
|  * pcibios_disable_device - disable arch specific PCI resources for device dev | ||||
|  * @dev: the PCI device to disable | ||||
|  | ||||
| @ -117,12 +117,18 @@ void __iomem *pci_map_rom(struct pci_dev *pdev, size_t *size) | ||||
| 	loff_t start; | ||||
| 	void __iomem *rom; | ||||
| 
 | ||||
| 	/*
 | ||||
| 	 * Some devices may provide ROMs via a source other than the BAR | ||||
| 	 */ | ||||
| 	if (pdev->rom && pdev->romlen) { | ||||
| 		*size = pdev->romlen; | ||||
| 		return phys_to_virt((phys_addr_t)pdev->rom); | ||||
| 	/*
 | ||||
| 	 * 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. | ||||
| 	 */ | ||||
| 	if (res->flags & IORESOURCE_ROM_SHADOW) { | ||||
| 	} else if (res->flags & IORESOURCE_ROM_SHADOW) { | ||||
| 		/* primary video rom always starts here */ | ||||
| 		start = (loff_t)0xC0000; | ||||
| 		*size = 0x20000; /* cover C000:0 through E000:0 */ | ||||
| @ -181,7 +187,8 @@ void pci_unmap_rom(struct pci_dev *pdev, void __iomem *rom) | ||||
| 	if (res->flags & (IORESOURCE_ROM_COPY | IORESOURCE_ROM_BIOS_COPY)) | ||||
| 		return; | ||||
| 
 | ||||
| 	iounmap(rom); | ||||
| 	if (!pdev->rom || !pdev->romlen) | ||||
| 		iounmap(rom); | ||||
| 
 | ||||
| 	/* Disable again before continuing, leave enabled if pci=rom */ | ||||
| 	if (!(res->flags & (IORESOURCE_ROM_ENABLE | IORESOURCE_ROM_SHADOW))) | ||||
|  | ||||
| @ -196,6 +196,77 @@ typedef struct { | ||||
| 	void *create_event_ex; | ||||
| } efi_boot_services_t; | ||||
| 
 | ||||
| typedef enum { | ||||
| 	EfiPciIoWidthUint8, | ||||
| 	EfiPciIoWidthUint16, | ||||
| 	EfiPciIoWidthUint32, | ||||
| 	EfiPciIoWidthUint64, | ||||
| 	EfiPciIoWidthFifoUint8, | ||||
| 	EfiPciIoWidthFifoUint16, | ||||
| 	EfiPciIoWidthFifoUint32, | ||||
| 	EfiPciIoWidthFifoUint64, | ||||
| 	EfiPciIoWidthFillUint8, | ||||
| 	EfiPciIoWidthFillUint16, | ||||
| 	EfiPciIoWidthFillUint32, | ||||
| 	EfiPciIoWidthFillUint64, | ||||
| 	EfiPciIoWidthMaximum | ||||
| } EFI_PCI_IO_PROTOCOL_WIDTH; | ||||
| 
 | ||||
| typedef enum { | ||||
| 	EfiPciIoAttributeOperationGet, | ||||
| 	EfiPciIoAttributeOperationSet, | ||||
| 	EfiPciIoAttributeOperationEnable, | ||||
| 	EfiPciIoAttributeOperationDisable, | ||||
| 	EfiPciIoAttributeOperationSupported, | ||||
|     EfiPciIoAttributeOperationMaximum | ||||
| } EFI_PCI_IO_PROTOCOL_ATTRIBUTE_OPERATION; | ||||
| 
 | ||||
| 
 | ||||
| typedef struct { | ||||
| 	void *read; | ||||
| 	void *write; | ||||
| } efi_pci_io_protocol_access_t; | ||||
| 
 | ||||
| typedef struct { | ||||
| 	void *poll_mem; | ||||
| 	void *poll_io; | ||||
| 	efi_pci_io_protocol_access_t mem; | ||||
| 	efi_pci_io_protocol_access_t io; | ||||
| 	efi_pci_io_protocol_access_t pci; | ||||
| 	void *copy_mem; | ||||
| 	void *map; | ||||
| 	void *unmap; | ||||
| 	void *allocate_buffer; | ||||
| 	void *free_buffer; | ||||
| 	void *flush; | ||||
| 	void *get_location; | ||||
| 	void *attributes; | ||||
| 	void *get_bar_attributes; | ||||
| 	void *set_bar_attributes; | ||||
| 	uint64_t romsize; | ||||
| 	void *romimage; | ||||
| } efi_pci_io_protocol; | ||||
| 
 | ||||
| #define EFI_PCI_IO_ATTRIBUTE_ISA_MOTHERBOARD_IO 0x0001 | ||||
| #define EFI_PCI_IO_ATTRIBUTE_ISA_IO 0x0002 | ||||
| #define EFI_PCI_IO_ATTRIBUTE_VGA_PALETTE_IO 0x0004 | ||||
| #define EFI_PCI_IO_ATTRIBUTE_VGA_MEMORY 0x0008 | ||||
| #define EFI_PCI_IO_ATTRIBUTE_VGA_IO 0x0010 | ||||
| #define EFI_PCI_IO_ATTRIBUTE_IDE_PRIMARY_IO 0x0020 | ||||
| #define EFI_PCI_IO_ATTRIBUTE_IDE_SECONDARY_IO 0x0040 | ||||
| #define EFI_PCI_IO_ATTRIBUTE_MEMORY_WRITE_COMBINE 0x0080 | ||||
| #define EFI_PCI_IO_ATTRIBUTE_IO 0x0100 | ||||
| #define EFI_PCI_IO_ATTRIBUTE_MEMORY 0x0200 | ||||
| #define EFI_PCI_IO_ATTRIBUTE_BUS_MASTER 0x0400 | ||||
| #define EFI_PCI_IO_ATTRIBUTE_MEMORY_CACHED 0x0800 | ||||
| #define EFI_PCI_IO_ATTRIBUTE_MEMORY_DISABLE 0x1000 | ||||
| #define EFI_PCI_IO_ATTRIBUTE_EMBEDDED_DEVICE 0x2000 | ||||
| #define EFI_PCI_IO_ATTRIBUTE_EMBEDDED_ROM 0x4000 | ||||
| #define EFI_PCI_IO_ATTRIBUTE_DUAL_ADDRESS_CYCLE 0x8000 | ||||
| #define EFI_PCI_IO_ATTRIBUTE_ISA_IO_16 0x10000 | ||||
| #define EFI_PCI_IO_ATTRIBUTE_VGA_PALETTE_IO_16 0x20000 | ||||
| #define EFI_PCI_IO_ATTRIBUTE_VGA_IO_16 0x40000 | ||||
| 
 | ||||
| /*
 | ||||
|  * Types and defines for EFI ResetSystem | ||||
|  */ | ||||
|  | ||||
| @ -333,6 +333,8 @@ struct pci_dev { | ||||
| 	}; | ||||
| 	struct pci_ats	*ats;	/* Address Translation Service */ | ||||
| #endif | ||||
| 	void *rom; /* Physical pointer to ROM if it's not from the BAR */ | ||||
| 	size_t romlen; /* Length of ROM if it's not from the BAR */ | ||||
| }; | ||||
| 
 | ||||
| static inline struct pci_dev *pci_physfn(struct pci_dev *dev) | ||||
| @ -1599,6 +1601,7 @@ void pcibios_disable_device(struct pci_dev *dev); | ||||
| void pcibios_set_master(struct pci_dev *dev); | ||||
| int pcibios_set_pcie_reset_state(struct pci_dev *dev, | ||||
| 				 enum pcie_reset_state state); | ||||
| int pcibios_add_device(struct pci_dev *dev); | ||||
| 
 | ||||
| #ifdef CONFIG_PCI_MMCONFIG | ||||
| extern void __init pci_mmcfg_early_init(void); | ||||
|  | ||||
		Loading…
	
		Reference in New Issue
	
	Block a user