2 * Copyright (C) 2008 Michael Brown <mbrown@fensystems.co.uk>.
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.
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.
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
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.
24 FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL
);
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>
39 * iPXE PCI I/O API for EFI
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, \
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 )
59 /******************************************************************************
63 ******************************************************************************
67 * Locate EFI PCI root bridge I/O protocol
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
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
;
81 EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL
*root
;
87 /* Enumerate all handles */
88 if ( ( efirc
= bs
->LocateHandleBuffer ( ByProtocol
,
89 &efi_pci_root_bridge_io_protocol_guid
,
90 NULL
, &num_handles
, &handles
) ) != 0 ) {
92 DBGC ( pci
, "EFIPCI " PCI_FMT
" cannot locate root bridges: "
93 "%s\n", PCI_ARGS ( pci
), strerror ( rc
) );
97 /* Look for matching root bridge I/O protocol */
98 for ( i
= 0 ; i
< num_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
),
110 if ( u
.root
->SegmentNumber
== PCI_SEG ( pci
->busdevfn
) ) {
112 bs
->FreePool ( handles
);
115 bs
->CloseProtocol ( *handle
,
116 &efi_pci_root_bridge_io_protocol_guid
,
117 efi_image_handle
, *handle
);
119 DBGC ( pci
, "EFIPCI " PCI_FMT
" found no root bridge\n",
123 bs
->FreePool ( handles
);
129 * Calculate EFI PCI configuration space address
132 * @v location Encoded offset and width
133 * @ret address EFI PCI address
135 static unsigned long efipci_address ( struct pci_device
*pci
,
136 unsigned long location
) {
138 return EFI_PCI_ADDRESS ( PCI_BUS ( pci
->busdevfn
),
139 PCI_SLOT ( pci
->busdevfn
),
140 PCI_FUNC ( pci
->busdevfn
),
141 EFIPCI_OFFSET ( location
) );
145 * Read from PCI configuration space
148 * @v location Encoded offset and width
150 * @ret rc Return status code
152 int efipci_read ( struct pci_device
*pci
, unsigned long location
,
154 EFI_BOOT_SERVICES
*bs
= efi_systab
->BootServices
;
155 EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL
*root
;
160 /* Identify root bridge */
161 if ( ( rc
= efipci_root ( pci
, &handle
, &root
) ) != 0 )
164 /* Read from configuration space */
165 if ( ( efirc
= root
->Pci
.Read ( root
, EFIPCI_WIDTH ( location
),
166 efipci_address ( pci
, location
), 1,
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
) );
176 bs
->CloseProtocol ( handle
, &efi_pci_root_bridge_io_protocol_guid
,
177 efi_image_handle
, handle
);
183 * Write to PCI configuration space
186 * @v location Encoded offset and width
188 * @ret rc Return status code
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
;
198 /* Identify root bridge */
199 if ( ( rc
= efipci_root ( pci
, &handle
, &root
) ) != 0 )
202 /* Read from configuration space */
203 if ( ( efirc
= root
->Pci
.Write ( root
, EFIPCI_WIDTH ( location
),
204 efipci_address ( pci
, location
), 1,
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
) );
214 bs
->CloseProtocol ( handle
, &efi_pci_root_bridge_io_protocol_guid
,
215 efi_image_handle
, handle
);
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
);
228 /******************************************************************************
230 * EFI PCI device instantiation
232 ******************************************************************************
236 * Open EFI PCI device
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
243 int efipci_open ( EFI_HANDLE device
, UINT32 attributes
,
244 struct pci_device
*pci
) {
245 EFI_BOOT_SERVICES
*bs
= efi_systab
->BootServices
;
247 EFI_PCI_IO_PROTOCOL
*pci_io
;
250 UINTN pci_segment
, pci_bus
, pci_dev
, pci_fn
;
251 unsigned int busdevfn
;
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
;
265 /* Get PCI bus:dev.fn address */
266 if ( ( efirc
= pci_io
.pci_io
->GetLocation ( pci_io
.pci_io
, &pci_segment
,
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
;
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
) );
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.
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
);
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
;
307 bs
->CloseProtocol ( device
, &efi_pci_io_protocol_guid
,
308 efi_image_handle
, device
);
314 * Close EFI PCI device
316 * @v device EFI device handle
318 void efipci_close ( EFI_HANDLE device
) {
319 EFI_BOOT_SERVICES
*bs
= efi_systab
->BootServices
;
321 bs
->CloseProtocol ( device
, &efi_pci_io_protocol_guid
,
322 efi_image_handle
, device
);
326 * Get EFI PCI device information
328 * @v device EFI device handle
329 * @v pci PCI device to fill in
330 * @ret rc Return status code
332 int efipci_info ( EFI_HANDLE device
, struct pci_device
*pci
) {
335 /* Open PCI device, if possible */
336 if ( ( rc
= efipci_open ( device
, EFI_OPEN_PROTOCOL_GET_PROTOCOL
,
340 /* Close PCI device */
341 efipci_close ( device
);
346 /******************************************************************************
350 ******************************************************************************
354 * Check to see if driver supports a device
356 * @v device EFI device handle
357 * @ret rc Return status code
359 static int efipci_supported ( EFI_HANDLE device
) {
360 struct pci_device pci
;
363 /* Get PCI device information */
364 if ( ( rc
= efipci_info ( device
, &pci
) ) != 0 )
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 );
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
);
382 * Attach driver to device
384 * @v efidev EFI device
385 * @ret rc Return status code
387 static int efipci_start ( struct efi_device
*efidev
) {
388 EFI_HANDLE device
= efidev
->device
;
389 struct pci_device
*pci
;
392 /* Allocate PCI device */
393 pci
= zalloc ( sizeof ( *pci
) );
399 /* Open PCI device */
400 if ( ( rc
= efipci_open ( device
, ( EFI_OPEN_PROTOCOL_BY_DRIVER
|
401 EFI_OPEN_PROTOCOL_EXCLUSIVE
),
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
);
410 if ( ( rc
= pci_find_driver ( pci
) ) != 0 ) {
411 DBGC ( device
, "EFIPCI " PCI_FMT
" has no driver\n",
413 goto err_find_driver
;
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
);
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
,
427 DBGC ( device
, "EFIPCI " PCI_FMT
" using driver \"%s\"\n",
428 PCI_ARGS ( pci
), pci
->id
->name
);
430 efidev_set_drvdata ( efidev
, pci
);
435 list_del ( &pci
->dev
.siblings
);
437 efipci_close ( device
);
445 * Detach driver from device
447 * @v efidev EFI device
449 static void efipci_stop ( struct efi_device
*efidev
) {
450 struct pci_device
*pci
= efidev_get_drvdata ( efidev
);
451 EFI_HANDLE device
= efidev
->device
;
454 list_del ( &pci
->dev
.siblings
);
455 efipci_close ( device
);
459 /** EFI PCI driver */
460 struct efi_driver efipci_driver
__efi_driver ( EFI_DRIVER_NORMAL
) = {
462 .supported
= efipci_supported
,
463 .start
= efipci_start
,