1 /** <at> file 2 Implementation of driver entry point and driver binding protocol. 3 4 Copyright (c) 2004 - 2010, Intel Corporation. All rights reserved.<BR> 5 Copyright (c) 2011 - 2016, ARM Limited. All rights reserved. 6 7 This program and the accompanying materials are licensed 8 and made available under the terms and conditions of the BSD License which 9 accompanies this distribution. The full text of the license may be found at 10 http://opensource.org/licenses/bsd-license.php 11 12 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, 13 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. 14 15 **/ 16 17 #include <Library/NetLib.h> 18 #include <Library/DevicePathLib.h> 19 #include "MarvellYukon.h" 20 #include "if_msk.h" 21 22 STATIC LIST_ENTRY MarvellYukonDrvDataHead; 23 24 /** 25 Test to see if this driver supports ControllerHandle. This service 26 is called by the EFI boot service ConnectController(). In 27 order to make drivers as small as possible, there are a few calling 28 restrictions for this service. ConnectController() must 29 follow these calling restrictions. If any other agent wishes to call 30 Supported() it must also follow these calling restrictions. 31 32 <at> param This Protocol instance pointer. 33 <at> param ControllerHandle Handle of device to test. 34 <at> param RemainingDevicePath Optional parameter use to pick a specific child 35 device to start. 36 37 <at> retval EFI_SUCCESS This driver supports this device. 38 <at> retval EFI_ALREADY_STARTED This driver is already running on this device. 39 <at> retval other This driver does not support this device. 40 41 **/ 42 EFI_STATUS 43 EFIAPI 44 MarvellYukonDriverSupported ( 45 IN EFI_DRIVER_BINDING_PROTOCOL *This, 46 IN EFI_HANDLE Controller, 47 IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath 48 ) 49 { 50 EFI_STATUS Status; 51 EFI_PCI_IO_PROTOCOL *PciIo; 52 53 // 54 // Test that the PCI IO Protocol is attached to the controller handle and no other driver is consuming it 55 // 56 Status = gBS->OpenProtocol ( 57 Controller, 58 &gEfiPciIoProtocolGuid, 59 (VOID **) &PciIo, 60 This->DriverBindingHandle, 61 Controller, 62 EFI_OPEN_PROTOCOL_BY_DRIVER 63 ); 64 65 if (!EFI_ERROR (Status)) { 66 // 67 // Test whether the controller is on a supported NIC 68 // 69 Status = mskc_probe (PciIo); 70 if (EFI_ERROR (Status)) { 71 Status = EFI_UNSUPPORTED; 72 } else { 73 DEBUG ((EFI_D_NET, "Marvell Yukon: MarvellYukonDriverSupported: Supported Controller = %p\n", Controller)); 74 } 75 76 gBS->CloseProtocol ( 77 Controller, 78 &gEfiPciIoProtocolGuid, 79 This->DriverBindingHandle, 80 Controller 81 ); 82 } 83 84 return Status; 85 } 86 87 /** 88 Start this driver on Controller by opening PciIo and DevicePath protocols. 89 Initialize PXE structures, create a copy of the Controller Device Path with the 90 NIC's MAC address appended to it, install the NetworkInterfaceIdentifier protocol 91 on the newly created Device Path. 92 93 @param [in] pThis Protocol instance pointer. 94 @param [in] Controller Handle of device to work with. 95 @param [in] pRemainingDevicePath Not used, always produce all possible children. 96 97 @retval EFI_SUCCESS This driver is added to Controller. 98 @retval other This driver does not support this device. 99 100 **/ 101 EFI_STATUS 102 EFIAPI 103 MarvellYukonDriverStart ( 104 IN EFI_DRIVER_BINDING_PROTOCOL * pThis, 105 IN EFI_HANDLE Controller, 106 IN EFI_DEVICE_PATH_PROTOCOL * pRemainingDevicePath 107 ) 108 { 109 110 EFI_STATUS Status; 111 EFI_DEVICE_PATH_PROTOCOL *ParentDevicePath; 112 MAC_ADDR_DEVICE_PATH MacDeviceNode; 113 VOID *ChildPciIo; 114 YUKON_DRIVER *YukonDriver; 115 struct msk_softc *ScData; 116 EFI_PCI_IO_PROTOCOL *PciIo; 117 UINTN Port; 118 119 Status = gBS->OpenProtocol ( 120 Controller, 121 &gEfiPciIoProtocolGuid, 122 (VOID **) &PciIo, 123 pThis->DriverBindingHandle, 124 Controller, 125 EFI_OPEN_PROTOCOL_BY_DRIVER 126 ); 127 128 if (EFI_ERROR (Status)) { 129 DEBUG ((EFI_D_ERROR, "Marvell Yukon: OpenProtocol: EFI_PCI_IO_PROTOCOL ERROR Status = %r\n", Status)); 130 gBS->FreePool (YukonDriver); 131 return Status; 132 } 133 134 // 135 // Initialize Marvell Yukon controller 136 // Get number of ports and MAC address for each port 137 // 138 Status = mskc_attach (PciIo, &ScData); 139 if (EFI_ERROR (Status)) { 140 return Status; 141 } 142 143 Status = MarvellYukonAddControllerData (Controller, ScData); 144 if (EFI_ERROR (Status)) { 145 return Status; 146 } 147 148 for (Port = 0; Port < ScData->msk_num_port; Port++) { 149 150 Status = gBS->AllocatePool (EfiBootServicesData, 151 sizeof (YUKON_DRIVER), 152 (VOID**) &YukonDriver); 153 if (EFI_ERROR (Status)) { 154 DEBUG ((DEBUG_ERROR, "Marvell Yukon: AllocatePool() failed with Status = %r\n", Status)); 155 return Status; 156 } 157 158 if (ScData->msk_if[Port] == NULL) { 159 DEBUG ((DEBUG_ERROR, "Marvell Yukon: AllocatePool() failed with Status = %r\n", EFI_BAD_BUFFER_SIZE)); 160 return EFI_BAD_BUFFER_SIZE; 161 } 162 163 gBS->SetMem (YukonDriver, sizeof (YUKON_DRIVER), 0); 164 EfiInitializeLock (&YukonDriver->Lock, TPL_NOTIFY); 165 166 // 167 // Set the structure signature 168 // 169 YukonDriver->Signature = YUKON_DRIVER_SIGNATURE; 170 171 // 172 // Set MAC address 173 // 174 gBS->CopyMem (&YukonDriver->SnpMode.PermanentAddress, &(ScData->msk_if[Port])->MacAddress, 175 sizeof (EFI_MAC_ADDRESS)); 176 177 // 178 // Set Port number 179 // 180 YukonDriver->Port = Port; 181 182 // 183 // Initialize the simple network protocol 184 // 185 Status = InitializeSNPProtocol (YukonDriver); 186 187 if (EFI_ERROR (Status)) { 188 DEBUG ((DEBUG_ERROR, "Marvell Yukon: InitializeSNPProtocol: ERROR Status = %r\n", Status)); 189 gBS->CloseProtocol ( 190 Controller, 191 &gEfiPciIoProtocolGuid, 192 pThis->DriverBindingHandle, 193 Controller 194 ); 195 } 196 197 // 198 // Set Device Path 199 // 200 Status = gBS->OpenProtocol ( 201 Controller, 202 &gEfiDevicePathProtocolGuid, 203 (VOID **) &ParentDevicePath, 204 pThis->DriverBindingHandle, 205 Controller, 206 EFI_OPEN_PROTOCOL_GET_PROTOCOL 207 ); 208 209 if (EFI_ERROR (Status)) { 210 DEBUG ((DEBUG_ERROR, "Marvell Yukon: OpenProtocol:EFI_DEVICE_PATH_PROTOCOL error. Status = %r\n", Status)); 211 212 gBS->CloseProtocol ( 213 Controller, 214 &gEfiPciIoProtocolGuid, 215 pThis->DriverBindingHandle, 216 Controller 217 ); 218 219 gBS->FreePool (YukonDriver); 220 return Status; 221 } 222 223 gBS->SetMem (&MacDeviceNode, sizeof (MAC_ADDR_DEVICE_PATH), 0); 224 MacDeviceNode.Header.Type = MESSAGING_DEVICE_PATH; 225 MacDeviceNode.Header.SubType = MSG_MAC_ADDR_DP; 226 227 SetDevicePathNodeLength (&MacDeviceNode, sizeof (MacDeviceNode)); 228 229 // 230 // Assign fields for device path 231 // 232 gBS->CopyMem (&YukonDriver->SnpMode.CurrentAddress, &YukonDriver->SnpMode.PermanentAddress, 233 sizeof (EFI_MAC_ADDRESS)); 234 gBS->CopyMem (&MacDeviceNode.MacAddress, &YukonDriver->SnpMode.CurrentAddress, sizeof (EFI_MAC_ADDRESS)); 235 236 MacDeviceNode.IfType = YukonDriver->SnpMode.IfType; 237 YukonDriver->DevicePath = AppendDevicePathNode (ParentDevicePath, &MacDeviceNode.Header); 238 if (YukonDriver->DevicePath == NULL) { 239 DEBUG ((DEBUG_ERROR, "Marvell Yukon: AppendDevicePathNode: ERROR Status = %r\n", EFI_OUT_OF_RESOURCES)); 240 gBS->CloseProtocol ( 241 Controller, 242 &gEfiPciIoProtocolGuid, 243 pThis->DriverBindingHandle, 244 Controller 245 ); 246 gBS->FreePool (YukonDriver); 247 return EFI_OUT_OF_RESOURCES; 248 } 249 250 // 251 // Install both the simple network and device path protocols. 252 // 253 Status = gBS->InstallMultipleProtocolInterfaces ( 254 &YukonDriver->Controller, 255 &gEfiSimpleNetworkProtocolGuid, 256 &YukonDriver->Snp, 257 &gEfiDevicePathProtocolGuid, 258 YukonDriver->DevicePath, 259 NULL 260 ); 261 262 if (EFI_ERROR (Status)) { 263 DEBUG ((DEBUG_ERROR, "Marvell Yukon: InstallMultipleProtocolInterfaces error. Status = %r\n", Status)); 264 265 gBS->CloseProtocol ( 266 Controller, 267 &gEfiPciIoProtocolGuid, 268 pThis->DriverBindingHandle, 269 Controller 270 ); 271 272 gBS->FreePool (YukonDriver->DevicePath); 273 gBS->FreePool (YukonDriver); 274 return Status; 275 } else { 276 277 // 278 // Hook as a child device 279 // 280 Status = gBS->OpenProtocol (Controller, 281 &gEfiPciIoProtocolGuid, 282 &ChildPciIo, 283 pThis->DriverBindingHandle, 284 YukonDriver->Controller, 285 EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER); 286 if (EFI_ERROR (Status)) { 287 DEBUG ((DEBUG_ERROR, "Marvell Yukon: OpenProtocol: child controller error. Status = %r\n", Status)); 288 289 gBS->UninstallMultipleProtocolInterfaces ( 290 Controller, 291 &gEfiSimpleNetworkProtocolGuid, 292 &YukonDriver->Snp, 293 &gEfiDevicePathProtocolGuid, 294 YukonDriver->DevicePath, 295 NULL 296 ); 297 298 gBS->CloseProtocol ( 299 Controller, 300 &gEfiPciIoProtocolGuid, 301 pThis->DriverBindingHandle, 302 Controller 303 ); 304 305 gBS->FreePool (YukonDriver->DevicePath); 306 gBS->FreePool (YukonDriver); 307 return Status; 308 } else { 309 DEBUG ((DEBUG_NET, "Marvell Yukon: MarvellYukonDriverSupported: New Controller Handle = %p\n", 310 YukonDriver->Controller)); 311 } 312 313 Status = MarvellYukonAddControllerData (YukonDriver->Controller, ScData); 314 if (EFI_ERROR (Status)) { 315 DEBUG ((DEBUG_ERROR, "Marvell Yukon: Failed to register port %d with controller handle %p\n", Port, 316 YukonDriver->Controller)); 317 } 318 319 } 320 321 if (!EFI_ERROR (Status)) { 322 Status = gBS->CreateEvent (EVT_SIGNAL_EXIT_BOOT_SERVICES, TPL_CALLBACK, 323 &MarvellYukonNotifyExitBoot, YukonDriver, &YukonDriver->ExitBootEvent); 324 } 325 } 326 327 return Status; 328 } 329 330 /** 331 Stop this driver on Controller by removing NetworkInterfaceIdentifier protocol and 332 closing the DevicePath and PciIo protocols on Controller. 333 334 @param [in] pThis Protocol instance pointer. 335 @param [in] Controller Handle of device to stop driver on. 336 @param [in] NumberOfChildren How many children need to be stopped. 337 @param [in] pChildHandleBuffer Not used. 338 339 @retval EFI_SUCCESS This driver is removed Controller. 340 @retval EFI_DEVICE_ERROR The device could not be stopped due to a device error. 341 @retval other This driver was not removed from this device. 342 343 **/ 344 EFI_STATUS 345 EFIAPI 346 MarvellYukonDriverStop ( 347 IN EFI_DRIVER_BINDING_PROTOCOL * pThis, 348 IN EFI_HANDLE Controller, 349 IN UINTN NumberOfChildren, 350 IN EFI_HANDLE * ChildHandleBuffer 351 ) 352 { 353 EFI_SIMPLE_NETWORK_PROTOCOL *SimpleNetwork; 354 EFI_STATUS Status; 355 YUKON_DRIVER *YukonDriver; 356 EFI_TPL OldTpl; 357 UINTN ChildController; 358 struct msk_softc *ScData; 359 360 if (pThis == NULL) { 361 DEBUG ((EFI_D_ERROR, "Marvell Yukon: MarvellYukonDriverStop() failed with Status = %r\n", EFI_INVALID_PARAMETER)); 362 return EFI_INVALID_PARAMETER; 363 } 364 365 if (NumberOfChildren > 0 && ChildHandleBuffer == NULL) { 366 DEBUG ((EFI_D_ERROR, "Marvell Yukon: MarvellYukonDriverStop() failed with Status = %r\n", EFI_INVALID_PARAMETER)); 367 return EFI_INVALID_PARAMETER; 368 } 369 370 for (ChildController = 0; ChildController < NumberOfChildren; ChildController ++) { 371 372 Status = gBS->OpenProtocol ( 373 ChildHandleBuffer[ChildController], 374 &gEfiSimpleNetworkProtocolGuid, 375 (VOID **) &SimpleNetwork, 376 pThis->DriverBindingHandle, 377 Controller, 378 EFI_OPEN_PROTOCOL_GET_PROTOCOL 379 ); 380 381 if (!EFI_ERROR(Status)) { 382 383 YukonDriver = YUKON_DEV_FROM_THIS_SNP (SimpleNetwork); 384 385 Status = MarvellYukonGetControllerData (YukonDriver->Controller, &ScData); 386 if (EFI_ERROR (Status)) { 387 continue; 388 } 389 390 OldTpl = gBS->RaiseTPL (TPL_CALLBACK); 391 392 ASSERT (YukonDriver->Controller == ChildHandleBuffer[ChildController]); 393 if (YukonDriver->SnpMode.State != EfiSimpleNetworkStopped) { 394 395 // 396 // Device in use, cannot stop driver instance 397 // 398 Status = EFI_DEVICE_ERROR; 399 DEBUG ((DEBUG_ERROR, 400 "Marvell Yukon: MarvellYukonDriverStop: Error: SNP is not stopped. Status %r\n", Status)); 401 } else { 402 403 // 404 // Unhook the child controller 405 // 406 Status = gBS->CloseProtocol (Controller, 407 &gEfiPciIoProtocolGuid, 408 pThis->DriverBindingHandle, 409 YukonDriver->Controller); 410 411 if (EFI_ERROR (Status)) { 412 DEBUG ((DEBUG_ERROR, 413 "Marvell Yukon: MarvellYukonDriverStop:Close Child EfiPciIoProtocol error. Status %r\n", Status)); 414 } 415 416 Status = gBS->UninstallMultipleProtocolInterfaces ( 417 YukonDriver->Controller, 418 &gEfiSimpleNetworkProtocolGuid, 419 &YukonDriver->Snp, 420 &gEfiDevicePathProtocolGuid, 421 YukonDriver->DevicePath, 422 NULL 423 ); 424 425 if (EFI_ERROR(Status)){ 426 DEBUG ((DEBUG_ERROR, 427 "Marvell Yukon: MarvellYukonDriverStop:UninstallMultipleProtocolInterfaces error. Status %r\n", 428 Status)); 429 } 430 431 MarvellYukonDelControllerData (YukonDriver->Controller); 432 433 gBS->CloseEvent (YukonDriver->ExitBootEvent); 434 gBS->FreePool (YukonDriver->DevicePath); 435 gBS->FreePool (YukonDriver); 436 } 437 gBS->RestoreTPL (OldTpl); 438 } 439 } 440 441 Status = gBS->CloseProtocol ( 442 Controller, 443 &gEfiPciIoProtocolGuid, 444 pThis->DriverBindingHandle, 445 Controller 446 ); 447 448 if (EFI_ERROR (Status)) { 449 DEBUG ((DEBUG_ERROR, "Marvell Yukon: MarvellYukonDriverStop:Close EfiPciIoProtocol error. Status %r\n", Status)); 450 } 451 452 Status = MarvellYukonGetControllerData (Controller, &ScData); 453 if (EFI_ERROR (Status)) { 454 return Status; 455 } 456 457 mskc_detach (ScData); 458 gBS->FreePool (ScData); 459 Status = MarvellYukonDelControllerData (Controller); 460 461 return Status; 462 } 463 464 /** 465 Process exit boot event. 466 467 @param [in] Event Event id. 468 @param [in] Context Driver context. 469 470 **/ 471 VOID 472 EFIAPI 473 MarvellYukonNotifyExitBoot ( 474 IN EFI_EVENT Event, 475 IN VOID *Context 476 ) 477 { 478 YUKON_DRIVER *YukonDriver; 479 EFI_STATUS Status; 480 481 if (Context == NULL) { 482 DEBUG ((DEBUG_ERROR, 483 "Marvell Yukon: MarvellYukonNotifyExitBoot() failed with Status = %r\n", EFI_INVALID_PARAMETER)); 484 } else { 485 486 YukonDriver = Context; 487 488 if (YukonDriver->SnpMode.State != EfiSimpleNetworkStopped) { 489 Status = YukonDriver->Snp.Shutdown(&YukonDriver->Snp); 490 if (!EFI_ERROR (Status)) { 491 YukonDriver->Snp.Stop(&YukonDriver->Snp); 492 } 493 } 494 } 495 } 496 497 /** 498 Get driver's data structure associated with controller 499 500 @param [in] Controller Controller Id. 501 @param [out] Data Driver's data. 502 503 **/ 504 EFI_STATUS 505 EFIAPI 506 MarvellYukonGetControllerData ( 507 IN EFI_HANDLE Controller, 508 OUT struct msk_softc **Data 509 ) 510 { 511 MSK_LINKED_DRV_BUF *DrvNode; 512 EFI_STATUS Status; 513 514 Status = MarvellYukonFindControllerNode (Controller, &DrvNode); 515 if (!EFI_ERROR (Status)) { 516 *Data = DrvNode->Data; 517 } 518 return Status; 519 } 520 521 /** 522 Add driver's data structure associated with controller 523 524 @param [in] Controller Controller Id. 525 @param [in] Data Driver's data. 526 527 **/ 528 EFI_STATUS 529 EFIAPI 530 MarvellYukonAddControllerData ( 531 IN EFI_HANDLE Controller, 532 IN struct msk_softc *Data 533 ) 534 { 535 MSK_LINKED_DRV_BUF *DrvNode; 536 EFI_STATUS Status; 537 538 Status = MarvellYukonFindControllerNode (Controller, &DrvNode); 539 if (EFI_ERROR (Status)) { 540 Status = gBS->AllocatePool (EfiBootServicesData, 541 sizeof (MSK_LINKED_DRV_BUF), 542 (VOID**) &DrvNode); 543 if (!EFI_ERROR (Status)) { 544 DrvNode->Signature = MSK_DRV_SIGNATURE; 545 DrvNode->Controller = Controller; 546 DrvNode->Data = Data; 547 InsertTailList (&MarvellYukonDrvDataHead, &DrvNode->Link); 548 } 549 } else { 550 Status = EFI_ALREADY_STARTED; 551 } 552 553 return Status; 554 } 555 556 /** 557 Delete driver's data structure associated with controller 558 559 @param [in] Controller Controller Id. 560 561 **/ 562 EFI_STATUS 563 EFIAPI 564 MarvellYukonDelControllerData ( 565 IN EFI_HANDLE Controller 566 ) 567 { 568 MSK_LINKED_DRV_BUF *DrvNode; 569 EFI_STATUS Status; 570 571 Status = MarvellYukonFindControllerNode (Controller, &DrvNode); 572 if (!EFI_ERROR (Status)) { 573 RemoveEntryList (&DrvNode->Link); 574 gBS->FreePool (DrvNode); 575 } 576 577 return Status; 578 } 579 580 /** 581 Find node associated with controller 582 583 @param [in] Controller Controller Id. 584 @param [out] DrvLinkedBuff Controller's node. 585 586 **/ 587 EFI_STATUS 588 EFIAPI 589 MarvellYukonFindControllerNode ( 590 IN EFI_HANDLE Controller, 591 OUT MSK_LINKED_DRV_BUF **DrvLinkedBuff 592 ) 593 { 594 MSK_LINKED_DRV_BUF *DrvBuffNode; 595 EFI_STATUS Status; 596 LIST_ENTRY *Node; 597 598 Status = EFI_NOT_FOUND; 599 600 Node = GetFirstNode (&MarvellYukonDrvDataHead); 601 while (!IsNull (&MarvellYukonDrvDataHead, Node)) { 602 DrvBuffNode = MSK_DRV_INFO_FROM_THIS (Node); 603 if (DrvBuffNode->Controller == Controller) { 604 *DrvLinkedBuff = DrvBuffNode; 605 Status = EFI_SUCCESS; 606 break; 607 } 608 Node = GetNextNode (&MarvellYukonDrvDataHead, Node); 609 } 610 611 return Status; 612 } 613 614 // 615 // Simple Network Protocol Driver Global Variables 616 // 617 EFI_DRIVER_BINDING_PROTOCOL gMarvellYukonDriverBinding = { 618 MarvellYukonDriverSupported, 619 MarvellYukonDriverStart, 620 MarvellYukonDriverStop, 621 0xa, 622 NULL, 623 NULL 624 }; 625 626 /** 627 The Marvell Yukon driver entry point. 628 629 <at> param ImageHandle The driver image handle. 630 <at> param SystemTable The system table. 631 632 <at> retval EFI_SUCCESS Initialization routine has found and initialized 633 hardware successfully. 634 <at> retval Other Return value from HandleProtocol for 635 DeviceIoProtocol or LoadedImageProtocol 636 637 **/ 638 EFI_STATUS 639 EFIAPI 640 InitializeMarvellYukonDriver ( 641 IN EFI_HANDLE ImageHandle, 642 IN EFI_SYSTEM_TABLE *SystemTable 643 ) 644 { 645 EFI_STATUS Status; 646 647 DEBUG ((EFI_D_NET, "Marvell Yukon: InitializeMarvellYukonDriver()\n")); 648 649 if (SystemTable == NULL) { 650 DEBUG ((DEBUG_ERROR, 651 "Marvell Yukon: InitializeMarvellYukonDriver() failed with Status = %r\n", EFI_INVALID_PARAMETER)); 652 return EFI_INVALID_PARAMETER; 653 } 654 655 Status = EfiLibInstallDriverBindingComponentName2 ( 656 ImageHandle, 657 SystemTable, 658 &gMarvellYukonDriverBinding, 659 NULL, 660 &gSimpleNetworkComponentName, 661 &gSimpleNetworkComponentName2 662 ); 663 664 if (EFI_ERROR (Status)) { 665 DEBUG ((EFI_D_ERROR, "Marvell Yukon: InitializeMarvellYukonDriver(): Driver binding failed\n")); 666 return Status; 667 } 668 669 InitializeListHead (&MarvellYukonDrvDataHead); 670 671 return Status; 672 } 673