|
|
1.1 ! root 1: /* ! 2: * Copyright (C) 2008 Michael Brown <[email protected]>. ! 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., 675 Mass Ave, Cambridge, MA 02139, USA. ! 17: */ ! 18: ! 19: FILE_LICENCE ( GPL2_OR_LATER ); ! 20: ! 21: #include <stdlib.h> ! 22: #include <errno.h> ! 23: #include <ipxe/pci.h> ! 24: #include <ipxe/init.h> ! 25: #include <ipxe/efi/efi.h> ! 26: #include <ipxe/efi/efi_pci.h> ! 27: #include <ipxe/efi/efi_driver.h> ! 28: #include <ipxe/efi/Protocol/PciIo.h> ! 29: #include <ipxe/efi/Protocol/PciRootBridgeIo.h> ! 30: ! 31: /** @file ! 32: * ! 33: * iPXE PCI I/O API for EFI ! 34: * ! 35: */ ! 36: ! 37: /****************************************************************************** ! 38: * ! 39: * iPXE PCI API ! 40: * ! 41: ****************************************************************************** ! 42: */ ! 43: ! 44: /** PCI root bridge I/O protocol */ ! 45: static EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *efipci; ! 46: EFI_REQUIRE_PROTOCOL ( EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL, &efipci ); ! 47: ! 48: static unsigned long efipci_address ( struct pci_device *pci, ! 49: unsigned long location ) { ! 50: return EFI_PCI_ADDRESS ( PCI_BUS ( pci->busdevfn ), ! 51: PCI_SLOT ( pci->busdevfn ), ! 52: PCI_FUNC ( pci->busdevfn ), ! 53: EFIPCI_OFFSET ( location ) ); ! 54: } ! 55: ! 56: int efipci_read ( struct pci_device *pci, unsigned long location, ! 57: void *value ) { ! 58: EFI_STATUS efirc; ! 59: ! 60: if ( ( efirc = efipci->Pci.Read ( efipci, EFIPCI_WIDTH ( location ), ! 61: efipci_address ( pci, location ), 1, ! 62: value ) ) != 0 ) { ! 63: DBG ( "EFIPCI config read from " PCI_FMT " offset %02lx " ! 64: "failed: %s\n", PCI_ARGS ( pci ), ! 65: EFIPCI_OFFSET ( location ), efi_strerror ( efirc ) ); ! 66: return -EIO; ! 67: } ! 68: ! 69: return 0; ! 70: } ! 71: ! 72: int efipci_write ( struct pci_device *pci, unsigned long location, ! 73: unsigned long value ) { ! 74: EFI_STATUS efirc; ! 75: ! 76: if ( ( efirc = efipci->Pci.Write ( efipci, EFIPCI_WIDTH ( location ), ! 77: efipci_address ( pci, location ), 1, ! 78: &value ) ) != 0 ) { ! 79: DBG ( "EFIPCI config write to " PCI_FMT " offset %02lx " ! 80: "failed: %s\n", PCI_ARGS ( pci ), ! 81: EFIPCI_OFFSET ( location ), efi_strerror ( efirc ) ); ! 82: return -EIO; ! 83: } ! 84: ! 85: return 0; ! 86: } ! 87: ! 88: PROVIDE_PCIAPI_INLINE ( efi, pci_num_bus ); ! 89: PROVIDE_PCIAPI_INLINE ( efi, pci_read_config_byte ); ! 90: PROVIDE_PCIAPI_INLINE ( efi, pci_read_config_word ); ! 91: PROVIDE_PCIAPI_INLINE ( efi, pci_read_config_dword ); ! 92: PROVIDE_PCIAPI_INLINE ( efi, pci_write_config_byte ); ! 93: PROVIDE_PCIAPI_INLINE ( efi, pci_write_config_word ); ! 94: PROVIDE_PCIAPI_INLINE ( efi, pci_write_config_dword ); ! 95: ! 96: /****************************************************************************** ! 97: * ! 98: * EFI PCI device instantiation ! 99: * ! 100: ****************************************************************************** ! 101: */ ! 102: ! 103: /** EFI PCI I/O protocol GUID */ ! 104: static EFI_GUID efi_pci_io_protocol_guid ! 105: = EFI_PCI_IO_PROTOCOL_GUID; ! 106: ! 107: /** EFI device path protocol GUID */ ! 108: static EFI_GUID efi_device_path_protocol_guid ! 109: = EFI_DEVICE_PATH_PROTOCOL_GUID; ! 110: ! 111: /** EFI PCI devices */ ! 112: static LIST_HEAD ( efi_pci_devices ); ! 113: ! 114: /** ! 115: * Create EFI PCI device ! 116: * ! 117: * @v efidrv EFI driver ! 118: * @v device EFI device ! 119: * @ret efipci EFI PCI device, or NULL ! 120: */ ! 121: struct efi_pci_device * efipci_create ( struct efi_driver *efidrv, ! 122: EFI_HANDLE device ) { ! 123: EFI_BOOT_SERVICES *bs = efi_systab->BootServices; ! 124: struct efi_pci_device *efipci; ! 125: union { ! 126: EFI_PCI_IO_PROTOCOL *pci_io; ! 127: void *interface; ! 128: } pci_io; ! 129: union { ! 130: EFI_DEVICE_PATH_PROTOCOL *path; ! 131: void *interface; ! 132: } path; ! 133: UINTN pci_segment, pci_bus, pci_dev, pci_fn; ! 134: EFI_STATUS efirc; ! 135: int rc; ! 136: ! 137: /* Allocate PCI device */ ! 138: efipci = zalloc ( sizeof ( *efipci ) ); ! 139: if ( ! efipci ) ! 140: goto err_zalloc; ! 141: efipci->device = device; ! 142: efipci->efidrv = efidrv; ! 143: ! 144: /* See if device is a PCI device */ ! 145: if ( ( efirc = bs->OpenProtocol ( device, ! 146: &efi_pci_io_protocol_guid, ! 147: &pci_io.interface, ! 148: efidrv->driver.DriverBindingHandle, ! 149: device, ! 150: EFI_OPEN_PROTOCOL_BY_DRIVER )) !=0 ){ ! 151: DBGCP ( efipci, "EFIPCI device %p is not a PCI device\n", ! 152: device ); ! 153: goto err_open_protocol; ! 154: } ! 155: efipci->pci_io = pci_io.pci_io; ! 156: ! 157: /* Get PCI bus:dev.fn address */ ! 158: if ( ( efirc = pci_io.pci_io->GetLocation ( pci_io.pci_io, ! 159: &pci_segment, ! 160: &pci_bus, &pci_dev, ! 161: &pci_fn ) ) != 0 ) { ! 162: DBGC ( efipci, "EFIPCI device %p could not get PCI " ! 163: "location: %s\n", device, efi_strerror ( efirc ) ); ! 164: goto err_get_location; ! 165: } ! 166: DBGC2 ( efipci, "EFIPCI device %p is PCI %04lx:%02lx:%02lx.%lx\n", ! 167: device, ( ( unsigned long ) pci_segment ), ! 168: ( ( unsigned long ) pci_bus ), ( ( unsigned long ) pci_dev ), ! 169: ( ( unsigned long ) pci_fn ) ); ! 170: ! 171: /* Populate PCI device */ ! 172: pci_init ( &efipci->pci, PCI_BUSDEVFN ( pci_bus, pci_dev, pci_fn ) ); ! 173: if ( ( rc = pci_read_config ( &efipci->pci ) ) != 0 ) { ! 174: DBGC ( efipci, "EFIPCI " PCI_FMT " cannot read PCI " ! 175: "configuration: %s\n", ! 176: PCI_ARGS ( &efipci->pci ), strerror ( rc ) ); ! 177: goto err_pci_read_config; ! 178: } ! 179: ! 180: /* Retrieve device path */ ! 181: if ( ( efirc = bs->OpenProtocol ( device, ! 182: &efi_device_path_protocol_guid, ! 183: &path.interface, ! 184: efidrv->driver.DriverBindingHandle, ! 185: device, ! 186: EFI_OPEN_PROTOCOL_BY_DRIVER )) !=0 ){ ! 187: DBGC ( efipci, "EFIPCI " PCI_FMT " has no device path\n", ! 188: PCI_ARGS ( &efipci->pci ) ); ! 189: goto err_no_device_path; ! 190: } ! 191: efipci->path = path.path; ! 192: ! 193: /* Add to list of PCI devices */ ! 194: list_add ( &efipci->list, &efi_pci_devices ); ! 195: ! 196: return efipci; ! 197: ! 198: bs->CloseProtocol ( device, &efi_device_path_protocol_guid, ! 199: efidrv->driver.DriverBindingHandle, device ); ! 200: err_no_device_path: ! 201: err_pci_read_config: ! 202: err_get_location: ! 203: bs->CloseProtocol ( device, &efi_pci_io_protocol_guid, ! 204: efidrv->driver.DriverBindingHandle, device ); ! 205: err_open_protocol: ! 206: free ( efipci ); ! 207: err_zalloc: ! 208: return NULL; ! 209: } ! 210: ! 211: /** ! 212: * Enable EFI PCI device ! 213: * ! 214: * @v efipci EFI PCI device ! 215: * @ret efirc EFI status code ! 216: */ ! 217: EFI_STATUS efipci_enable ( struct efi_pci_device *efipci ) { ! 218: EFI_PCI_IO_PROTOCOL *pci_io = efipci->pci_io; ! 219: EFI_STATUS efirc; ! 220: ! 221: /* Enable device */ ! 222: if ( ( efirc = pci_io->Attributes ( pci_io, ! 223: EfiPciIoAttributeOperationSet, ! 224: EFI_PCI_DEVICE_ENABLE, ! 225: NULL ) ) != 0 ) { ! 226: DBGC ( efipci, "EFIPCI " PCI_FMT " could not be enabled: %s\n", ! 227: PCI_ARGS ( &efipci->pci ), efi_strerror ( efirc ) ); ! 228: return efirc; ! 229: } ! 230: ! 231: return 0; ! 232: } ! 233: ! 234: /** ! 235: * Find EFI PCI device by EFI device ! 236: * ! 237: * @v device EFI device ! 238: * @ret efipci EFI PCI device, or NULL ! 239: */ ! 240: struct efi_pci_device * efipci_find_efi ( EFI_HANDLE device ) { ! 241: struct efi_pci_device *efipci; ! 242: ! 243: list_for_each_entry ( efipci, &efi_pci_devices, list ) { ! 244: if ( efipci->device == device ) ! 245: return efipci; ! 246: } ! 247: return NULL; ! 248: } ! 249: ! 250: /** ! 251: * Find EFI PCI device by iPXE device ! 252: * ! 253: * @v dev Device ! 254: * @ret efipci EFI PCI device, or NULL ! 255: */ ! 256: struct efi_pci_device * efipci_find ( struct device *dev ) { ! 257: struct efi_pci_device *efipci; ! 258: ! 259: list_for_each_entry ( efipci, &efi_pci_devices, list ) { ! 260: if ( &efipci->pci.dev == dev ) ! 261: return efipci; ! 262: } ! 263: return NULL; ! 264: } ! 265: ! 266: /** ! 267: * Add EFI device as child of EFI PCI device ! 268: * ! 269: * @v efipci EFI PCI device ! 270: * @v device EFI child device ! 271: * @ret efirc EFI status code ! 272: */ ! 273: EFI_STATUS efipci_child_add ( struct efi_pci_device *efipci, ! 274: EFI_HANDLE device ) { ! 275: EFI_BOOT_SERVICES *bs = efi_systab->BootServices; ! 276: struct efi_driver *efidrv = efipci->efidrv; ! 277: union { ! 278: EFI_PCI_IO_PROTOCOL *pci_io; ! 279: void *interface; ! 280: } pci_io; ! 281: EFI_STATUS efirc; ! 282: ! 283: /* Re-open the PCI_IO_PROTOCOL */ ! 284: if ( ( efirc = bs->OpenProtocol ( efipci->device, ! 285: &efi_pci_io_protocol_guid, ! 286: &pci_io.interface, ! 287: efidrv->driver.DriverBindingHandle, ! 288: device, ! 289: EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER ! 290: ) ) != 0 ) { ! 291: DBGC ( efipci, "EFIPCI " PCI_FMT " could not add child: %s\n", ! 292: PCI_ARGS ( &efipci->pci ), efi_strerror ( efirc ) ); ! 293: return efirc; ! 294: } ! 295: ! 296: return 0; ! 297: } ! 298: ! 299: /** ! 300: * Remove EFI device as child of PCI device ! 301: * ! 302: * @v efipci EFI PCI device ! 303: * @v device EFI child device ! 304: * @ret efirc EFI status code ! 305: */ ! 306: void efipci_child_del ( struct efi_pci_device *efipci, EFI_HANDLE device ) { ! 307: EFI_BOOT_SERVICES *bs = efi_systab->BootServices; ! 308: struct efi_driver *efidrv = efipci->efidrv; ! 309: ! 310: bs->CloseProtocol ( efipci->device, &efi_pci_io_protocol_guid, ! 311: efidrv->driver.DriverBindingHandle, device ); ! 312: } ! 313: ! 314: /** ! 315: * Destroy EFI PCI device ! 316: * ! 317: * @v efidrv EFI driver ! 318: * @v efipci EFI PCI device ! 319: */ ! 320: void efipci_destroy ( struct efi_driver *efidrv, ! 321: struct efi_pci_device *efipci ) { ! 322: EFI_BOOT_SERVICES *bs = efi_systab->BootServices; ! 323: ! 324: list_del ( &efipci->list ); ! 325: bs->CloseProtocol ( efipci->device, &efi_device_path_protocol_guid, ! 326: efidrv->driver.DriverBindingHandle, ! 327: efipci->device ); ! 328: bs->CloseProtocol ( efipci->device, &efi_pci_io_protocol_guid, ! 329: efidrv->driver.DriverBindingHandle, ! 330: efipci->device ); ! 331: free ( efipci ); ! 332: } ! 333: ! 334: /****************************************************************************** ! 335: * ! 336: * EFI PCI driver ! 337: * ! 338: ****************************************************************************** ! 339: */ ! 340: ! 341: /** ! 342: * Check to see if driver supports a device ! 343: * ! 344: * @v driver EFI driver ! 345: * @v device EFI device ! 346: * @v child Path to child device, if any ! 347: * @ret efirc EFI status code ! 348: */ ! 349: static EFI_STATUS EFIAPI ! 350: efipci_supported ( EFI_DRIVER_BINDING_PROTOCOL *driver, EFI_HANDLE device, ! 351: EFI_DEVICE_PATH_PROTOCOL *child ) { ! 352: struct efi_driver *efidrv = ! 353: container_of ( driver, struct efi_driver, driver ); ! 354: struct efi_pci_device *efipci; ! 355: EFI_STATUS efirc; ! 356: int rc; ! 357: ! 358: DBGCP ( efidrv, "EFIPCI DRIVER_SUPPORTED %p (%p)\n", device, child ); ! 359: ! 360: /* Create temporary corresponding PCI device, if any */ ! 361: efipci = efipci_create ( efidrv, device ); ! 362: if ( ! efipci ) { ! 363: /* Non-PCI devices are simply unsupported */ ! 364: efirc = EFI_UNSUPPORTED; ! 365: goto err_not_pci; ! 366: } ! 367: ! 368: /* Look for a driver */ ! 369: if ( ( rc = pci_find_driver ( &efipci->pci ) ) != 0 ) { ! 370: DBGCP ( efipci, "EFIPCI " PCI_FMT " has no driver\n", ! 371: PCI_ARGS ( &efipci->pci ) ); ! 372: efirc = EFI_UNSUPPORTED; ! 373: goto err_no_driver; ! 374: } ! 375: ! 376: DBGC ( efipci, "EFIPCI " PCI_FMT " is supported by driver \"%s\"\n", ! 377: PCI_ARGS ( &efipci->pci ), efipci->pci.id->name ); ! 378: ! 379: /* Destroy temporary PCI device */ ! 380: efipci_destroy ( efidrv, efipci ); ! 381: ! 382: return 0; ! 383: ! 384: err_no_driver: ! 385: efipci_destroy ( efidrv, efipci ); ! 386: err_not_pci: ! 387: return efirc; ! 388: } ! 389: ! 390: /** ! 391: * Attach driver to device ! 392: * ! 393: * @v driver EFI driver ! 394: * @v device EFI device ! 395: * @v child Path to child device, if any ! 396: * @ret efirc EFI status code ! 397: */ ! 398: static EFI_STATUS EFIAPI ! 399: efipci_start ( EFI_DRIVER_BINDING_PROTOCOL *driver, EFI_HANDLE device, ! 400: EFI_DEVICE_PATH_PROTOCOL *child ) { ! 401: struct efi_driver *efidrv = ! 402: container_of ( driver, struct efi_driver, driver ); ! 403: struct efi_pci_device *efipci; ! 404: EFI_STATUS efirc; ! 405: int rc; ! 406: ! 407: DBGC ( efidrv, "EFIPCI DRIVER_START %p (%p)\n", device, child ); ! 408: ! 409: /* Create corresponding PCI device */ ! 410: efipci = efipci_create ( efidrv, device ); ! 411: if ( ! efipci ) { ! 412: efirc = EFI_OUT_OF_RESOURCES; ! 413: goto err_create; ! 414: } ! 415: ! 416: /* Find driver */ ! 417: if ( ( rc = pci_find_driver ( &efipci->pci ) ) != 0 ) { ! 418: DBGC ( efipci, "EFIPCI " PCI_FMT " has no driver\n", ! 419: PCI_ARGS ( &efipci->pci ) ); ! 420: efirc = RC_TO_EFIRC ( rc ); ! 421: goto err_find_driver; ! 422: } ! 423: ! 424: /* Enable PCI device */ ! 425: if ( ( efirc = efipci_enable ( efipci ) ) != 0 ) ! 426: goto err_enable; ! 427: ! 428: /* Probe driver */ ! 429: if ( ( rc = pci_probe ( &efipci->pci ) ) != 0 ) { ! 430: DBGC ( efipci, "EFIPCI " PCI_FMT " could not probe driver " ! 431: "\"%s\": %s\n", PCI_ARGS ( &efipci->pci ), ! 432: efipci->pci.id->name, strerror ( rc ) ); ! 433: efirc = RC_TO_EFIRC ( rc ); ! 434: goto err_probe; ! 435: } ! 436: ! 437: return 0; ! 438: ! 439: pci_remove ( &efipci->pci ); ! 440: err_probe: ! 441: err_enable: ! 442: err_find_driver: ! 443: efipci_destroy ( efidrv, efipci ); ! 444: err_create: ! 445: return efirc; ! 446: } ! 447: ! 448: /** ! 449: * Detach driver from device ! 450: * ! 451: * @v driver EFI driver ! 452: * @v device EFI device ! 453: * @v pci PCI device ! 454: * @v num_children Number of child devices ! 455: * @v children List of child devices ! 456: * @ret efirc EFI status code ! 457: */ ! 458: static EFI_STATUS EFIAPI ! 459: efipci_stop ( EFI_DRIVER_BINDING_PROTOCOL *driver, EFI_HANDLE device, ! 460: UINTN num_children, EFI_HANDLE *children ) { ! 461: struct efi_driver *efidrv = ! 462: container_of ( driver, struct efi_driver, driver ); ! 463: struct efi_pci_device *efipci; ! 464: ! 465: DBGC ( efidrv, "EFIPCI DRIVER_STOP %p (%ld %p)\n", ! 466: device, ( ( unsigned long ) num_children ), children ); ! 467: ! 468: /* Find PCI device */ ! 469: efipci = efipci_find_efi ( device ); ! 470: if ( ! efipci ) { ! 471: DBGC ( efidrv, "EFIPCI device %p not started!\n", device ); ! 472: return EFI_INVALID_PARAMETER; ! 473: } ! 474: ! 475: /* Remove device */ ! 476: pci_remove ( &efipci->pci ); ! 477: ! 478: /* Delete EFI PCI device */ ! 479: efipci_destroy ( efidrv, efipci ); ! 480: ! 481: return 0; ! 482: } ! 483: ! 484: /** EFI PCI driver */ ! 485: static struct efi_driver efipci_driver = ! 486: EFI_DRIVER_INIT ( "PCI", efipci_supported, efipci_start, efipci_stop ); ! 487: ! 488: /** ! 489: * Install EFI PCI driver ! 490: * ! 491: */ ! 492: static void efipci_driver_startup ( void ) { ! 493: struct efi_driver *efidrv = &efipci_driver; ! 494: EFI_STATUS efirc; ! 495: ! 496: /* Install driver */ ! 497: if ( ( efirc = efi_driver_install ( efidrv ) ) != 0 ) { ! 498: DBGC ( efidrv, "EFIPCI could not install driver: %s\n", ! 499: efi_strerror ( efirc ) ); ! 500: return; ! 501: } ! 502: ! 503: DBGC ( efidrv, "EFIPCI driver installed\n" ); ! 504: } ! 505: ! 506: /** ! 507: * Shut down EFI PCI driver ! 508: * ! 509: * @v booting System is shutting down for OS boot ! 510: */ ! 511: static void efipci_driver_shutdown ( int booting __unused ) { ! 512: struct efi_driver *efidrv = &efipci_driver; ! 513: struct efi_pci_device *efipci; ! 514: struct efi_pci_device *tmp; ! 515: ! 516: /* Shut down any remaining devices */ ! 517: list_for_each_entry_safe ( efipci, tmp, &efi_pci_devices, list ) { ! 518: DBGC ( efipci, "EFIPCI " PCI_FMT " still active at shutdown; " ! 519: "forcing close\n", PCI_ARGS ( &efipci->pci ) ); ! 520: pci_remove ( &efipci->pci ); ! 521: efipci_destroy ( efidrv, efipci ); ! 522: } ! 523: } ! 524: ! 525: /** EFI PCI startup function */ ! 526: struct startup_fn startup_pci __startup_fn ( STARTUP_NORMAL ) = { ! 527: .startup = efipci_driver_startup, ! 528: .shutdown = efipci_driver_shutdown, ! 529: };
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.