EFI_PCI_IO_PROTOCOL *pci_io;
/** Device path */
EFI_DEVICE_PATH_PROTOCOL *path;
+ /** EFI driver */
+ struct efi_driver *efidrv;
};
extern struct efi_pci_device * efipci_create ( struct efi_driver *efidrv,
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 EFI_STATUS efipci_child_add ( struct efi_pci_device *efipci,
+ EFI_HANDLE device );
+extern void efipci_child_del ( struct efi_pci_device *efipci,
+ EFI_HANDLE device );
extern void efipci_destroy ( struct efi_driver *efidrv,
struct efi_pci_device *efipci );
if ( ! efipci )
goto err_zalloc;
efipci->device = device;
+ efipci->efidrv = efidrv;
/* See if device is a PCI device */
if ( ( efirc = bs->OpenProtocol ( device,
return NULL;
}
+/**
+ * Add EFI device as child of EFI PCI device
+ *
+ * @v efipci EFI PCI device
+ * @v device EFI child device
+ * @ret efirc EFI status code
+ */
+EFI_STATUS efipci_child_add ( struct efi_pci_device *efipci,
+ EFI_HANDLE device ) {
+ EFI_BOOT_SERVICES *bs = efi_systab->BootServices;
+ struct efi_driver *efidrv = efipci->efidrv;
+ union {
+ EFI_PCI_IO_PROTOCOL *pci_io;
+ void *interface;
+ } pci_io;
+ EFI_STATUS efirc;
+
+ /* Re-open the PCI_IO_PROTOCOL */
+ if ( ( efirc = bs->OpenProtocol ( efipci->device,
+ &efi_pci_io_protocol_guid,
+ &pci_io.interface,
+ efidrv->driver.DriverBindingHandle,
+ device,
+ EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER
+ ) ) != 0 ) {
+ DBGC ( efipci, "EFIPCI " PCI_FMT " could not add child: %s\n",
+ PCI_ARGS ( &efipci->pci ), efi_strerror ( efirc ) );
+ return efirc;
+ }
+
+ return 0;
+}
+
+/**
+ * Remove EFI device as child of PCI device
+ *
+ * @v efipci EFI PCI device
+ * @v device EFI child device
+ * @ret efirc EFI status code
+ */
+void efipci_child_del ( struct efi_pci_device *efipci, EFI_HANDLE device ) {
+ EFI_BOOT_SERVICES *bs = efi_systab->BootServices;
+ struct efi_driver *efidrv = efipci->efidrv;
+
+ bs->CloseProtocol ( efipci->device, &efi_pci_io_protocol_guid,
+ efidrv->driver.DriverBindingHandle, device );
+}
+
/**
* Destroy EFI PCI device
*
struct list_head list;
/** The underlying iPXE network device */
struct net_device *netdev;
+ /** The underlying EFI PCI device */
+ struct efi_pci_device *efipci;
/** EFI device handle */
EFI_HANDLE handle;
/** The SNP structure itself */
goto err_alloc_snp;
}
snpdev->netdev = netdev_get ( netdev );
+ snpdev->efipci = efipci;
/* Sanity check */
if ( netdev->ll_protocol->ll_addr_len > sizeof ( EFI_MAC_ADDRESS ) ) {
goto err_install_protocol_interface;
}
+ /* Add as child of PCI device */
+ if ( ( efirc = efipci_child_add ( efipci, snpdev->handle ) ) != 0 ) {
+ DBGC ( snpdev, "SNPDEV %p could not become child of " PCI_FMT
+ ": %s\n", snpdev, PCI_ARGS ( &efipci->pci ),
+ efi_strerror ( efirc ) );
+ rc = EFIRC_TO_RC ( efirc );
+ goto err_efipci_child_add;
+ }
+
/* Add to list of SNP devices */
list_add ( &snpdev->list, &efi_snp_devices );
snpdev, netdev->name, snpdev->handle );
return 0;
+ efipci_child_del ( efipci, snpdev->handle );
+ err_efipci_child_add:
bs->UninstallMultipleProtocolInterfaces (
snpdev->handle,
&efi_simple_network_protocol_guid, &snpdev->snp,
}
/* Uninstall the SNP */
+ efipci_child_del ( snpdev->efipci, snpdev->handle );
list_del ( &snpdev->list );
bs->UninstallMultipleProtocolInterfaces (
snpdev->handle,