Explorar el Código

[efi] Allow network devices to be created on top of arbitrary SNP devices

Signed-off-by: Michael Brown <mcb30@ipxe.org>
tags/v1.20.1
Michael Brown hace 10 años
padre
commit
c7051d826b

+ 219
- 0
src/drivers/net/efi/snp.c Ver fichero

@@ -0,0 +1,219 @@
1
+/*
2
+ * Copyright (C) 2014 Michael Brown <mbrown@fensystems.co.uk>.
3
+ *
4
+ * This program is free software; you can redistribute it and/or
5
+ * modify it under the terms of the GNU General Public License as
6
+ * published by the Free Software Foundation; either version 2 of the
7
+ * License, or any later version.
8
+ *
9
+ * This program is distributed in the hope that it will be useful, but
10
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
11
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12
+ * General Public License for more details.
13
+ *
14
+ * You should have received a copy of the GNU General Public License
15
+ * along with this program; if not, write to the Free Software
16
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
17
+ * 02110-1301, USA.
18
+ */
19
+
20
+FILE_LICENCE ( GPL2_OR_LATER );
21
+
22
+#include <stdlib.h>
23
+#include <stdio.h>
24
+#include <string.h>
25
+#include <errno.h>
26
+#include <ipxe/efi/efi.h>
27
+#include <ipxe/efi/Protocol/SimpleNetwork.h>
28
+#include <ipxe/efi/efi_driver.h>
29
+#include <ipxe/efi/efi_snp.h>
30
+#include <ipxe/efi/efi_pci.h>
31
+#include "snpnet.h"
32
+#include "snp.h"
33
+
34
+/** @file
35
+ *
36
+ * SNP driver
37
+ *
38
+ */
39
+
40
+/** EFI simple network protocol GUID */
41
+static EFI_GUID efi_simple_network_protocol_guid
42
+	= EFI_SIMPLE_NETWORK_PROTOCOL_GUID;
43
+
44
+/** EFI PCI I/O protocol GUID */
45
+static EFI_GUID efi_pci_io_protocol_guid
46
+	= EFI_PCI_IO_PROTOCOL_GUID;
47
+
48
+/**
49
+ * Check to see if driver supports a device
50
+ *
51
+ * @v device		EFI device handle
52
+ * @ret rc		Return status code
53
+ */
54
+static int snp_supported ( EFI_HANDLE device ) {
55
+	EFI_BOOT_SERVICES *bs = efi_systab->BootServices;
56
+	EFI_STATUS efirc;
57
+
58
+	/* Check that this is not a device we are providing ourselves */
59
+	if ( find_snpdev ( device ) != NULL ) {
60
+		DBGCP ( device, "SNP %p %s is provided by this binary\n",
61
+			device, efi_handle_devpath_text ( device ) );
62
+		return -ENOTTY;
63
+	}
64
+
65
+	/* Test for presence of simple network protocol */
66
+	if ( ( efirc = bs->OpenProtocol ( device,
67
+					  &efi_simple_network_protocol_guid,
68
+					  NULL, efi_image_handle, device,
69
+					  EFI_OPEN_PROTOCOL_TEST_PROTOCOL))!=0){
70
+		DBGCP ( device, "SNP %p %s is not an SNP device\n",
71
+			device, efi_handle_devpath_text ( device ) );
72
+		return -EEFI ( efirc );
73
+	}
74
+	DBGC ( device, "SNP %p %s is an SNP device\n",
75
+	       device, efi_handle_devpath_text ( device ) );
76
+
77
+	return 0;
78
+}
79
+
80
+/**
81
+ * Get underlying PCI device information
82
+ *
83
+ * @v snpdev		SNP device
84
+ * @ret rc		Return status code
85
+ */
86
+static int snp_pci_info ( struct snp_device *snpdev ) {
87
+	EFI_BOOT_SERVICES *bs = efi_systab->BootServices;
88
+	struct efi_device *efidev = snpdev->efidev;
89
+	EFI_DEVICE_PATH_PROTOCOL *devpath = efidev->path;
90
+	struct pci_device pci;
91
+	EFI_HANDLE device;
92
+	EFI_STATUS efirc;
93
+	int rc;
94
+
95
+	/* Check for presence of PCI I/O protocol */
96
+	if ( ( efirc = bs->LocateDevicePath ( &efi_pci_io_protocol_guid,
97
+					      &devpath, &device ) ) != 0 ) {
98
+		DBGC ( efidev->device, "SNP %p %s is not a PCI device\n",
99
+		       efidev->device, efi_devpath_text ( efidev->path ) );
100
+		return -EEFI ( efirc );
101
+	}
102
+
103
+	/* Get PCI device information */
104
+	if ( ( rc = efipci_info ( device, &pci ) ) != 0 ) {
105
+		DBGC ( efidev->device, "SNP %p %s could not get PCI "
106
+		       "information: %s\n", efidev->device,
107
+		       efi_devpath_text ( efidev->path ), strerror ( rc ) );
108
+		return rc;
109
+	}
110
+
111
+	/* Populate SNP device information */
112
+	memcpy ( &snpdev->dev.desc, &pci.dev.desc, sizeof ( snpdev->dev.desc ));
113
+	snprintf ( snpdev->dev.name, sizeof ( snpdev->dev.name ), "SNP-%s",
114
+		   pci.dev.name );
115
+
116
+	return 0;
117
+}
118
+
119
+/**
120
+ * Attach driver to device
121
+ *
122
+ * @v efidev		EFI device
123
+ * @ret rc		Return status code
124
+ */
125
+static int snp_start ( struct efi_device *efidev ) {
126
+	EFI_BOOT_SERVICES *bs = efi_systab->BootServices;
127
+	EFI_HANDLE device = efidev->device;
128
+	struct snp_device *snpdev;
129
+	union {
130
+		EFI_SIMPLE_NETWORK_PROTOCOL *snp;
131
+		void *interface;
132
+	} snp;
133
+	EFI_STATUS efirc;
134
+	int rc;
135
+
136
+	/* Check that this is not a device we are providing ourselves */
137
+	if ( find_snpdev ( efidev->device ) != NULL ) {
138
+		DBGCP ( device, "SNP %p %s is provided by this binary\n",
139
+			device, efi_devpath_text ( efidev->path ) );
140
+		rc = -ENOTTY;
141
+		goto err_own;
142
+	}
143
+
144
+	/* Allocate and initialise structure */
145
+	snpdev = zalloc ( sizeof ( *snpdev ) );
146
+	if ( ! snpdev ) {
147
+		rc = -ENOMEM;
148
+		goto err_alloc;
149
+	}
150
+	snpdev->efidev = efidev;
151
+	snpdev->dev.driver_name = "SNP";
152
+	INIT_LIST_HEAD ( &snpdev->dev.children );
153
+
154
+	/* See if device is an SNP device */
155
+	if ( ( efirc = bs->OpenProtocol ( device,
156
+					  &efi_simple_network_protocol_guid,
157
+					  &snp.interface, efi_image_handle,
158
+					  device,
159
+					  ( EFI_OPEN_PROTOCOL_BY_DRIVER |
160
+					    EFI_OPEN_PROTOCOL_EXCLUSIVE )))!=0){
161
+		rc = -EEFI ( efirc );
162
+		DBGCP ( device, "SNP %p %s cannot open SNP protocol: %s\n",
163
+			device, efi_devpath_text ( efidev->path ),
164
+			strerror ( rc ) );
165
+		goto err_open_protocol;
166
+	}
167
+	snpdev->snp = snp.snp;
168
+
169
+	/* Get underlying device information */
170
+	if ( ( rc = snp_pci_info ( snpdev ) ) != 0 )
171
+		goto err_info;
172
+
173
+	/* Mark SNP device as a child of the EFI device */
174
+	snpdev->dev.parent = &efidev->dev;
175
+	list_add ( &snpdev->dev.siblings, &efidev->dev.children );
176
+
177
+	/* Create SNP network device */
178
+	if ( ( rc = snpnet_probe ( snpdev ) ) != 0 )
179
+		goto err_probe;
180
+
181
+	efidev_set_drvdata ( efidev, snpdev );
182
+	return 0;
183
+
184
+	snpnet_remove ( snpdev );
185
+ err_probe:
186
+	list_del ( &snpdev->dev.siblings );
187
+ err_info:
188
+	bs->CloseProtocol ( device, &efi_simple_network_protocol_guid,
189
+			    efi_image_handle, device );
190
+ err_open_protocol:
191
+	free ( snpdev );
192
+ err_alloc:
193
+ err_own:
194
+	return rc;
195
+}
196
+
197
+/**
198
+ * Detach driver from device
199
+ *
200
+ * @v efidev		EFI device
201
+  */
202
+static void snp_stop ( struct efi_device *efidev ) {
203
+	EFI_BOOT_SERVICES *bs = efi_systab->BootServices;
204
+	struct snp_device *snpdev = efidev_get_drvdata ( efidev );
205
+
206
+	snpnet_remove ( snpdev );
207
+	list_del ( &snpdev->dev.siblings );
208
+	bs->CloseProtocol ( efidev->device, &efi_simple_network_protocol_guid,
209
+			    efi_image_handle, efidev->device );
210
+	free ( snpdev );
211
+}
212
+
213
+/** EFI SNP driver */
214
+struct efi_driver snp_driver __efi_driver ( EFI_DRIVER_NORMAL ) = {
215
+	.name = "SNP",
216
+	.supported = snp_supported,
217
+	.start = snp_start,
218
+	.stop = snp_stop,
219
+};

