Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
[efi] Allow EFI to control PCI bus enumeration
EFI performs its own PCI bus enumeration. Respect this, and start controlling devices only when instructed to do so by EFI. As a side benefit, we should now correctly create multiple SNP instances for multi-port devices. This should also fix the problem of failing to enumerate devices because the PCI bridges have not yet been enabled at the time the iPXE driver is loaded. Signed-off-by: Michael Brown <mcb30@ipxe.org>
- Loading branch information
Showing
7 changed files
with
685 additions
and
288 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,49 @@ | ||
#ifndef _IPXE_EFI_DRIVER_H | ||
#define _IPXE_EFI_DRIVER_H | ||
|
||
/** @file | ||
* | ||
* EFI driver interface | ||
*/ | ||
|
||
FILE_LICENCE ( GPL2_OR_LATER ); | ||
|
||
#include <ipxe/efi/efi.h> | ||
#include <ipxe/efi/Protocol/DriverBinding.h> | ||
#include <ipxe/efi/Protocol/ComponentName2.h> | ||
#include <ipxe/efi/Protocol/DevicePath.h> | ||
|
||
/** An EFI driver */ | ||
struct efi_driver { | ||
/** Name */ | ||
const char *name; | ||
/** EFI name */ | ||
CHAR16 *wname; | ||
/** EFI driver binding protocol */ | ||
EFI_DRIVER_BINDING_PROTOCOL driver; | ||
/** EFI component name protocol */ | ||
EFI_COMPONENT_NAME2_PROTOCOL wtf; | ||
}; | ||
|
||
/** Initialise an EFI driver | ||
* | ||
* @v name Driver name | ||
* @v supported Device supported method | ||
* @v start Device start method | ||
* @v stop Device stop method | ||
*/ | ||
#define EFI_DRIVER_INIT( _name, _supported, _start, _stop ) { \ | ||
.name = _name, \ | ||
.driver = { \ | ||
.Supported = _supported, \ | ||
.Start = _start, \ | ||
.Stop = _stop, \ | ||
.Version = 0x10, \ | ||
} } | ||
|
||
extern EFI_DEVICE_PATH_PROTOCOL * | ||
efi_devpath_end ( EFI_DEVICE_PATH_PROTOCOL *path ); | ||
|
||
extern EFI_STATUS efi_driver_install ( struct efi_driver *efidrv ); | ||
|
||
#endif /* _IPXE_EFI_DRIVER_H */ |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,40 @@ | ||
#ifndef _IPXE_EFI_PCI_H | ||
#define _IPXE_EFI_PCI_H | ||
|
||
/** @file | ||
* | ||
* EFI driver interface | ||
*/ | ||
|
||
FILE_LICENCE ( GPL2_OR_LATER ); | ||
|
||
#include <ipxe/efi/efi.h> | ||
#include <ipxe/efi/Protocol/PciIo.h> | ||
#include <ipxe/efi/Protocol/DevicePath.h> | ||
|
||
struct efi_driver; | ||
struct device; | ||
|
||
/** An EFI PCI device */ | ||
struct efi_pci_device { | ||
/** List of EFI PCI devices */ | ||
struct list_head list; | ||
/** iPXE PCI device */ | ||
struct pci_device pci; | ||
/** Underlying EFI device */ | ||
EFI_HANDLE device; | ||
/** PCI I/O protocol */ | ||
EFI_PCI_IO_PROTOCOL *pci_io; | ||
/** Device path */ | ||
EFI_DEVICE_PATH_PROTOCOL *path; | ||
}; | ||
|
||
extern struct efi_pci_device * efipci_create ( struct efi_driver *efidrv, | ||
EFI_HANDLE device ); | ||
extern EFI_STATUS efipci_enable ( struct efi_pci_device *efipci ); | ||
extern struct efi_pci_device * efipci_find_efi ( EFI_HANDLE device ); | ||
extern struct efi_pci_device * efipci_find ( struct device *dev ); | ||
extern void efipci_destroy ( struct efi_driver *efidrv, | ||
struct efi_pci_device *efipci ); | ||
|
||
#endif /* _IPXE_EFI_PCI_H */ |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,143 @@ | ||
/* | ||
* Copyright (C) 2011 Michael Brown <mbrown@fensystems.co.uk>. | ||
* | ||
* This program is free software; you can redistribute it and/or | ||
* modify it under the terms of the GNU General Public License as | ||
* published by the Free Software Foundation; either version 2 of the | ||
* License, or any later version. | ||
* | ||
* This program is distributed in the hope that it will be useful, but | ||
* WITHOUT ANY WARRANTY; without even the implied warranty of | ||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
* General Public License for more details. | ||
* | ||
* You should have received a copy of the GNU General Public License | ||
* along with this program; if not, write to the Free Software | ||
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. | ||
*/ | ||
|
||
FILE_LICENCE ( GPL2_OR_LATER ); | ||
|
||
#include <stddef.h> | ||
#include <stdio.h> | ||
#include <ipxe/efi/efi.h> | ||
#include <ipxe/efi/Protocol/DriverBinding.h> | ||
#include <ipxe/efi/Protocol/ComponentName2.h> | ||
#include <ipxe/efi/efi_driver.h> | ||
#include <config/general.h> | ||
|
||
/** @file | ||
* | ||
* EFI driver interface | ||
* | ||
*/ | ||
|
||
/** EFI driver binding protocol GUID */ | ||
static EFI_GUID efi_driver_binding_protocol_guid | ||
= EFI_DRIVER_BINDING_PROTOCOL_GUID; | ||
|
||
/** EFI component name protocol GUID */ | ||
static EFI_GUID efi_component_name2_protocol_guid | ||
= EFI_COMPONENT_NAME2_PROTOCOL_GUID; | ||
|
||
/** | ||
* Find end of device path | ||
* | ||
* @v path Path to device | ||
* @ret path_end End of device path | ||
*/ | ||
EFI_DEVICE_PATH_PROTOCOL * efi_devpath_end ( EFI_DEVICE_PATH_PROTOCOL *path ) { | ||
|
||
while ( path->Type != END_DEVICE_PATH_TYPE ) { | ||
path = ( ( ( void * ) path ) + | ||
/* There's this amazing new-fangled thing known as | ||
* a UINT16, but who wants to use one of those? */ | ||
( ( path->Length[1] << 8 ) | path->Length[0] ) ); | ||
} | ||
|
||
return path; | ||
} | ||
|
||
/** | ||
* Look up driver name | ||
* | ||
* @v wtf Component name protocol | ||
* @v language Language to use | ||
* @v driver_name Driver name to fill in | ||
* @ret efirc EFI status code | ||
*/ | ||
static EFI_STATUS EFIAPI | ||
efi_driver_get_driver_name ( EFI_COMPONENT_NAME2_PROTOCOL *wtf, | ||
CHAR8 *language __unused, CHAR16 **driver_name ) { | ||
struct efi_driver *efidrv = | ||
container_of ( wtf, struct efi_driver, wtf ); | ||
|
||
*driver_name = efidrv->wname; | ||
return 0; | ||
} | ||
|
||
/** | ||
* Look up controller name | ||
* | ||
* @v wtf Component name protocol | ||
* @v device Device | ||
* @v child Child device, or NULL | ||
* @v language Language to use | ||
* @v driver_name Device name to fill in | ||
* @ret efirc EFI status code | ||
*/ | ||
static EFI_STATUS EFIAPI | ||
efi_driver_get_controller_name ( EFI_COMPONENT_NAME2_PROTOCOL *wtf __unused, | ||
EFI_HANDLE device __unused, | ||
EFI_HANDLE child __unused, | ||
CHAR8 *language __unused, | ||
CHAR16 **controller_name __unused ) { | ||
|
||
/* Just let EFI use the default Device Path Name */ | ||
return EFI_UNSUPPORTED; | ||
} | ||
|
||
/** | ||
* Install EFI driver | ||
* | ||
* @v efidrv EFI driver | ||
* @ret efirc EFI status code | ||
*/ | ||
EFI_STATUS efi_driver_install ( struct efi_driver *efidrv ) { | ||
EFI_BOOT_SERVICES *bs = efi_systab->BootServices; | ||
EFI_DRIVER_BINDING_PROTOCOL *driver = &efidrv->driver; | ||
EFI_COMPONENT_NAME2_PROTOCOL *wtf = &efidrv->wtf; | ||
char buf[ sizeof ( efidrv->wname ) / sizeof ( efidrv->wname[0] ) ]; | ||
unsigned int i; | ||
EFI_STATUS efirc; | ||
|
||
/* Configure driver binding protocol */ | ||
driver->ImageHandle = efi_image_handle; | ||
|
||
/* Configure component name protocol */ | ||
wtf->GetDriverName = efi_driver_get_driver_name; | ||
wtf->GetControllerName = efi_driver_get_controller_name; | ||
wtf->SupportedLanguages = "en"; | ||
|
||
/* Fill in driver name */ | ||
snprintf ( buf, sizeof ( buf ), PRODUCT_SHORT_NAME " - %s", | ||
efidrv->name ); | ||
for ( i = 0 ; i < sizeof ( buf ) ; i++ ) { | ||
/* Damn Unicode names */ | ||
efidrv->wname[i] = *( ( ( unsigned char * ) buf ) + i ); | ||
} | ||
|
||
/* Install driver */ | ||
if ( ( efirc = bs->InstallMultipleProtocolInterfaces ( | ||
&driver->DriverBindingHandle, | ||
&efi_driver_binding_protocol_guid, driver, | ||
&efi_component_name2_protocol_guid, wtf, | ||
NULL ) ) != 0 ) { | ||
DBGC ( efidrv, "EFIDRV %s could not install protocol: %s\n", | ||
efidrv->name, efi_strerror ( efirc ) ); | ||
return efirc; | ||
} | ||
|
||
DBGC ( efidrv, "EFIDRV %s installed\n", efidrv->name ); | ||
return 0; | ||
} |
Oops, something went wrong.