Browse Source

[efi] Mark SNP devices as children of EFI PCI device

Re-open the EFI_PCI_IO_PROTOCOL specifying an Attributes value of
EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER.  This causes the SNP devices to
be marked as children of the EFI PCI device (as shown in the "devtree"
command).

On at least one IBM blade system, this is required in order to have
the relevant drivers automatically attach to the SNP controller at
device creation time.

Signed-off-by: Michael Brown <mcb30@ipxe.org>
tags/v1.20.1
Michael Brown 13 years ago
parent
commit
b9326c3655
3 changed files with 70 additions and 0 deletions
  1. 6
    0
      src/include/ipxe/efi/efi_pci.h
  2. 49
    0
      src/interface/efi/efi_pci.c
  3. 15
    0
      src/interface/efi/efi_snp.c

+ 6
- 0
src/include/ipxe/efi/efi_pci.h View File

27
 	EFI_PCI_IO_PROTOCOL *pci_io;
27
 	EFI_PCI_IO_PROTOCOL *pci_io;
28
 	/** Device path */
28
 	/** Device path */
29
 	EFI_DEVICE_PATH_PROTOCOL *path;
29
 	EFI_DEVICE_PATH_PROTOCOL *path;
30
+	/** EFI driver */
31
+	struct efi_driver *efidrv;
30
 };
32
 };
31
 
33
 