+ 7
- 8
src/drivers/net/efi/snp.h Ver fichero

@@ -28,22 +28,21 @@
28 28
 FILE_LICENCE ( GPL2_OR_LATER );
29 29
 
30 30
 #include <ipxe/device.h>
31
-#include <ipxe/netdevice.h>
31
+#include <ipxe/efi/efi.h>
32 32
 #include <ipxe/efi/Protocol/SimpleNetwork.h>
33 33
 
34
-/** A network device that consumes the EFI Simple Network Protocol */
34
+/** An SNP device */
35 35
 struct snp_device {
36
-	/** Underlying simple network protocol instance */
36
+	/** EFI device */
37
+	struct efi_device *efidev;
38
+	/** Simple network protocol */
37 39
 	EFI_SIMPLE_NETWORK_PROTOCOL *snp;
38
-
39 40
 	/** Generic device */
40 41
 	struct device dev;
41
-
42 42
 	/** Network device */
43 43
 	struct net_device *netdev;
44
-
45
-	/** State to put the snp in when removing the device */
46
-	uint32 removal_state;
44
+	/** State to restore when removing the device */
45
+	UINT32 removal_state;
47 46
 };
48 47
 
49 48
 #endif /* _SNP_H */

+ 3
- 0
src/include/ipxe/device.h Ver fichero

