mirror of
https://github.com/edk2-porting/linux-next.git
synced 2024-12-17 09:43:59 +08:00
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/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);
|
||||||
|
@ -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 {
|
||||||
|
@ -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 */
|
||||||
|
@ -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..
|
||||||
|
@ -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;
|
||||||
|
@ -170,6 +170,11 @@ int pci_bus_add_device(struct pci_dev *dev)
|
|||||||
int retval;
|
int retval;
|
||||||
|
|
||||||
pci_fixup_device(pci_fixup_final, dev);
|
pci_fixup_device(pci_fixup_final, dev);
|
||||||
|
|
||||||
|
retval = pcibios_add_device(dev);
|
||||||
|
if (retval)
|
||||||
|
return retval;
|
||||||
|
|
||||||
retval = device_add(&dev->dev);
|
retval = device_add(&dev->dev);
|
||||||
if (retval)
|
if (retval)
|
||||||
return retval;
|
return retval;
|
||||||
|
@ -1333,6 +1333,19 @@ void pcim_pin_device(struct pci_dev *pdev)
|
|||||||
dr->pinned = 1;
|
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
|
* pcibios_disable_device - disable arch specific PCI resources for device dev
|
||||||
* @dev: the PCI device to disable
|
* @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;
|
loff_t start;
|
||||||
void __iomem *rom;
|
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
|
* 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
|
* memory map if the VGA enable bit of the Bridge Control register is
|
||||||
* set for embedded VGA.
|
* set for embedded VGA.
|
||||||
*/
|
*/
|
||||||
if (res->flags & IORESOURCE_ROM_SHADOW) {
|
} else if (res->flags & IORESOURCE_ROM_SHADOW) {
|
||||||
/* primary video rom always starts here */
|
/* primary video rom always starts here */
|
||||||
start = (loff_t)0xC0000;
|
start = (loff_t)0xC0000;
|
||||||
*size = 0x20000; /* cover C000:0 through E000:0 */
|
*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))
|
if (res->flags & (IORESOURCE_ROM_COPY | IORESOURCE_ROM_BIOS_COPY))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
iounmap(rom);
|
if (!pdev->rom || !pdev->romlen)
|
||||||
|
iounmap(rom);
|
||||||
|
|
||||||
/* Disable again before continuing, leave enabled if pci=rom */
|
/* Disable again before continuing, leave enabled if pci=rom */
|
||||||
if (!(res->flags & (IORESOURCE_ROM_ENABLE | IORESOURCE_ROM_SHADOW)))
|
if (!(res->flags & (IORESOURCE_ROM_ENABLE | IORESOURCE_ROM_SHADOW)))
|
||||||
|
@ -196,6 +196,77 @@ typedef struct {
|
|||||||
void *create_event_ex;
|
void *create_event_ex;
|
||||||
} efi_boot_services_t;
|
} 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
|
* Types and defines for EFI ResetSystem
|
||||||
*/
|
*/
|
||||||
|
@ -333,6 +333,8 @@ struct pci_dev {
|
|||||||
};
|
};
|
||||||
struct pci_ats *ats; /* Address Translation Service */
|
struct pci_ats *ats; /* Address Translation Service */
|
||||||
#endif
|
#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)
|
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);
|
void pcibios_set_master(struct pci_dev *dev);
|
||||||
int pcibios_set_pcie_reset_state(struct pci_dev *dev,
|
int pcibios_set_pcie_reset_state(struct pci_dev *dev,
|
||||||
enum pcie_reset_state state);
|
enum pcie_reset_state state);
|
||||||
|
int pcibios_add_device(struct pci_dev *dev);
|
||||||
|
|
||||||
#ifdef CONFIG_PCI_MMCONFIG
|
#ifdef CONFIG_PCI_MMCONFIG
|
||||||
extern void __init pci_mmcfg_early_init(void);
|
extern void __init pci_mmcfg_early_init(void);
|
||||||
|
Loading…
Reference in New Issue
Block a user