32
 extern struct efi_pci_device * efipci_create ( struct efi_driver *efidrv,
34
 extern struct efi_pci_device * efipci_create ( struct efi_driver *efidrv,
34
 extern EFI_STATUS efipci_enable ( struct efi_pci_device *efipci );
36
 extern EFI_STATUS efipci_enable ( struct efi_pci_device *efipci );
35
 extern struct efi_pci_device * efipci_find_efi ( EFI_HANDLE device );
37
 extern struct efi_pci_device * efipci_find_efi ( EFI_HANDLE device );
36
 extern struct efi_pci_device * efipci_find ( struct device *dev );
38
 extern struct efi_pci_device * efipci_find ( struct device *dev );
39
+extern EFI_STATUS efipci_child_add ( struct efi_pci_device *efipci,
40
+				     EFI_HANDLE device );
41
+extern void efipci_child_del ( struct efi_pci_device *efipci,
42
+			       EFI_HANDLE device );
37
 extern void efipci_destroy ( struct efi_driver *efidrv,
43
 extern void efipci_destroy ( struct efi_driver *efidrv,
38
 			     struct efi_pci_device *efipci );
44
 			     struct efi_pci_device *efipci );
39
 
45
 

+ 49
- 0
src/interface/efi/efi_pci.c View File

139
 	if ( ! efipci )
139
 	if ( ! efipci )
140
 		goto err_zalloc;
140
 		goto err_zalloc;
141
 	efipci->device = device;
141
 	efipci->device = device;
142
+	efipci->efidrv = efidrv;
142
 
143
 
143
 	/* See if device is a PCI device */
144
 	/* See if device is a PCI device */
144
 	if ( ( efirc = bs->OpenProtocol ( device,
145
 	if ( ( efirc = bs->OpenProtocol ( device,
262
 	return NULL;
263
 	return NULL;
263
 }
264
 }
264
 
265
 
266
+/**
267
+ * Add EFI device as child of EFI PCI device
268
+ *
269
+ * @v efipci		EFI PCI device
270
+ * @v device		EFI child device
271
+ * @ret efirc		EFI status code
272
+ */
273
+EFI_STATUS efipci_child_add ( struct efi_pci_device *efipci,
274
+			      EFI_HANDLE device ) {
275
+	EFI_BOOT_SERVICES *bs = efi_systab->BootServices;
276
+	struct efi_driver *efidrv = efipci->efidrv;
277
+	union {
278
+		EFI_PCI_IO_PROTOCOL *pci_io;
279
+		void *interface;
280
+	} pci_io;
281
+	EFI_STATUS efirc;
282
+
283
+	/* Re-open the PCI_IO_PROTOCOL */
284
+	if ( ( efirc = bs->OpenProtocol ( efipci->device,
285
+					  &efi_pci_io_protocol_guid,
286
+					  &pci_io.interface,
287
+					  efidrv->driver.DriverBindingHandle,
288
+					  device,
289
+					  EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER
290
+					  ) ) != 0 ) {
291
+		DBGC ( efipci, "EFIPCI " PCI_FMT " could not add child: %s\n",
292
+		       PCI_ARGS ( &efipci->pci ), efi_strerror ( efirc ) );
293
+		return efirc;
294
+	}
295
+
296
+	return 0;
297
+}
298
+
299
+/**
300
+ * Remove EFI device as child of PCI device
301
+ *
302
+ * @v efipci		EFI PCI device
303
+ * @v device		EFI child device
304
+ * @ret efirc		EFI status code
305
+ */
306
+void efipci_child_del ( struct efi_pci_device *efipci, EFI_HANDLE device ) {
307
+	EFI_BOOT_SERVICES *bs = efi_systab->BootServices;
308
+	struct efi_driver *efidrv = efipci->efidrv;
309
+
310
+	bs->CloseProtocol ( efipci->device, &efi_pci_io_protocol_guid,
311
+			    efidrv->driver.DriverBindingHandle, device );
312
+}
313
+
265
 /**
314
 /**
266
  * Destroy EFI PCI device
315
  * Destroy EFI PCI device
267
  *
316
  *

+ 15
- 0
src/interface/efi/efi_snp.c View File

46
 	struct list_head list;
46
 	struct list_head list;
47
 	/** The underlying iPXE network device */
47
 	/** The underlying iPXE network device */
48
 	struct net_device *netdev;
48
 	struct net_device *netdev;
49
+	/** The underlying EFI PCI device */
50
+	struct efi_pci_device *efipci;
49
 	/** EFI device handle */
51
 	/** EFI device handle */
50
 	EFI_HANDLE handle;
52
 	EFI_HANDLE handle;
51
 	/** The SNP structure itself */
53
 	/** The SNP structure itself */
795
 		goto err_alloc_snp;
797
 		goto err_alloc_snp;
796
 	}
798
 	}
797
 	snpdev->netdev = netdev_get ( netdev );
799
 	snpdev->netdev = netdev_get ( netdev );
800
+	snpdev->efipci = efipci;
798
 
801
 
799
 	/* Sanity check */
802
 	/* Sanity check */
800
 	if ( netdev->ll_protocol->ll_addr_len > sizeof ( EFI_MAC_ADDRESS ) ) {
803
 	if ( netdev->ll_protocol->ll_addr_len > sizeof ( EFI_MAC_ADDRESS ) ) {
865
 		goto err_install_protocol_interface;
868
 		goto err_install_protocol_interface;
866
 	}
869
 	}
867
 
870
 
871
+	/* Add as child of PCI device */
872
+	if ( ( efirc = efipci_child_add ( efipci, snpdev->handle ) ) != 0 ) {
873
+		DBGC ( snpdev, "SNPDEV %p could not become child of " PCI_FMT
874
+		       ": %s\n", snpdev, PCI_ARGS ( &efipci->pci ),
875
+		       efi_strerror ( efirc ) );
876
+		rc = EFIRC_TO_RC ( efirc );
877
+		goto err_efipci_child_add;
878
+	}
879
+
868
 	/* Add to list of SNP devices */
880
 	/* Add to list of SNP devices */
869
 	list_add ( &snpdev->list, &efi_snp_devices );
881
 	list_add ( &snpdev->list, &efi_snp_devices );
870
 
882
 
872
 	       snpdev, netdev->name, snpdev->handle );
884
 	       snpdev, netdev->name, snpdev->handle );
873
 	return 0;
885
 	return 0;
874
 
886
 
887
+	efipci_child_del ( efipci, snpdev->handle );
888
+ err_efipci_child_add:
875
 	bs->UninstallMultipleProtocolInterfaces (
889
 	bs->UninstallMultipleProtocolInterfaces (
876
 			snpdev->handle,
890
 			snpdev->handle,
877
 			&efi_simple_network_protocol_guid, &snpdev->snp,
891
 			&efi_simple_network_protocol_guid, &snpdev->snp,
916
 	}
930
 	}
917
 
931
 
918
 	/* Uninstall the SNP */
932
 	/* Uninstall the SNP */
933
+	efipci_child_del ( snpdev->efipci, snpdev->handle );
919
 	list_del ( &snpdev->list );
934
 	list_del ( &snpdev->list );
920
 	bs->UninstallMultipleProtocolInterfaces (
935
 	bs->UninstallMultipleProtocolInterfaces (
921
 			snpdev->handle,
936
 			snpdev->handle,

Loading…
Cancel
Save