@@ -57,6 +57,9 @@ struct device_description {
57 57
 /** TAP bus type */
58 58
 #define BUS_TYPE_TAP 6
59 59
 
60
+/** EFI bus type */
61
+#define BUS_TYPE_EFI 7
62
+
60 63
 /** A hardware device */
61 64
 struct device {
62 65
 	/** Name */

+ 44
- 5
src/include/ipxe/efi/efi_driver.h Ver fichero

@@ -8,10 +8,25 @@
8 8
 
9 9
 FILE_LICENCE ( GPL2_OR_LATER );
10 10
 
11
+#include <ipxe/device.h>
11 12
 #include <ipxe/tables.h>
12 13
 #include <ipxe/efi/efi.h>
13 14
 #include <ipxe/efi/Protocol/DevicePath.h>
14 15
 
16
+/** An EFI device */
17
+struct efi_device {
18
+	/** Generic device */
19
+	struct device dev;
20
+	/** EFI device handle */
21
+	EFI_HANDLE device;
22
+	/** Device path */
23
+	EFI_DEVICE_PATH_PROTOCOL *path;
24
+	/** Driver for this device */
25
+	struct efi_driver *driver;
26
+	/** Driver-private data */
27
+	void *priv;
28
+};
29
+
15 30
 /** An EFI driver */
16 31
 struct efi_driver {
17 32
 	/** Name */
@@ -19,23 +34,23 @@ struct efi_driver {
19 34
 	/**
20 35
 	 * Check if driver supports device
21 36
 	 *
22
-	 * @v device		Device
37
+	 * @v device		EFI device handle
23 38
 	 * @ret rc		Return status code
24 39
 	 */
25 40
 	int ( * supported ) ( EFI_HANDLE device );
26 41
 	/**
27 42
 	 * Attach driver to device
28 43
 	 *
29
-	 * @v device		Device
44
+	 * @v efidev		EFI device
30 45
 	 * @ret rc		Return status code
31 46
 	 */
32
-	int ( * start ) ( EFI_HANDLE device );
47
+	int ( * start ) ( struct efi_device *efidev );
33 48
 	/**
34 49
 	 * Detach driver from device
35 50
 	 *
36
-	 * @v device		Device
51
+	 * @v efidev		EFI device
37 52
 	 */
38
-	void ( * stop ) ( EFI_HANDLE device );
53
+	void ( * stop ) ( struct efi_device *efidev );
39 54
 };
40 55
 
41 56
 /** EFI driver table */
@@ -48,8 +63,32 @@ struct efi_driver {
48 63
 #define EFI_DRIVER_NORMAL	02	/**< Normal drivers */
49 64
 #define EFI_DRIVER_LATE		03	/**< Late drivers */
50 65
 
66
+/**
67
+ * Set EFI driver-private data
68
+ *
69
+ * @v efidev		EFI device
70
+ * @v priv		Private data
71
+ */
72
+static inline void efidev_set_drvdata ( struct efi_device *efidev,
73
+					void *priv ) {
74
+	efidev->priv = priv;
75
+}
76
+
77
+/**
78
+ * Get EFI driver-private data
79
+ *
80
+ * @v efidev		EFI device
81
+ * @ret priv		Private data
82
+ */
83
+static inline void * efidev_get_drvdata ( struct efi_device *efidev ) {
84
+	return efidev->priv;
85
+}
86
+
51 87
 extern EFI_DEVICE_PATH_PROTOCOL *
52 88
 efi_devpath_end ( EFI_DEVICE_PATH_PROTOCOL *path );
89
+extern struct efi_device * efidev_parent ( struct device *dev );
90
+extern int efidev_child_add ( struct efi_device *efidev, EFI_HANDLE device );
91
+extern void efidev_child_del ( struct efi_device *efidev, EFI_HANDLE device );
53 92
 extern int efi_driver_install ( void );
54 93
 extern void efi_driver_uninstall ( void );
55 94
 extern int efi_driver_connect_all ( void );

+ 5
- 27
src/include/ipxe/efi/efi_pci.h Ver fichero

@@ -8,40 +8,18 @@
8 8
 
9 9
 FILE_LICENCE ( GPL2_OR_LATER );
10 10
 
11
+#include <ipxe/pci.h>
11 12
 #include <ipxe/efi/efi.h>
12 13
 #include <ipxe/efi/Protocol/PciIo.h>
13
-#include <ipxe/efi/Protocol/DevicePath.h>
14 14
 
15 15
 /* PciRootBridgeIo.h uses LShiftU64(), which isn't defined anywhere else */
16 16
 static inline EFIAPI uint64_t LShiftU64 ( UINT64 value, UINTN shift ) {
17 17
 	return ( value << shift );
18 18
 }
19 19
 
20
-struct device;
21
-
22
-/** An EFI PCI device */
23
-struct efi_pci_device {
24
-	/** List of EFI PCI devices */
25
-	struct list_head list;
26
-	/** iPXE PCI device */
27
-	struct pci_device pci;
28
-	/** Underlying EFI device */
29
-	EFI_HANDLE device;
30
-	/** PCI I/O protocol */
31
-	EFI_PCI_IO_PROTOCOL *pci_io;
32
-	/** Device path */
33
-	EFI_DEVICE_PATH_PROTOCOL *path;
34
-};
35
-
36
-extern int efipci_create ( EFI_HANDLE device, UINT32 attributes,
37
-			   struct efi_pci_device **efipci );
38
-extern int efipci_enable ( struct efi_pci_device *efipci );
39
-extern struct efi_pci_device * efipci_find_efi ( EFI_HANDLE device );
40
-extern struct efi_pci_device * efipci_find ( struct device *dev );
41
-extern int efipci_child_add ( struct efi_pci_device *efipci,
42
-			      EFI_HANDLE device );
43
-extern void efipci_child_del ( struct efi_pci_device *efipci,
44
-			       EFI_HANDLE device );
45
-extern void efipci_destroy ( struct efi_pci_device *efipci );
20
+extern int efipci_open ( EFI_HANDLE device, UINT32 attributes,
21
+			 struct pci_device *pci );
22
+extern void efipci_close ( EFI_HANDLE device );
23
+extern int efipci_info ( EFI_HANDLE device, struct pci_device *pci );
46 24
 
47 25
 #endif /* _IPXE_EFI_PCI_H */

+ 3
- 2
src/include/ipxe/efi/efi_snp.h Ver fichero

@@ -24,8 +24,8 @@ struct efi_snp_device {
24 24
 	struct list_head list;
25 25
 	/** The underlying iPXE network device */
26 26
 	struct net_device *netdev;
27
-	/** The underlying EFI PCI device */
28
-	struct efi_pci_device *efipci;
27
+	/** The underlying EFI device */
28
+	struct efi_device *efidev;
29 29
 	/** EFI device handle */
30 30
 	EFI_HANDLE handle;
31 31
 	/** The SNP structure itself */
@@ -76,6 +76,7 @@ struct efi_snp_device {
76 76
 
77 77
 extern int efi_snp_hii_install ( struct efi_snp_device *snpdev );
78 78
 extern void efi_snp_hii_uninstall ( struct efi_snp_device *snpdev );
79
+extern struct efi_snp_device * find_snpdev ( EFI_HANDLE handle );
79 80
 extern struct efi_snp_device * last_opened_snpdev ( void );
80 81
 extern void efi_snp_claim ( void );
81 82
 extern void efi_snp_release ( void );

+ 1
- 0
src/include/ipxe/errfile.h Ver fichero

@@ -154,6 +154,7 @@ FILE_LICENCE ( GPL2_OR_LATER );
154 154
 #define ERRFILE_intel		     ( ERRFILE_DRIVER | 0x00650000 )
155 155
 #define ERRFILE_myson		     ( ERRFILE_DRIVER | 0x00660000 )
156 156
 #define ERRFILE_intelx		     ( ERRFILE_DRIVER | 0x00670000 )
157
+#define ERRFILE_snp		     ( ERRFILE_DRIVER | 0x00680000 )
157 158
 
158 159
 #define ERRFILE_scsi		     ( ERRFILE_DRIVER | 0x00700000 )
159 160
 #define ERRFILE_arbel		     ( ERRFILE_DRIVER | 0x00710000 )

+ 41
- 79
src/interface/efi/efi_bofm.c Ver fichero

@@ -155,38 +155,28 @@ static EFI_GUID bofm2_protocol_guid =
155 155
 /**
156 156
  * Check if device is supported
157 157
  *
158
- * @v device		EFI device
158
+ * @v device		EFI device handle
159 159
  * @ret rc		Return status code
160 160
  */
161 161
 static int efi_bofm_supported ( EFI_HANDLE device ) {
162 162
 	EFI_BOOT_SERVICES *bs = efi_systab->BootServices;
163
+	struct pci_device pci;
163 164
 	union {
164 165
 		IBM_BOFM_DRIVER_CONFIGURATION_PROTOCOL *bofm1;
165 166
 		void *interface;
166 167
 	} bofm1;
167
-	struct efi_pci_device *efipci;
168 168
 	EFI_STATUS efirc;
169 169
 	int rc;
170 170
 
171
-	/* Do nothing if we are already driving this device */
172
-	efipci = efipci_find_efi ( device );
173
-	if ( efipci ) {
174
-		DBGCP ( device, "EFIBOFM %p %s already started\n",
175
-			device, efi_devpath_text ( efipci->path ) );
176
-		rc = -EALREADY;
177
-		goto err_already_started;
178
-	}
179
-
180
-	/* Create corresponding PCI device, if any */
181
-	if ( ( rc = efipci_create ( device, EFI_OPEN_PROTOCOL_GET_PROTOCOL,
182
-				    &efipci ) ) != 0 )
183
-		goto err_create;
171
+	/* Get PCI device information */
172
+	if ( ( rc = efipci_info ( device, &pci ) ) != 0 )
173
+		return rc;
184 174
 
185 175
 	/* Look for a BOFM driver */
186
-	if ( ( rc = bofm_find_driver ( &efipci->pci ) ) != 0 ) {
176
+	if ( ( rc = bofm_find_driver ( &pci ) ) != 0 ) {
187 177
 		DBGCP ( device, "EFIBOFM %p %s has no driver\n",
188
-			device, efi_devpath_text ( efipci->path ) );
189
-		goto err_no_driver;
178
+			device, efi_handle_devpath_text ( device ) );
179
+		return rc;
190 180
 	}
191 181
 
192 182
 	/* Locate BOFM protocol */
@@ -194,8 +184,8 @@ static int efi_bofm_supported ( EFI_HANDLE device ) {
194 184
 					    &bofm1.interface ) ) != 0 ) {
195 185
 		rc = -EEFI ( efirc );
196 186
 		DBGC ( device, "EFIBOFM %p %s cannot find BOFM protocol\n",
197
-		       device, efi_devpath_text ( efipci->path ) );
198
-		goto err_not_bofm;
187
+		       device, efi_handle_devpath_text ( device ) );
188
+		return rc;
199 189
 	}
200 190
 
201 191
 	/* Register support for this device */
@@ -205,36 +195,25 @@ static int efi_bofm_supported ( EFI_HANDLE device ) {
205 195
 						      0x02 /* Version */ ))!=0){
206 196
 		rc = -EEFI ( efirc );
207 197
 		DBGC ( device, "EFIBOFM %p %s could not register support: %s\n",
208
-		       device, efi_devpath_text ( efipci->path ),
198
+		       device, efi_handle_devpath_text ( device ),
209 199
 		       strerror ( rc ) );
210
-		goto err_cannot_register;
200
+		return rc;
211 201
 	}
212 202
 
213
-	DBGC ( device, "EFIBOFM %p %s has driver \"%s\"\n", device,
214
-	       efi_devpath_text ( efipci->path ), efipci->pci.id->name );
215
-
216
-	/* Destroy temporary PCI device */
217
-	efipci_destroy ( efipci );
218
-
203
+	DBGC ( device, "EFIBOFM %p %s has driver \"%s\"\n",
204
+	       device, efi_handle_devpath_text ( device ), pci.id->name );
219 205
 	return 0;
220
-
221
- err_cannot_register:
222
- err_not_bofm:
223
- err_no_driver:
224
-	efipci_destroy ( efipci );
225
- err_create:
226
- err_already_started:
227
-	return rc;
228 206
 }
229 207
 
230 208
 /**
231 209
  * Attach driver to device
232 210
  *
233
- * @v device		EFI device
211
+ * @v efidev		EFI device
234 212
  * @ret rc		Return status code
235 213
  */
236
-static int efi_bofm_start ( EFI_HANDLE device ) {
214
+static int efi_bofm_start ( struct efi_device *efidev ) {
237 215
 	EFI_BOOT_SERVICES *bs = efi_systab->BootServices;
216
+	EFI_HANDLE device = efidev->device;
238 217
 	union {
239 218
 		IBM_BOFM_DRIVER_CONFIGURATION_PROTOCOL *bofm1;
240 219
 		void *interface;
@@ -243,42 +222,29 @@ static int efi_bofm_start ( EFI_HANDLE device ) {
243 222
 		IBM_BOFM_DRIVER_CONFIGURATION_PROTOCOL2 *bofm2;
244 223
 		void *interface;
245 224
 	} bofm2;
246
-	struct efi_pci_device *efipci;
225
+	struct pci_device pci;
247 226
 	IBM_BOFM_TABLE *bofmtab;
248 227
 	IBM_BOFM_TABLE *bofmtab2;
249 228
 	int bofmrc;
250 229
 	EFI_STATUS efirc;
251 230
 	int rc;
252 231
 
253
-	/* Do nothing if we are already driving this device */
254
-	efipci = efipci_find_efi ( device );
255
-	if ( efipci ) {
256
-		DBGCP ( device, "EFIPCI %p %s already started\n",
257
-			device, efi_devpath_text ( efipci->path ) );
258
-		rc = -EALREADY;
259
-		goto err_already_started;
260
-	}
261
-
262
-	/* Create corresponding PCI device */
263
-	if ( ( rc = efipci_create ( device, EFI_OPEN_PROTOCOL_GET_PROTOCOL,
264
-				    &efipci ) ) != 0 )
265
-		goto err_create;
266
-
267
-	/* Enable PCI device */
268
-	if ( ( rc = efipci_enable ( efipci ) ) != 0 )
269
-		goto err_enable;
232
+	/* Open PCI device, if possible */
233
+	if ( ( rc = efipci_open ( device, EFI_OPEN_PROTOCOL_GET_PROTOCOL,
234
+				  &pci ) ) != 0 )
235
+		goto err_open;
270 236
 
271 237
 	/* Locate BOFM protocol */
272 238
 	if ( ( efirc = bs->LocateProtocol ( &bofm1_protocol_guid, NULL,
273 239
 					    &bofm1.interface ) ) != 0 ) {
274 240
 		rc = -EEFI ( efirc );
275 241
 		DBGC ( device, "EFIBOFM %p %s cannot find BOFM protocol\n",
276
-		       device, efi_devpath_text ( efipci->path ) );
242
+		       device, efi_devpath_text ( efidev->path ) );
277 243
 		goto err_locate_bofm;
278 244
 	}
279 245
 	bofmtab = &bofm1.bofm1->BofmTable;
280 246
 	DBGC ( device, "EFIBOFM %p %s found version 1 BOFM table at %p+%04x\n",
281
-	       device, efi_devpath_text ( efipci->path ), bofmtab,
247
+	       device, efi_devpath_text ( efidev->path ), bofmtab,
282 248
 	       bofmtab->Parameters.Length );
283 249
 
284 250
 	/* Locate BOFM2 protocol, if available */
@@ -286,36 +252,35 @@ static int efi_bofm_start ( EFI_HANDLE device ) {
286 252
 					    &bofm2.interface ) ) == 0 ) {
287 253
 		bofmtab2 = &bofm2.bofm2->BofmTable;
288 254
 		DBGC ( device, "EFIBOFM %p %s found version 2 BOFM table at "
289
-		       "%p+%04x\n", device, efi_devpath_text ( efipci->path ),
255
+		       "%p+%04x\n", device, efi_devpath_text ( efidev->path ),
290 256
 		       bofmtab2, bofmtab2->Parameters.Length );
291 257
 		assert ( bofm2.bofm2->RegisterSupport ==
292 258
 			 bofm1.bofm1->RegisterSupport );
293 259
 	} else {
294 260
 		DBGC ( device, "EFIBOFM %p %s cannot find BOFM2 protocol\n",
295
-		       device, efi_devpath_text ( efipci->path ) );
261
+		       device, efi_devpath_text ( efidev->path ) );
296 262
 		/* Not a fatal error; may be a BOFM1-only system */
297 263
 		bofmtab2 = NULL;
298 264
 	}
299 265
 
300 266
 	/* Process BOFM table */
301 267
 	DBGC2 ( device, "EFIBOFM %p %s version 1 before processing:\n",
302
-		device, efi_devpath_text ( efipci->path ) );
268
+		device, efi_devpath_text ( efidev->path ) );
303 269
 	DBGC2_HD ( device, bofmtab, bofmtab->Parameters.Length );
304 270
 	if ( bofmtab2 ) {
305 271
 		DBGC2 ( device, "EFIBOFM %p %s version 2 before processing:\n",
306
-			device, efi_devpath_text ( efipci->path ) );
272
+			device, efi_devpath_text ( efidev->path ) );
307 273
 		DBGC2_HD ( device, bofmtab2, bofmtab2->Parameters.Length );
