]> glassweightruler.freedombox.rocks Git - Ventoy.git/blob - IPXE/ipxe-3fe683e/src/interface/efi/efi_pci.c
Update PhyDrive.c
[Ventoy.git] / IPXE / ipxe-3fe683e / src / interface / efi / efi_pci.c
1 /*
2 * Copyright (C) 2008 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 * You can also choose to distribute this program under the terms of
20 * the Unmodified Binary Distribution Licence (as given in the file
21 * COPYING.UBDL), provided that you have satisfied its requirements.
22 */
23
24 FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
25
26 #if 0
27
28 #include <stdlib.h>
29 #include <errno.h>
30 #include <ipxe/pci.h>
31 #include <ipxe/efi/efi.h>
32 #include <ipxe/efi/efi_pci.h>
33 #include <ipxe/efi/efi_driver.h>
34 #include <ipxe/efi/Protocol/PciIo.h>
35 #include <ipxe/efi/Protocol/PciRootBridgeIo.h>
36
37 /** @file
38 *
39 * iPXE PCI I/O API for EFI
40 *
41 */
42
43 /* Disambiguate the various error causes */
44 #define EINFO_EEFI_PCI \
45 __einfo_uniqify ( EINFO_EPLATFORM, 0x01, \
46 "Could not open PCI I/O protocol" )
47 #define EINFO_EEFI_PCI_NOT_PCI \
48 __einfo_platformify ( EINFO_EEFI_PCI, EFI_UNSUPPORTED, \
49 "Not a PCI device" )
50 #define EEFI_PCI_NOT_PCI __einfo_error ( EINFO_EEFI_PCI_NOT_PCI )
51 #define EINFO_EEFI_PCI_IN_USE \
52 __einfo_platformify ( EINFO_EEFI_PCI, EFI_ACCESS_DENIED, \
53 "PCI device already has a driver" )
54 #define EEFI_PCI_IN_USE __einfo_error ( EINFO_EEFI_PCI_IN_USE )
55 #define EEFI_PCI( efirc ) \
56 EPLATFORM ( EINFO_EEFI_PCI, efirc, \
57 EEFI_PCI_NOT_PCI, EEFI_PCI_IN_USE )
58
59 /******************************************************************************
60 *
61 * iPXE PCI API
62 *
63 ******************************************************************************
64 */
65
66 /**
67 * Locate EFI PCI root bridge I/O protocol
68 *
69 * @v pci PCI device
70 * @ret handle EFI PCI root bridge handle
71 * @ret root EFI PCI root bridge I/O protocol, or NULL if not found
72 * @ret rc Return status code
73 */
74 static int efipci_root ( struct pci_device *pci, EFI_HANDLE *handle,
75 EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL **root ) {
76 EFI_BOOT_SERVICES *bs = efi_systab->BootServices;
77 EFI_HANDLE *handles;
78 UINTN num_handles;
79 union {
80 void *interface;
81 EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *root;
82 } u;
83 EFI_STATUS efirc;
84 UINTN i;
85 int rc;
86
87 /* Enumerate all handles */
88 if ( ( efirc = bs->LocateHandleBuffer ( ByProtocol,
89 &efi_pci_root_bridge_io_protocol_guid,
90 NULL, &num_handles, &handles ) ) != 0 ) {
91 rc = -EEFI ( efirc );
92 DBGC ( pci, "EFIPCI " PCI_FMT " cannot locate root bridges: "
93 "%s\n", PCI_ARGS ( pci ), strerror ( rc ) );
94 goto err_locate;
95 }
96
97 /* Look for matching root bridge I/O protocol */
98 for ( i = 0 ; i < num_handles ; i++ ) {
99 *handle = handles[i];
100 if ( ( efirc = bs->OpenProtocol ( *handle,
101 &efi_pci_root_bridge_io_protocol_guid,
102 &u.interface, efi_image_handle, *handle,
103 EFI_OPEN_PROTOCOL_GET_PROTOCOL ) ) != 0 ) {
104 rc = -EEFI ( efirc );
105 DBGC ( pci, "EFIPCI " PCI_FMT " cannot open %s: %s\n",
106 PCI_ARGS ( pci ), efi_handle_name ( *handle ),
107 strerror ( rc ) );
108 continue;
109 }
110 if ( u.root->SegmentNumber == PCI_SEG ( pci->busdevfn ) ) {
111 *root = u.root;
112 bs->FreePool ( handles );
113 return 0;
114 }
115 bs->CloseProtocol ( *handle,
116 &efi_pci_root_bridge_io_protocol_guid,
117 efi_image_handle, *handle );
118 }
119 DBGC ( pci, "EFIPCI " PCI_FMT " found no root bridge\n",
120 PCI_ARGS ( pci ) );
121 rc = -ENOENT;
122
123 bs->FreePool ( handles );
124 err_locate:
125 return rc;
126 }
127
128 /**
129 * Calculate EFI PCI configuration space address
130 *
131 * @v pci PCI device
132 * @v location Encoded offset and width
133 * @ret address EFI PCI address
134 */
135 static unsigned long efipci_address ( struct pci_device *pci,
136 unsigned long location ) {
137
138 return EFI_PCI_ADDRESS ( PCI_BUS ( pci->busdevfn ),
139 PCI_SLOT ( pci->busdevfn ),
140 PCI_FUNC ( pci->busdevfn ),
141 EFIPCI_OFFSET ( location ) );
142 }
143
144 /**
145 * Read from PCI configuration space
146 *
147 * @v pci PCI device
148 * @v location Encoded offset and width
149 * @ret value Value
150 * @ret rc Return status code
151 */
152 int efipci_read ( struct pci_device *pci, unsigned long location,
153 void *value ) {
154 EFI_BOOT_SERVICES *bs = efi_systab->BootServices;
155 EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *root;
156 EFI_HANDLE handle;
157 EFI_STATUS efirc;
158 int rc;
159
160 /* Identify root bridge */
161 if ( ( rc = efipci_root ( pci, &handle, &root ) ) != 0 )
162 goto err_root;
163
164 /* Read from configuration space */
165 if ( ( efirc = root->Pci.Read ( root, EFIPCI_WIDTH ( location ),
166 efipci_address ( pci, location ), 1,
167 value ) ) != 0 ) {
168 rc = -EEFI ( efirc );
169 DBGC ( pci, "EFIPCI " PCI_FMT " config read from offset %02lx "
170 "failed: %s\n", PCI_ARGS ( pci ),
171 EFIPCI_OFFSET ( location ), strerror ( rc ) );
172 goto err_read;
173 }
174
175 err_read:
176 bs->CloseProtocol ( handle, &efi_pci_root_bridge_io_protocol_guid,
177 efi_image_handle, handle );
178 err_root:
179 return rc;
180 }
181
182 /**
183 * Write to PCI configuration space
184 *
185 * @v pci PCI device
186 * @v location Encoded offset and width
187 * @v value Value
188 * @ret rc Return status code
189 */
190 int efipci_write ( struct pci_device *pci, unsigned long location,
191 unsigned long value ) {
192 EFI_BOOT_SERVICES *bs = efi_systab->BootServices;
193 EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *root;
194 EFI_HANDLE handle;
195 EFI_STATUS efirc;
196 int rc;
197
198 /* Identify root bridge */
199 if ( ( rc = efipci_root ( pci, &handle, &root ) ) != 0 )
200 goto err_root;
201
202 /* Read from configuration space */
203 if ( ( efirc = root->Pci.Write ( root, EFIPCI_WIDTH ( location ),
204 efipci_address ( pci, location ), 1,
205 &value ) ) != 0 ) {
206 rc = -EEFI ( efirc );
207 DBGC ( pci, "EFIPCI " PCI_FMT " config write to offset %02lx "
208 "failed: %s\n", PCI_ARGS ( pci ),
209 EFIPCI_OFFSET ( location ), strerror ( rc ) );
210 goto err_write;
211 }
212
213 err_write:
214 bs->CloseProtocol ( handle, &efi_pci_root_bridge_io_protocol_guid,
215 efi_image_handle, handle );
216 err_root:
217 return rc;
218 }
219
220 PROVIDE_PCIAPI_INLINE ( efi, pci_num_bus );
221 PROVIDE_PCIAPI_INLINE ( efi, pci_read_config_byte );
222 PROVIDE_PCIAPI_INLINE ( efi, pci_read_config_word );
223 PROVIDE_PCIAPI_INLINE ( efi, pci_read_config_dword );
224 PROVIDE_PCIAPI_INLINE ( efi, pci_write_config_byte );
225 PROVIDE_PCIAPI_INLINE ( efi, pci_write_config_word );
226 PROVIDE_PCIAPI_INLINE ( efi, pci_write_config_dword );
227
228 /******************************************************************************
229 *
230 * EFI PCI device instantiation
231 *
232 ******************************************************************************
233 */
234
235 /**
236 * Open EFI PCI device
237 *
238 * @v device EFI device handle
239 * @v attributes Protocol opening attributes
240 * @v pci PCI device to fill in
241 * @ret rc Return status code
242 */
243 int efipci_open ( EFI_HANDLE device, UINT32 attributes,
244 struct pci_device *pci ) {
245 EFI_BOOT_SERVICES *bs = efi_systab->BootServices;
246 union {
247 EFI_PCI_IO_PROTOCOL *pci_io;
248 void *interface;
249 } pci_io;
250 UINTN pci_segment, pci_bus, pci_dev, pci_fn;
251 unsigned int busdevfn;
252 EFI_STATUS efirc;
253 int rc;
254
255 /* See if device is a PCI device */
256 if ( ( efirc = bs->OpenProtocol ( device, &efi_pci_io_protocol_guid,
257 &pci_io.interface, efi_image_handle,
258 device, attributes ) ) != 0 ) {
259 rc = -EEFI_PCI ( efirc );
260 DBGCP ( device, "EFIPCI %s cannot open PCI protocols: %s\n",
261 efi_handle_name ( device ), strerror ( rc ) );
262 goto err_open_protocol;
263 }
264
265 /* Get PCI bus:dev.fn address */
266 if ( ( efirc = pci_io.pci_io->GetLocation ( pci_io.pci_io, &pci_segment,
267 &pci_bus, &pci_dev,
268 &pci_fn ) ) != 0 ) {
269 rc = -EEFI ( efirc );
270 DBGC ( device, "EFIPCI %s could not get PCI location: %s\n",
271 efi_handle_name ( device ), strerror ( rc ) );
272 goto err_get_location;
273 }
274 busdevfn = PCI_BUSDEVFN ( pci_segment, pci_bus, pci_dev, pci_fn );
275 pci_init ( pci, busdevfn );
276 DBGCP ( device, "EFIPCI " PCI_FMT " is %s\n",
277 PCI_ARGS ( pci ), efi_handle_name ( device ) );
278
279 /* Try to enable I/O cycles, memory cycles, and bus mastering.
280 * Some platforms will 'helpfully' report errors if these bits
281 * can't be enabled (for example, if the card doesn't actually
282 * support I/O cycles). Work around any such platforms by
283 * enabling bits individually and simply ignoring any errors.
284 */
285 pci_io.pci_io->Attributes ( pci_io.pci_io,
286 EfiPciIoAttributeOperationEnable,
287 EFI_PCI_IO_ATTRIBUTE_IO, NULL );
288 pci_io.pci_io->Attributes ( pci_io.pci_io,
289 EfiPciIoAttributeOperationEnable,
290 EFI_PCI_IO_ATTRIBUTE_MEMORY, NULL );
291 pci_io.pci_io->Attributes ( pci_io.pci_io,
292 EfiPciIoAttributeOperationEnable,
293 EFI_PCI_IO_ATTRIBUTE_BUS_MASTER, NULL );
294
295 /* Populate PCI device */
296 if ( ( rc = pci_read_config ( pci ) ) != 0 ) {
297 DBGC ( device, "EFIPCI " PCI_FMT " cannot read PCI "
298 "configuration: %s\n",
299 PCI_ARGS ( pci ), strerror ( rc ) );
300 goto err_pci_read_config;
301 }
302
303 return 0;
304
305 err_pci_read_config:
306 err_get_location:
307 bs->CloseProtocol ( device, &efi_pci_io_protocol_guid,
308 efi_image_handle, device );
309 err_open_protocol:
310 return rc;
311 }
312
313 /**
314 * Close EFI PCI device
315 *
316 * @v device EFI device handle
317 */
318 void efipci_close ( EFI_HANDLE device ) {
319 EFI_BOOT_SERVICES *bs = efi_systab->BootServices;
320
321 bs->CloseProtocol ( device, &efi_pci_io_protocol_guid,
322 efi_image_handle, device );
323 }
324
325 /**
326 * Get EFI PCI device information
327 *
328 * @v device EFI device handle
329 * @v pci PCI device to fill in
330 * @ret rc Return status code
331 */
332 int efipci_info ( EFI_HANDLE device, struct pci_device *pci ) {
333 int rc;
334
335 /* Open PCI device, if possible */
336 if ( ( rc = efipci_open ( device, EFI_OPEN_PROTOCOL_GET_PROTOCOL,
337 pci ) ) != 0 )
338 return rc;
339
340 /* Close PCI device */
341 efipci_close ( device );
342
343 return 0;
344 }
345
346 /******************************************************************************
347 *
348 * EFI PCI driver
349 *
350 ******************************************************************************
351 */
352
353 /**
354 * Check to see if driver supports a device
355 *
356 * @v device EFI device handle
357 * @ret rc Return status code
358 */
359 static int efipci_supported ( EFI_HANDLE device ) {
360 struct pci_device pci;
361 int rc;
362
363 /* Get PCI device information */
364 if ( ( rc = efipci_info ( device, &pci ) ) != 0 )
365 return rc;
366
367 /* Look for a driver */
368 if ( ( rc = pci_find_driver ( &pci ) ) != 0 ) {
369 DBGC ( device, "EFIPCI " PCI_FMT " (%04x:%04x class %06x) "
370 "has no driver\n", PCI_ARGS ( &pci ), pci.vendor,
371 pci.device, pci.class );
372 return rc;
373 }
374 DBGC ( device, "EFIPCI " PCI_FMT " (%04x:%04x class %06x) has driver "
375 "\"%s\"\n", PCI_ARGS ( &pci ), pci.vendor, pci.device,
376 pci.class, pci.id->name );
377
378 return 0;
379 }
380
381 /**
382 * Attach driver to device
383 *
384 * @v efidev EFI device
385 * @ret rc Return status code
386 */
387 static int efipci_start ( struct efi_device *efidev ) {
388 EFI_HANDLE device = efidev->device;
389 struct pci_device *pci;
390 int rc;
391
392 /* Allocate PCI device */
393 pci = zalloc ( sizeof ( *pci ) );
394 if ( ! pci ) {
395 rc = -ENOMEM;
396 goto err_alloc;
397 }
398
399 /* Open PCI device */
400 if ( ( rc = efipci_open ( device, ( EFI_OPEN_PROTOCOL_BY_DRIVER |
401 EFI_OPEN_PROTOCOL_EXCLUSIVE ),
402 pci ) ) != 0 ) {
403 DBGC ( device, "EFIPCI %s could not open PCI device: %s\n",
404 efi_handle_name ( device ), strerror ( rc ) );
405 DBGC_EFI_OPENERS ( device, device, &efi_pci_io_protocol_guid );
406 goto err_open;
407 }
408
409 /* Find driver */
410 if ( ( rc = pci_find_driver ( pci ) ) != 0 ) {
411 DBGC ( device, "EFIPCI " PCI_FMT " has no driver\n",
412 PCI_ARGS ( pci ) );
413 goto err_find_driver;
414 }
415
416 /* Mark PCI device as a child of the EFI device */
417 pci->dev.parent = &efidev->dev;
418 list_add ( &pci->dev.siblings, &efidev->dev.children );
419
420 /* Probe driver */
421 if ( ( rc = pci_probe ( pci ) ) != 0 ) {
422 DBGC ( device, "EFIPCI " PCI_FMT " could not probe driver "
423 "\"%s\": %s\n", PCI_ARGS ( pci ), pci->id->name,
424 strerror ( rc ) );
425 goto err_probe;
426 }
427 DBGC ( device, "EFIPCI " PCI_FMT " using driver \"%s\"\n",
428 PCI_ARGS ( pci ), pci->id->name );
429
430 efidev_set_drvdata ( efidev, pci );
431 return 0;
432
433 pci_remove ( pci );
434 err_probe:
435 list_del ( &pci->dev.siblings );
436 err_find_driver:
437 efipci_close ( device );
438 err_open:
439 free ( pci );
440 err_alloc:
441 return rc;
442 }
443
444 /**
445 * Detach driver from device
446 *
447 * @v efidev EFI device
448 */
449 static void efipci_stop ( struct efi_device *efidev ) {
450 struct pci_device *pci = efidev_get_drvdata ( efidev );
451 EFI_HANDLE device = efidev->device;
452
453 pci_remove ( pci );
454 list_del ( &pci->dev.siblings );
455 efipci_close ( device );
456 free ( pci );
457 }
458
459 /** EFI PCI driver */
460 struct efi_driver efipci_driver __efi_driver ( EFI_DRIVER_NORMAL ) = {
461 .name = "PCI",
462 .supported = efipci_supported,
463 .start = efipci_start,
464 .stop = efipci_stop,
465 };
466
467 #endif