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