308 274
 	}
309
-	bofmrc = bofm ( virt_to_user ( bofmtab2 ? bofmtab2 : bofmtab ),
310
-			&efipci->pci );
275
+	bofmrc = bofm ( virt_to_user ( bofmtab2 ? bofmtab2 : bofmtab ), &pci );
311 276
 	DBGC ( device, "EFIBOFM %p %s status %08x\n",
312
-	       device, efi_devpath_text ( efipci->path ), bofmrc );
277
+	       device, efi_devpath_text ( efidev->path ), bofmrc );
313 278
 	DBGC2 ( device, "EFIBOFM %p %s version 1 after processing:\n",
314
-		device, efi_devpath_text ( efipci->path ) );
279
+		device, efi_devpath_text ( efidev->path ) );
315 280
 	DBGC2_HD ( device, bofmtab, bofmtab->Parameters.Length );
316 281
 	if ( bofmtab2 ) {
317 282
 		DBGC2 ( device, "EFIBOFM %p %s version 2 after processing:\n",
318
-			device, efi_devpath_text ( efipci->path ) );
283
+			device, efi_devpath_text ( efidev->path ) );
319 284
 		DBGC2_HD ( device, bofmtab2, bofmtab2->Parameters.Length );
320 285
 	}
321 286
 
@@ -326,7 +291,7 @@ static int efi_bofm_start ( EFI_HANDLE device ) {
326 291
 			rc = -EEFI ( efirc );
327 292
 			DBGC ( device, "EFIBOFM %p %s could not set BOFM2 "
328 293
 			       "status: %s\n",
329
-			       device, efi_devpath_text ( efipci->path ),
294
+			       device, efi_devpath_text ( efidev->path ),
330 295
 			       strerror ( rc ) );
331 296
 			goto err_set_status;
332 297
 		}
@@ -336,24 +301,19 @@ static int efi_bofm_start ( EFI_HANDLE device ) {
336 301
 			rc = -EEFI ( efirc );
337 302
 			DBGC ( device, "EFIBOFM %p %s could not set BOFM "
338 303
 			       "status: %s\n",
339
-			       device, efi_devpath_text ( efipci->path ),
304
+			       device, efi_devpath_text ( efidev->path ),
340 305
 			       strerror ( rc ) );
341 306
 			goto err_set_status;
342 307
 		}
343 308
 	}
344 309
 
345
-	/* Destroy the PCI device anyway; we have no further use for it */
346
-	efipci_destroy ( efipci );
347
-
348 310
 	/* BOFM (ab)uses the "start" method to mean "process and exit" */
349
-	return -EAGAIN;
311
+	rc = -EAGAIN;
350 312
 
351 313
  err_set_status:
352 314
  err_locate_bofm:
353
- err_enable:
354
-	efipci_destroy ( efipci );
355
- err_create:
356
- err_already_started:
315
+	efipci_close ( device );
316
+ err_open:
357 317
 	return rc;
358 318
 }
359 319
 
@@ -362,8 +322,10 @@ static int efi_bofm_start ( EFI_HANDLE device ) {
362 322
  *
363 323
  * @v device		EFI device
364 324
  */
365
-static void efi_bofm_stop ( EFI_HANDLE device __unused ) {
366
-	/* Nothing to do */
325
+static void efi_bofm_stop ( struct efi_device *efidev __unused ) {
326
+
327
+	/* Should never happen */
328
+	assert ( 0 );
367 329
 }
368 330
 
369 331
 /** EFI BOFM driver */

+ 181
- 9
src/interface/efi/efi_driver.c Ver fichero

@@ -20,6 +20,7 @@
20 20
 FILE_LICENCE ( GPL2_OR_LATER );
21 21
 
22 22
 #include <stddef.h>
23
+#include <stdlib.h>
23 24
 #include <stdio.h>
24 25
 #include <string.h>
25 26
 #include <errno.h>
@@ -27,6 +28,7 @@ FILE_LICENCE ( GPL2_OR_LATER );
27 28
 #include <ipxe/efi/efi.h>
28 29
 #include <ipxe/efi/Protocol/DriverBinding.h>
29 30
 #include <ipxe/efi/Protocol/ComponentName2.h>
31
+#include <ipxe/efi/Protocol/DevicePath.h>
30 32
 #include <ipxe/efi/efi_strings.h>
31 33
 #include <ipxe/efi/efi_driver.h>
32 34
 
@@ -46,6 +48,13 @@ static EFI_GUID efi_driver_binding_protocol_guid
46 48
 static EFI_GUID efi_component_name2_protocol_guid
47 49
 	= EFI_COMPONENT_NAME2_PROTOCOL_GUID;
48 50
 
51
+/** EFI device path protocol GUID */
52
+static EFI_GUID efi_device_path_protocol_guid
53
+	= EFI_DEVICE_PATH_PROTOCOL_GUID;
54
+
55
+/** List of controlled EFI devices */
56
+static LIST_HEAD ( efi_devices );
57
+
49 58
 /**
50 59
  * Find end of device path
51 60
  *
@@ -64,6 +73,99 @@ EFI_DEVICE_PATH_PROTOCOL * efi_devpath_end ( EFI_DEVICE_PATH_PROTOCOL *path ) {
64 73
 	return path;
65 74
 }
66 75
 
76
+/**
77
+ * Find EFI device
78
+ *
79
+ * @v device		EFI device handle
80
+ * @ret efidev		EFI device, or NULL if not found
81
+ */
82
+static struct efi_device * efidev_find ( EFI_HANDLE device ) {
83
+	struct efi_device *efidev;
84
+
85
+	/* Look for an existing EFI device */
86
+	list_for_each_entry ( efidev, &efi_devices, dev.siblings ) {
87
+		if ( efidev->device == device )
88
+			return efidev;
89
+	}
90
+
91
+	return NULL;
92
+}
93
+
94
+/**
95
+ * Get parent EFI device
96
+ *
97
+ * @v dev		Generic device
98
+ * @ret efidev		Parent EFI device, or NULL
99
+ */
100
+struct efi_device * efidev_parent ( struct device *dev ) {
101
+	struct device *parent = dev->parent;
102
+	struct efi_device *efidev;
103
+
104
+	/* Check that parent exists and is an EFI device */
105
+	if ( ! parent )
106
+		return NULL;
107
+	if ( parent->desc.bus_type != BUS_TYPE_EFI )
108
+		return NULL;
109
+
110
+	/* Get containing EFI device */
111
+	efidev = container_of ( parent, struct efi_device, dev );
112
+	return efidev;
113
+}
114
+
115
+/**
116
+ * Add EFI device as child of EFI device
117
+ *
118
+ * @v efidev		EFI device
119
+ * @v device		EFI child device handle
120
+ * @ret efirc		EFI status code
121
+ */
122
+int efidev_child_add ( struct efi_device *efidev, EFI_HANDLE device ) {
123
+	EFI_BOOT_SERVICES *bs = efi_systab->BootServices;
124
+	void *devpath;
125
+	EFI_STATUS efirc;
126
+	int rc;
127
+
128
+	/* Re-open the device path protocol */
129
+	if ( ( efirc = bs->OpenProtocol ( efidev->device,
130
+					  &efi_device_path_protocol_guid,
131
+					  &devpath,
132
+					  efi_image_handle, device,
133
+					  EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER
134
+					  ) ) != 0 ) {
135
+		rc = -EEFI ( efirc );
136
+		DBGC ( efidev->device, "EFIDRV %p %s could not add child",
137
+		       efidev->device, efi_devpath_text ( efidev->path ) );
138
+		DBGC ( efidev->device, " %p %s: %s\n", device,
139
+		       efi_handle_devpath_text ( device ), strerror ( rc ) );
140
+		return rc;
141
+	}
142
+
143
+	DBGC2 ( efidev->device, "EFIDRV %p %s added child",
144
+		efidev->device, efi_devpath_text ( efidev->path ) );
145
+	DBGC2 ( efidev->device, " %p %s\n",
146
+		device, efi_handle_devpath_text ( device ) );
147
+	return 0;
148
+}
149
+
150
+/**
151
+ * Remove EFI device as child of EFI device
152
+ *
153
+ * @v efidev		EFI device
154
+ * @v device		EFI child device handle
155
+ * @ret efirc		EFI status code
156
+ */
157
+void efidev_child_del ( struct efi_device *efidev, EFI_HANDLE device ) {
158
+	EFI_BOOT_SERVICES *bs = efi_systab->BootServices;
159
+
160
+	bs->CloseProtocol ( efidev->device,
161
+			    &efi_device_path_protocol_guid,
162
+			    efi_image_handle, device );
163
+	DBGC2 ( efidev->device, "EFIDRV %p %s removed child",
164
+		efidev->device, efi_devpath_text ( efidev->path ) );
165
+	DBGC2 ( efidev->device, " %p %s\n",
166
+		device, efi_handle_devpath_text ( device ) );
167
+}
168
+
67 169
 /**
68 170
  * Check to see if driver supports a device
69 171
  *
@@ -84,6 +186,13 @@ efi_driver_supported ( EFI_DRIVER_BINDING_PROTOCOL *driver __unused,
84 186
 		DBGCP ( device, " (child %s)", efi_devpath_text ( child ) );
85 187
 	DBGCP ( device, "\n" );
86 188
 
189
+	/* Do nothing if we are already driving this device */
190
+	if ( efidev_find ( device ) != NULL ) {
191
+		DBGCP ( device, "EFIDRV %p %s is already started\n",
192
+			device, efi_handle_devpath_text ( device ) );
193
+		return EFI_ALREADY_STARTED;
194
+	}
195
+
87 196
 	/* Look for a driver claiming to support this device */
88 197
 	for_each_table_entry ( efidrv, EFI_DRIVERS ) {
89 198
 		if ( ( rc = efidrv->supported ( device ) ) == 0 ) {
@@ -110,7 +219,14 @@ efi_driver_supported ( EFI_DRIVER_BINDING_PROTOCOL *driver __unused,
110 219
 static EFI_STATUS EFIAPI
111 220
 efi_driver_start ( EFI_DRIVER_BINDING_PROTOCOL *driver __unused,
112 221
 		   EFI_HANDLE device, EFI_DEVICE_PATH_PROTOCOL *child ) {
222
+	EFI_BOOT_SERVICES *bs = efi_systab->BootServices;
113 223
 	struct efi_driver *efidrv;
224
+	struct efi_device *efidev;
225
+	union {
226
+		EFI_DEVICE_PATH_PROTOCOL *devpath;
227
+		void *interface;
228
+	} devpath;
229
+	EFI_STATUS efirc;
114 230
 	int rc;
115 231
 
116 232
 	DBGC ( device, "EFIDRV %p %s DRIVER_START",
@@ -119,20 +235,61 @@ efi_driver_start ( EFI_DRIVER_BINDING_PROTOCOL *driver __unused,
119 235
 		DBGC ( device, " (child %s)", efi_devpath_text ( child ) );
120 236
 	DBGC ( device, "\n" );
121 237
 
238
+	/* Do nothing if we are already driving this device */
239
+	efidev = efidev_find ( device );
240
+	if ( efidev ) {
241
+		DBGCP ( device, "EFIDRV %p %s is already started\n",
242
+			device, efi_devpath_text ( efidev->path ) );
243
+		efirc = EFI_ALREADY_STARTED;
244
+		goto err_already_started;
245
+	}
246
+
247
+	/* Allocate and initialise structure */
248
+	efidev = zalloc ( sizeof ( *efidev ) );
249
+	if ( ! efidev ) {
250
+		efirc = EFI_OUT_OF_RESOURCES;
251
+		goto err_alloc;
252
+	}
253
+	efidev->device = device;
254
+	efidev->dev.desc.bus_type = BUS_TYPE_EFI;
255
+	INIT_LIST_HEAD ( &efidev->dev.children );
256
+	list_add ( &efidev->dev.siblings, &efi_devices );
257
+
258
+	/* Open device path protocol */
259
+	if ( ( efirc = bs->OpenProtocol ( device,
260
+					  &efi_device_path_protocol_guid,
261
+					  &devpath.interface,
262
+					  efi_image_handle, device,
263
+					  EFI_OPEN_PROTOCOL_BY_DRIVER ) ) != 0){
264
+		DBGCP ( device, "EFIDRV %p %s has no device path\n",
265
+			device, efi_handle_devpath_text ( device ) );
266
+		goto err_no_device_path;
267
+	}
268
+	efidev->path = devpath.devpath;
269
+
122 270
 	/* Try to start this device */
123 271
 	for_each_table_entry ( efidrv, EFI_DRIVERS ) {
124
-		if ( ( rc = efidrv->start ( device ) ) == 0 ) {
272
+		if ( ( rc = efidrv->start ( efidev ) ) == 0 ) {
273
+			efidev->driver = efidrv;
125 274
 			DBGC ( device, "EFIDRV %p %s using driver \"%s\"\n",
126
-			       device, efi_handle_devpath_text ( device ),
127
-			       efidrv->name );
275
+			       device, efi_devpath_text ( efidev->path ),
276
+			       efidev->driver->name );
128 277
 			return 0;
129 278
 		}
130 279
 		DBGC ( device, "EFIDRV %p %s could not start driver \"%s\": "
131
-		       "%s\n", device, efi_handle_devpath_text ( device ),
280
+		       "%s\n", device, efi_devpath_text ( efidev->path ),
132 281
 		       efidrv->name, strerror ( rc ) );
133 282
 	}
134
-
135
-	return EFI_UNSUPPORTED;
283
+	efirc = EFI_UNSUPPORTED;
284
+
285
+	bs->CloseProtocol ( device, &efi_device_path_protocol_guid,
286
+			    efi_image_handle, device );
287
+ err_no_device_path:
288
+	list_del ( &efidev->dev.siblings );
289
+	free ( efidev );
290
+ err_alloc:
291
+ err_already_started:
292
+	return efirc;
136 293
 }
137 294
 
138 295
 /**
@@ -149,7 +306,9 @@ static EFI_STATUS EFIAPI
149 306
 efi_driver_stop ( EFI_DRIVER_BINDING_PROTOCOL *driver __unused,
150 307
 		  EFI_HANDLE device, UINTN num_children,
151 308
 		  EFI_HANDLE *children ) {
309
+	EFI_BOOT_SERVICES *bs = efi_systab->BootServices;
152 310
 	struct efi_driver *efidrv;
311
+	struct efi_device *efidev;
153 312
 	UINTN i;
154 313
 
155 314
 	DBGC ( device, "EFIDRV %p %s DRIVER_STOP",
@@ -160,9 +319,22 @@ efi_driver_stop ( EFI_DRIVER_BINDING_PROTOCOL *driver __unused,
160 319
 	}
161 320
 	DBGC ( device, "\n" );
162 321
 
163
-	/* Try to stop this device */
164
-	for_each_table_entry ( efidrv, EFI_DRIVERS )
165
-		efidrv->stop ( device );
322
+	/* Do nothing unless we are driving this device */
323
+	efidev = efidev_find ( device );
324
+	if ( ! efidev ) {
325
+		DBGCP ( device, "EFIDRV %p %s is not started\n",
326
+			device, efi_devpath_text ( efidev->path ) );
327
+		return 0;
328
+	}
329
+
330
+	/* Stop this device */
331
+	efidrv = efidev->driver;
332
+	assert ( efidrv != NULL );
333
+	efidrv->stop ( efidev );
334
+	bs->CloseProtocol ( efidev->device, &efi_device_path_protocol_guid,
335
+			    efi_image_handle, efidev->device );
336
+	list_del ( &efidev->dev.siblings );
337
+	free ( efidev );
166 338
 
167 339
 	return 0;
168 340
 }

+ 99
- 242
src/interface/efi/efi_pci.c Ver fichero

@@ -37,7 +37,7 @@ FILE_LICENCE ( GPL2_OR_LATER );
37 37
 /* Disambiguate the various error causes */
38 38
 #define EINFO_EEFI_PCI							\
39 39
 	__einfo_uniqify ( EINFO_EPLATFORM, 0x01,			\
40
-			  "Could not open PCI I/O protocols" )
40
+			  "Could not open PCI I/O protocol" )
41 41
 #define EINFO_EEFI_PCI_NOT_PCI						\
42 42
 	__einfo_platformify ( EINFO_EEFI_PCI, EFI_UNSUPPORTED,		\
43 43
 			      "Not a PCI device" )
@@ -124,49 +124,28 @@ PROVIDE_PCIAPI_INLINE ( efi, pci_write_config_dword );
124 124
 static EFI_GUID efi_pci_io_protocol_guid
125 125
 	= EFI_PCI_IO_PROTOCOL_GUID;
126 126
 
127
-/** EFI device path protocol GUID */
128
-static EFI_GUID efi_device_path_protocol_guid
129
-	= EFI_DEVICE_PATH_PROTOCOL_GUID;
130
-
131
-/** EFI PCI devices */
132
-static LIST_HEAD ( efi_pci_devices );
133
-
134 127
 /**
135
- * Create EFI PCI device
128
+ * Open EFI PCI device
136 129
  *
137
- * @v device		EFI device
130
+ * @v device		EFI device handle
138 131
  * @v attributes	Protocol opening attributes
139
- * @v efipci		EFI PCI device to fill in
132
+ * @v pci		PCI device to fill in
140 133
  * @ret rc		Return status code
141 134
  */
142
-int efipci_create ( EFI_HANDLE device, UINT32 attributes,
143
-		    struct efi_pci_device **efipci ) {
135
+int efipci_open ( EFI_HANDLE device, UINT32 attributes,
136
+		  struct pci_device *pci ) {
144 137
 	EFI_BOOT_SERVICES *bs = efi_systab->BootServices;
145 138
 	union {
146 139
 		EFI_PCI_IO_PROTOCOL *pci_io;
147 140
 		void *interface;
148 141
 	} pci_io;
149
-	union {
150
-		EFI_DEVICE_PATH_PROTOCOL *path;
151
-		void *interface;
152
-	} path;
153 142
 	UINTN pci_segment, pci_bus, pci_dev, pci_fn;
154 143
 	EFI_STATUS efirc;
155 144
 	int rc;
156 145
 
157
-	/* Allocate PCI device */
158
-	*efipci = zalloc ( sizeof ( **efipci ) );
159
-	if ( ! *efipci ) {
160
-		rc = -ENOMEM;
161
-		goto err_zalloc;
162
-	}
163
-	(*efipci)->device = device;
164
-
165 146
 	/* See if device is a PCI device */
166
-	if ( ( efirc = bs->OpenProtocol ( device,
167
-					  &efi_pci_io_protocol_guid,
168
-					  &pci_io.interface,
169
-					  efi_image_handle,
147
+	if ( ( efirc = bs->OpenProtocol ( device, &efi_pci_io_protocol_guid,
148
+					  &pci_io.interface, efi_image_handle,
170 149
 					  device, attributes ) ) != 0 ) {
171 150
 		rc = -EEFI_PCI ( efirc );
172 151
 		DBGCP ( device, "EFIPCI %p %s cannot open PCI protocols: %s\n",
@@ -174,16 +153,14 @@ int efipci_create ( EFI_HANDLE device, UINT32 attributes,
174 153
 			strerror ( rc ) );
175 154
 		goto err_open_protocol;
176 155
 	}
177
-	(*efipci)->pci_io = pci_io.pci_io;
178 156
 
179 157
 	/* Get PCI bus:dev.fn address */
180
-	if ( ( efirc = pci_io.pci_io->GetLocation ( pci_io.pci_io,
181
-						    &pci_segment,
158
+	if ( ( efirc = pci_io.pci_io->GetLocation ( pci_io.pci_io, &pci_segment,
182 159
 						    &pci_bus, &pci_dev,
183 160
 						    &pci_fn ) ) != 0 ) {
184 161
 		rc = -EEFI ( efirc );
185
-		DBGC ( device, "EFIPCI %p %s could not get PCI location: "
186
-		       "%s\n", device, efi_handle_devpath_text ( device ),
162
+		DBGC ( device, "EFIPCI %p %s could not get PCI location: %s\n",
163
+		       device, efi_handle_devpath_text ( device ),
187 164
 		       strerror ( rc ) );
188 165
 		goto err_get_location;
189 166
 	}
@@ -192,172 +169,72 @@ int efipci_create ( EFI_HANDLE device, UINT32 attributes,
192 169
 		( ( unsigned long ) pci_segment ), ( ( unsigned long ) pci_bus),
193 170
 		( ( unsigned long ) pci_dev ), ( ( unsigned long ) pci_fn ) );
194 171
 
172
+	/* Try to enable I/O cycles, memory cycles, and bus mastering.
173
+	 * Some platforms will 'helpfully' report errors if these bits
174
+	 * can't be enabled (for example, if the card doesn't actually
175
+	 * support I/O cycles).  Work around any such platforms by
176
+	 * enabling bits individually and simply ignoring any errors.
177
+	 */
178
+	pci_io.pci_io->Attributes ( pci_io.pci_io,
179
+				    EfiPciIoAttributeOperationEnable,
180
+				    EFI_PCI_IO_ATTRIBUTE_IO, NULL );
181
+	pci_io.pci_io->Attributes ( pci_io.pci_io,
182
+				    EfiPciIoAttributeOperationEnable,
183
+				    EFI_PCI_IO_ATTRIBUTE_MEMORY, NULL );
184
+	pci_io.pci_io->Attributes ( pci_io.pci_io,
185
+				    EfiPciIoAttributeOperationEnable,
186
+				    EFI_PCI_IO_ATTRIBUTE_BUS_MASTER, NULL );
187
+
195 188
 	/* Populate PCI device */
196
-	pci_init ( &(*efipci)->pci, PCI_BUSDEVFN ( pci_bus, pci_dev, pci_fn ) );
197
-	if ( ( rc = pci_read_config ( &(*efipci)->pci ) ) != 0 ) {
189
+	pci_init ( pci, PCI_BUSDEVFN ( pci_bus, pci_dev, pci_fn ) );
190
+	if ( ( rc = pci_read_config ( pci ) ) != 0 ) {
198 191
 		DBGC ( device, "EFIPCI %p %s cannot read PCI configuration: "
199 192
 		       "%s\n", device, efi_handle_devpath_text ( device ),
200 193
 		       strerror ( rc ) );
201 194
 		goto err_pci_read_config;
202 195
 	}
203 196
 
204
-	/* Retrieve device path */
205
-	if ( ( efirc = bs->OpenProtocol ( device,
206
-					  &efi_device_path_protocol_guid,
207
-					  &path.interface, efi_image_handle,
208
-					  device, attributes ) ) != 0 ) {
209
-		rc = -EEFI ( efirc );
210
-		DBGC ( device, "EFIPCI %p %s has no device path\n",
211
-		       device, efi_handle_devpath_text ( device ) );
212
-		goto err_no_device_path;
213
-	}
214
-	(*efipci)->path = path.path;
215
-
216
-	/* Add to list of PCI devices */
217
-	list_add ( &(*efipci)->list, &efi_pci_devices );
218
-
219 197
 	return 0;
220 198
 
221
-	bs->CloseProtocol ( device, &efi_device_path_protocol_guid,
222
-			    efi_image_handle, device );
223
- err_no_device_path:
224 199
  err_pci_read_config:
225 200
  err_get_location:
226 201
 	bs->CloseProtocol ( device, &efi_pci_io_protocol_guid,
227 202
 			    efi_image_handle, device );
228 203
  err_open_protocol:
229
-	free ( *efipci );
230
- err_zalloc:
231 204
 	return rc;
232 205
 }
233 206
 
234 207
 /**
235
- * Enable EFI PCI device
236
- *
237
- * @v efipci		EFI PCI device
238
- * @ret rc		Return status code
239
- */
240
-int efipci_enable ( struct efi_pci_device *efipci ) {
241
-	EFI_PCI_IO_PROTOCOL *pci_io = efipci->pci_io;
242
-
243
-	/* Try to enable I/O cycles, memory cycles, and bus mastering.
244
-	 * Some platforms will 'helpfully' report errors if these bits
245
-	 * can't be enabled (for example, if the card doesn't actually
246
-	 * support I/O cycles).  Work around any such platforms by
247
-	 * enabling bits individually and simply ignoring any errors.
248
-	 */
249
-	pci_io->Attributes ( pci_io, EfiPciIoAttributeOperationEnable,
250
-			     EFI_PCI_IO_ATTRIBUTE_IO, NULL );
251
-	pci_io->Attributes ( pci_io, EfiPciIoAttributeOperationEnable,
252
-			     EFI_PCI_IO_ATTRIBUTE_MEMORY, NULL );
253
-	pci_io->Attributes ( pci_io, EfiPciIoAttributeOperationEnable,
254
-			     EFI_PCI_IO_ATTRIBUTE_BUS_MASTER, NULL );
255
-
256
-	return 0;
257
-}
258
-
259
-/**
260
- * Find EFI PCI device by EFI device
261
- *
262
- * @v device		EFI device
263
- * @ret efipci		EFI PCI device, or NULL
264
- */
265
-struct efi_pci_device * efipci_find_efi ( EFI_HANDLE device ) {
266
-	struct efi_pci_device *efipci;
267
-
268
-	list_for_each_entry ( efipci, &efi_pci_devices, list ) {
269
-		if ( efipci->device == device )
270
-			return efipci;
271
-	}
272
-	return NULL;
273
-}
274
-
275
-/**
276
- * Find EFI PCI device by iPXE device
208
+ * Close EFI PCI device
277 209
  *
278
- * @v dev		Device
279
- * @ret efipci		EFI PCI device, or NULL
210
+ * @v device		EFI device handle
280 211
  */
281
-struct efi_pci_device * efipci_find ( struct device *dev ) {
282
-	struct efi_pci_device *efipci;
212
+void efipci_close ( EFI_HANDLE device ) {
213
+	EFI_BOOT_SERVICES *bs = efi_systab->BootServices;
283 214
 
284
-	list_for_each_entry ( efipci, &efi_pci_devices, list ) {
285
-		if ( &efipci->pci.dev == dev )
286
-			return efipci;
287
-	}
288
-	return NULL;
215
+	bs->CloseProtocol ( device, &efi_pci_io_protocol_guid,
216
+			    efi_image_handle, device );
289 217
 }
290 218
 
291 219
 /**
292
- * Add EFI device as child of EFI PCI device
220
+ * Get EFI PCI device information
293 221
  *
294
- * @v efipci		EFI PCI device
295
- * @v device		EFI child device
296
- * @ret efirc		EFI status code
222
+ * @v device		EFI device handle
223
+ * @v pci		PCI device to fill in
224
+ * @ret rc		Return status code
297 225
  */
298
-int efipci_child_add ( struct efi_pci_device *efipci, EFI_HANDLE device ) {
299
-	EFI_BOOT_SERVICES *bs = efi_systab->BootServices;
300
-	union {
301
-		EFI_PCI_IO_PROTOCOL *pci_io;
302
-		void *interface;
303
-	} pci_io;
304
-	EFI_STATUS efirc;
226
+int efipci_info ( EFI_HANDLE device, struct pci_device *pci ) {
305 227
 	int rc;
306 228
 
307
-	/* Re-open the PCI_IO_PROTOCOL */
308
-	if ( ( efirc = bs->OpenProtocol ( efipci->device,
309
-					  &efi_pci_io_protocol_guid,
310
-					  &pci_io.interface,
311
-					  efi_image_handle, device,
312
-					  EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER
313
-					  ) ) != 0 ) {
314
-		rc = -EEFI ( efirc );
315
-		DBGC ( efipci->device, "EFIPCI %p %s could not add child",
316
-		       efipci->device, efi_devpath_text ( efipci->path ) );
317
-		DBGC ( efipci->device, " %p %s: %s\n", device,
318
-		       efi_handle_devpath_text ( device ), strerror ( rc ) );
229
+	/* Open PCI device, if possible */
230
+	if ( ( rc = efipci_open ( device, EFI_OPEN_PROTOCOL_GET_PROTOCOL,
231
+				  pci ) ) != 0 )
319 232
 		return rc;
320
-	}
321
-
322
-	DBGC2 ( efipci->device, "EFIPCI %p %s added child",
323
-		efipci->device, efi_devpath_text ( efipci->path ) );
324
-	DBGC2 ( efipci->device, " %p %s\n",
325
-		device, efi_handle_devpath_text ( device ) );
326
-	return 0;
327
-}
328
-
329
-/**
330
- * Remove EFI device as child of PCI device
331
- *
332
- * @v efipci		EFI PCI device
333
- * @v device		EFI child device
334
- * @ret efirc		EFI status code
335
- */
336
-void efipci_child_del ( struct efi_pci_device *efipci, EFI_HANDLE device ) {
337
-	EFI_BOOT_SERVICES *bs = efi_systab->BootServices;
338
-
339
-	bs->CloseProtocol ( efipci->device, &efi_pci_io_protocol_guid,
340
-			    efi_image_handle, device );
341
-	DBGC2 ( efipci->device, "EFIPCI %p %s removed child",
342
-		efipci->device, efi_devpath_text ( efipci->path ) );
343
-	DBGC2 ( efipci->device, " %p %s\n",
344
-		device, efi_handle_devpath_text ( device ) );
345
-}
346 233
 
347
-/**
348
- * Destroy EFI PCI device
349
- *
350
- * @v efipci		EFI PCI device
351
- */
352
-void efipci_destroy ( struct efi_pci_device *efipci ) {
353
-	EFI_BOOT_SERVICES *bs = efi_systab->BootServices;
234
+	/* Close PCI device */
235
+	efipci_close ( device );
354 236
 
355
-	list_del ( &efipci->list );
356
-	bs->CloseProtocol ( efipci->device, &efi_device_path_protocol_guid,
357
-			    efi_image_handle, efipci->device );
358
-	bs->CloseProtocol ( efipci->device, &efi_pci_io_protocol_guid,
359
-			    efi_image_handle, efipci->device );
360
-	free ( efipci );
237
+	return 0;
361 238
 }
362 239
 
363 240
 /******************************************************************************
@@ -370,125 +247,105 @@ void efipci_destroy ( struct efi_pci_device *efipci ) {
370 247
 /**
371 248
  * Check to see if driver supports a device
372 249
  *
373
- * @v device		EFI device
250
+ * @v device		EFI device handle
374 251
  * @ret rc		Return status code
375 252
  */
376 253
 static int efipci_supported ( EFI_HANDLE device ) {
377
-	struct efi_pci_device *efipci;
254
+	struct pci_device pci;
378 255
 	int rc;
379 256
 
380
-	/* Do nothing if we are already driving this device */
381
-	efipci = efipci_find_efi ( device );
382
-	if ( efipci ) {
383
-		DBGCP ( device, "EFIPCI %p %s already started\n",
384
-			device, efi_devpath_text ( efipci->path ) );
385
-		rc = -EALREADY;
386
-		goto err_already_started;
387
-	}
388
-
389
-	/* Create temporary corresponding PCI device, if any */
390
-	if ( ( rc = efipci_create ( device, EFI_OPEN_PROTOCOL_GET_PROTOCOL,
391
-				    &efipci ) ) != 0 )
392
-		goto err_create;
257
+	/* Get PCI device information */
258
+	if ( ( rc = efipci_info ( device, &pci ) ) != 0 )
259
+		return rc;
393 260
 
394 261
 	/* Look for a driver */
395
-	if ( ( rc = pci_find_driver ( &efipci->pci ) ) != 0 ) {
262
+	if ( ( rc = pci_find_driver ( &pci ) ) != 0 ) {
396 263
 		DBGCP ( device, "EFIPCI %p %s has no driver\n",
397
-			device, efi_devpath_text ( efipci->path ) );
398
-		goto err_no_driver;
264
+			device, efi_handle_devpath_text ( device ) );
265
+		return rc;
399 266
 	}
400
-
401
-	DBGC ( device, "EFIPCI %p %s has driver \"%s\"\n", device,
402
-	       efi_devpath_text ( efipci->path ), efipci->pci.id->name );
403
-
404
-	/* Destroy temporary PCI device */
405
-	efipci_destroy ( efipci );
267
+	DBGC ( device, "EFIPCI %p %s has driver \"%s\"\n",
268
+	       device, efi_handle_devpath_text ( device ), pci.id->name );
406 269
 
407 270
 	return 0;
408
-
409
- err_no_driver:
410
-	efipci_destroy ( efipci );
411
- err_create:
412
- err_already_started:
413
-	return rc;
414 271
 }
415 272
 
416 273
 /**
417 274
  * Attach driver to device
418 275
  *
419
- * @v device		EFI device
276
+ * @v efidev		EFI device
420 277
  * @ret rc		Return status code
421 278
  */
422
-static int efipci_start ( EFI_HANDLE device ) {
423
-	struct efi_pci_device *efipci;
279
+static int efipci_start ( struct efi_device *efidev ) {
280
+	EFI_HANDLE device = efidev->device;
281
+	struct pci_device *pci;
424 282
 	int rc;
425 283
 
426
-	/* Do nothing if we are already driving this device */
427
-	efipci = efipci_find_efi ( device );
428
-	if ( efipci ) {
429
-		DBGCP ( device, "EFIPCI %p %s already started\n",
430
-			device, efi_devpath_text ( efipci->path ) );
431
-		rc = -EALREADY;
432
-		goto err_already_started;
284
+	/* Allocate PCI device */
285
+	pci = zalloc ( sizeof ( *pci ) );
286
+	if ( ! pci ) {
287
+		rc = -ENOMEM;
288
+		goto err_alloc;
433 289
 	}
434 290
 
435
-	/* Create corresponding PCI device */
436
-	if ( ( rc = efipci_create ( device, ( EFI_OPEN_PROTOCOL_BY_DRIVER |
437
-					      EFI_OPEN_PROTOCOL_EXCLUSIVE ),
438
-				    &efipci ) ) != 0 )
439
-		goto err_create;
291
+	/* Open PCI device */
292
+	if ( ( rc = efipci_open ( device, ( EFI_OPEN_PROTOCOL_BY_DRIVER |
293
+					    EFI_OPEN_PROTOCOL_EXCLUSIVE ),
294
+				  pci ) ) != 0 ) {
295
+		DBGC ( device, "EFIPCI %p %s could not open PCI device: %s\n",
296
+		       device, efi_devpath_text ( efidev->path ),
297
+		       strerror ( rc ) );
298
+		goto err_open;
299
+	}
440 300
 
441 301
 	/* Find driver */
442
-	if ( ( rc = pci_find_driver ( &efipci->pci ) ) != 0 ) {
302
+	if ( ( rc = pci_find_driver ( pci ) ) != 0 ) {
443 303
 		DBGC ( device, "EFIPCI %p %s has no driver\n",
444
-		       device, efi_devpath_text ( efipci->path ) );
304
+		       device, efi_devpath_text ( efidev->path ) );
445 305
 		goto err_find_driver;
446 306
 	}
447 307
 
448
-	/* Enable PCI device */
449
-	if ( ( rc = efipci_enable ( efipci ) ) != 0 )
450
-		goto err_enable;
308
+	/* Mark PCI device as a child of the EFI device */
309
+	pci->dev.parent = &efidev->dev;
310
+	list_add ( &pci->dev.siblings, &efidev->dev.children );
451 311
 
452 312
 	/* Probe driver */
453
-	if ( ( rc = pci_probe ( &efipci->pci ) ) != 0 ) {
313
+	if ( ( rc = pci_probe ( pci ) ) != 0 ) {
454 314
 		DBGC ( device, "EFIPCI %p %s could not probe driver \"%s\": "
455
-		       "%s\n", device, efi_devpath_text ( efipci->path ),
456
-		       efipci->pci.id->name, strerror ( rc ) );
315
+		       "%s\n", device, efi_devpath_text ( efidev->path ),
316
+		       pci->id->name, strerror ( rc ) );
457 317
 		goto err_probe;
458 318
 	}
459 319
 	DBGC ( device, "EFIPCI %p %s using driver \"%s\"\n", device,
460
-	       efi_devpath_text ( efipci->path ), efipci->pci.id->name );
320
+	       efi_devpath_text ( efidev->path ), pci->id->name );
461 321
 
322
+	efidev_set_drvdata ( efidev, pci );
462 323
 	return 0;
463 324
 
464
-	pci_remove ( &efipci->pci );
325
+	pci_remove ( pci );
465 326
  err_probe:
466
- err_enable:
327
+	list_del ( &pci->dev.siblings );
467 328
  err_find_driver:
468
-	efipci_destroy ( efipci );
469
- err_create:
470
- err_already_started:
329
+	efipci_close ( device );
330
+ err_open:
331
+	free ( pci );
332
+ err_alloc:
471 333
 	return rc;
472 334
 }
473 335
 
474 336
 /**
475 337
  * Detach driver from device
476 338
  *
477
- * @v device		EFI device
339
+ * @v efidev		EFI device
478 340
   */
479
-static void efipci_stop ( EFI_HANDLE device ) {
480
-	struct efi_pci_device *efipci;
481
-
482
-	/* Find PCI device */
483
-	efipci = efipci_find_efi ( device );
484
-	if ( ! efipci )
485
-		return;
486
-
487
-	/* Remove device */
488
-	pci_remove ( &efipci->pci );
489
-
490
-	/* Delete EFI PCI device */
491
-	efipci_destroy ( efipci );
341
+static void efipci_stop ( struct efi_device *efidev ) {
342
+	struct pci_device *pci = efidev_get_drvdata ( efidev );
343
+	EFI_HANDLE device = efidev->device;
344
+
345
+	pci_remove ( pci );
346
+	list_del ( &pci->dev.siblings );
347
+	efipci_close ( device );
348
+	free ( pci );
492 349
 }
493 350
 
494 351
 /** EFI PCI driver */

+ 40
- 25
src/interface/efi/efi_snp.c Ver fichero

@@ -27,10 +27,8 @@ FILE_LICENCE ( GPL2_OR_LATER );
27 27
 #include <ipxe/netdevice.h>
28 28
 #include <ipxe/iobuf.h>
29 29
 #include <ipxe/in.h>
30
-#include <ipxe/pci.h>
31 30
 #include <ipxe/version.h>
32 31
 #include <ipxe/efi/efi.h>
33
-#include <ipxe/efi/efi_pci.h>
34 32
 #include <ipxe/efi/efi_driver.h>
35 33
 #include <ipxe/efi/efi_strings.h>
36 34
 #include <ipxe/efi/efi_snp.h>
@@ -348,7 +346,7 @@ efi_snp_station_address ( EFI_SIMPLE_NETWORK_PROTOCOL *snp, BOOLEAN reset,
348 346
 	/* MAC address changes take effect only on netdev_open() */
349 347
 	if ( netdev_is_open ( snpdev->netdev ) ) {
350 348
 		DBGC ( snpdev, "SNPDEV %p MAC address changed while net "
351
-		       "devive open\n", snpdev );
349
+		       "device open\n", snpdev );
352 350
 	}
353 351
 
354 352
 	return 0;
@@ -922,7 +920,7 @@ static struct efi_snp_device * efi_snp_demux ( struct net_device *netdev ) {
922 920
  */
923 921
 static int efi_snp_probe ( struct net_device *netdev ) {
924 922
 	EFI_BOOT_SERVICES *bs = efi_systab->BootServices;
925
-	struct efi_pci_device *efipci;
923
+	struct efi_device *efidev;
926 924
 	struct efi_snp_device *snpdev;
927 925
 	EFI_DEVICE_PATH_PROTOCOL *path_end;
928 926
 	MAC_ADDR_DEVICE_PATH *macpath;
@@ -930,18 +928,18 @@ static int efi_snp_probe ( struct net_device *netdev ) {
930 928
 	EFI_STATUS efirc;
931 929
 	int rc;
932 930
 
933
-	/* Find EFI PCI device */
934
-	efipci = efipci_find ( netdev->dev );
935
-	if ( ! efipci ) {
936
-		DBG ( "SNP skipping non-PCI device %s\n", netdev->name );
931
+	/* Find parent EFI device */
932
+	efidev = efidev_parent ( netdev->dev );
933
+	if ( ! efidev ) {
934
+		DBG ( "SNP skipping non-EFI device %s\n", netdev->name );
937 935
 		rc = 0;
938
-		goto err_no_pci;
936
+		goto err_no_efidev;
939 937
 	}
940 938
 
941 939
 	/* Calculate device path prefix length */
942
-	path_end = efi_devpath_end ( efipci->path );
940
+	path_end = efi_devpath_end ( efidev->path );
943 941
 	path_prefix_len = ( ( ( void * ) path_end ) -
944
-			    ( ( void * ) efipci->path ) );
942
+			    ( ( void * ) efidev->path ) );
945 943
 
946 944
 	/* Allocate the SNP device */
947 945
 	snpdev = zalloc ( sizeof ( *snpdev ) + path_prefix_len +
@@ -951,7 +949,7 @@ static int efi_snp_probe ( struct net_device *netdev ) {
951 949
 		goto err_alloc_snp;
952 950
 	}
953 951
 	snpdev->netdev = netdev_get ( netdev );
954
-	snpdev->efipci = efipci;
952
+	snpdev->efidev = efidev;
955 953
 
956 954
 	/* Sanity check */
957 955
 	if ( netdev->ll_protocol->ll_addr_len > sizeof ( EFI_MAC_ADDRESS ) ) {
@@ -1009,7 +1007,7 @@ static int efi_snp_probe ( struct net_device *netdev ) {
1009 1007
 		       "%s", netdev->name );
1010 1008
 
1011 1009
 	/* Populate the device path */
1012
-	memcpy ( &snpdev->path, efipci->path, path_prefix_len );
1010
+	memcpy ( &snpdev->path, efidev->path, path_prefix_len );
1013 1011
 	macpath = ( ( ( void * ) &snpdev->path ) + path_prefix_len );
1014 1012
 	path_end = ( ( void * ) ( macpath + 1 ) );
1015 1013
 	memset ( macpath, 0, sizeof ( *macpath ) );
@@ -1040,12 +1038,12 @@ static int efi_snp_probe ( struct net_device *netdev ) {
1040 1038
 		goto err_install_protocol_interface;
1041 1039
 	}
1042 1040
 
1043
-	/* Add as child of PCI device */
1044
-	if ( ( rc = efipci_child_add ( efipci, snpdev->handle ) ) != 0 ) {
1045
-		DBGC ( snpdev, "SNPDEV %p could not become child of " PCI_FMT
1046
-		       ": %s\n", snpdev, PCI_ARGS ( &efipci->pci ),
1047
-		       strerror ( rc ) );
1048
-		goto err_efipci_child_add;
1041
+	/* Add as child of EFI parent device */
1042
+	if ( ( rc = efidev_child_add ( efidev, snpdev->handle ) ) != 0 ) {
1043
+		DBGC ( snpdev, "SNPDEV %p could not become child of %p %s: "
1044
+		       "%s\n", snpdev, efidev->device,
1045
+		       efi_devpath_text ( efidev->path ), strerror ( rc ) );
1046
+		goto err_efidev_child_add;
1049 1047
 	}
1050 1048
 
1051 1049
 	/* Install HII */
@@ -1058,14 +1056,15 @@ static int efi_snp_probe ( struct net_device *netdev ) {
1058 1056
 	/* Add to list of SNP devices */
1059 1057
 	list_add ( &snpdev->list, &efi_snp_devices );
1060 1058
 
1061
-	DBGC ( snpdev, "SNPDEV %p installed for %s as device %p\n",
1062
-	       snpdev, netdev->name, snpdev->handle );
1059
+	DBGC ( snpdev, "SNPDEV %p installed for %s as device %p %s\n",
1060
+	       snpdev, netdev->name, snpdev->handle,
1061
+	       efi_devpath_text ( &snpdev->path ) );
1063 1062
 	return 0;
1064 1063
 
1065 1064
 	efi_snp_hii_uninstall ( snpdev );
1066 1065
  err_hii_install:
1067
-	efipci_child_del ( efipci, snpdev->handle );
1068
- err_efipci_child_add:
1066
+	efidev_child_del ( efidev, snpdev->handle );
1067
+ err_efidev_child_add:
1069 1068
 	bs->UninstallMultipleProtocolInterfaces (
1070 1069
 			snpdev->handle,
1071 1070
 			&efi_simple_network_protocol_guid, &snpdev->snp,
@@ -1082,7 +1081,7 @@ static int efi_snp_probe ( struct net_device *netdev ) {
1082 1081
 	netdev_put ( netdev );
1083 1082
 	free ( snpdev );
1084 1083
  err_alloc_snp:
1085
- err_no_pci:
1084
+ err_no_efidev:
1086 1085
 	return rc;
1087 1086
 }
1088 1087
 
@@ -1129,7 +1128,7 @@ static void efi_snp_remove ( struct net_device *netdev ) {
1129 1128
 
1130 1129
 	/* Uninstall the SNP */
1131 1130
 	efi_snp_hii_uninstall ( snpdev );
1132
-	efipci_child_del ( snpdev->efipci, snpdev->handle );
1131
+	efidev_child_del ( snpdev->efidev, snpdev->handle );
1133 1132
 	list_del ( &snpdev->list );
1134 1133
 	bs->UninstallMultipleProtocolInterfaces (
1135 1134
 			snpdev->handle,
@@ -1153,6 +1152,22 @@ struct net_driver efi_snp_driver __net_driver = {
1153 1152
 	.remove = efi_snp_remove,
1154 1153
 };
1155 1154
 
1155
+/**
1156
+ * Find SNP device by EFI device handle
1157
+ *
1158
+ * @v handle		EFI device handle
1159
+ * @ret snpdev		SNP device, or NULL
1160
+ */
1161
+struct efi_snp_device * find_snpdev ( EFI_HANDLE handle ) {
1162
+	struct efi_snp_device *snpdev;
1163
+
1164
+	list_for_each_entry ( snpdev, &efi_snp_devices, list ) {
1165
+		if ( snpdev->handle == handle )
1166
+			return snpdev;
1167
+	}
1168
+	return NULL;
1169
+}
1170
+
1156 1171
 /**
1157 1172
  * Get most recently opened SNP device
1158 1173
  *

Loading…
Cancelar
Guardar