Fixed potential issues to release resources when error occurs.
[mirror_edk2.git] / MdeModulePkg / Bus / Pci / UndiRuntimeDxe / Init.c
CommitLineData
40834173 1/*++\r
2\r
41057d77 3Copyright (c) 2006 - 2007, Intel Corporation\r
68246fa8 4All rights reserved. This program and the accompanying materials\r
5are licensed and made available under the terms and conditions of the BSD License\r
6which accompanies this distribution. The full text of the license may be found at\r
7http://opensource.org/licenses/bsd-license.php\r
8\r
9THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
10WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
40834173 11\r
12Module Name:\r
13\r
14 init.c\r
15\r
16Abstract:\r
17\r
18 Initialization functions for EFI UNDI32 driver\r
19\r
20Revision History\r
21\r
22--*/\r
23\r
24#include "Undi32.h"\r
68246fa8 25#include <Library/BaseLib.h>\r
40834173 26//\r
27// Global Variables\r
28//\r
40834173 29\r
41057d77 30PXE_SW_UNDI *pxe_31 = NULL; // 3.1 entry\r
31UNDI32_DEV *UNDI32DeviceList[MAX_NIC_INTERFACES];\r
68246fa8 32NII_TABLE *UndiDataPointer = NULL;\r
40834173 33\r
34VOID\r
35EFIAPI\r
36UndiNotifyVirtual (\r
37 EFI_EVENT Event,\r
38 VOID *Context\r
39 )\r
40/*++\r
41\r
42Routine Description:\r
43\r
44 When address mapping changes to virtual this should make the appropriate\r
45 address conversions.\r
46\r
47Arguments:\r
48\r
49 (Standard Event handler)\r
50\r
51Returns:\r
52\r
53 None\r
54\r
55--*/\r
56// TODO: Context - add argument and description to function comment\r
57{\r
58 UINT16 Index;\r
59 VOID *Pxe31Pointer;\r
60\r
61 if (pxe_31 != NULL) {\r
62 Pxe31Pointer = (VOID *) pxe_31;\r
63\r
64 EfiConvertPointer (\r
65 EFI_OPTIONAL_POINTER,\r
66 (VOID **) &Pxe31Pointer\r
67 );\r
68\r
69 //\r
70 // UNDI32DeviceList is an array of pointers\r
71 //\r
72 for (Index = 0; Index < pxe_31->IFcnt; Index++) {\r
73 UNDI32DeviceList[Index]->NIIProtocol_31.ID = (UINT64) (UINTN) Pxe31Pointer;\r
74 EfiConvertPointer (\r
75 EFI_OPTIONAL_POINTER,\r
76 (VOID **) &(UNDI32DeviceList[Index])\r
77 );\r
78 }\r
79\r
80 EfiConvertPointer (\r
81 EFI_OPTIONAL_POINTER,\r
82 (VOID **) &(pxe_31->EntryPoint)\r
83 );\r
84 pxe_31 = Pxe31Pointer;\r
85 }\r
86\r
87 for (Index = 0; Index <= PXE_OPCODE_LAST_VALID; Index++) {\r
88 EfiConvertPointer (\r
89 EFI_OPTIONAL_POINTER,\r
90 (VOID **) &api_table[Index].api_ptr\r
91 );\r
92 }\r
93}\r
94\r
95VOID\r
96EFIAPI\r
97UndiNotifyExitBs (\r
98 EFI_EVENT Event,\r
99 VOID *Context\r
100 )\r
101/*++\r
102\r
103Routine Description:\r
104\r
68246fa8 105 When EFI is shuting down the boot services, we need to install a\r
40834173 106 configuration table for UNDI to work at runtime!\r
107\r
108Arguments:\r
109\r
110 (Standard Event handler)\r
111\r
112Returns:\r
113\r
114 None\r
115\r
116--*/\r
117// TODO: Context - add argument and description to function comment\r
118{\r
119 InstallConfigTable ();\r
120}\r
121//\r
122// UNDI Class Driver Global Variables\r
123//\r
124EFI_DRIVER_BINDING_PROTOCOL gUndiDriverBinding = {\r
125 UndiDriverSupported,\r
126 UndiDriverStart,\r
127 UndiDriverStop,\r
128 0xa,\r
129 NULL,\r
130 NULL\r
131};\r
132\r
133\r
134EFI_STATUS\r
135EFIAPI\r
136UndiDriverSupported (\r
137 IN EFI_DRIVER_BINDING_PROTOCOL *This,\r
138 IN EFI_HANDLE Controller,\r
139 IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath\r
140 )\r
141/*++\r
142\r
143Routine Description:\r
144\r
145 Test to see if this driver supports ControllerHandle. Any ControllerHandle\r
146 than contains a DevicePath, PciIo protocol, Class code of 2, Vendor ID of 0x8086,\r
147 and DeviceId of (D100_DEVICE_ID || D102_DEVICE_ID || ICH3_DEVICE_ID_1 ||\r
148 ICH3_DEVICE_ID_2 || ICH3_DEVICE_ID_3 || ICH3_DEVICE_ID_4 || ICH3_DEVICE_ID_5 ||\r
149 ICH3_DEVICE_ID_6 || ICH3_DEVICE_ID_7 || ICH3_DEVICE_ID_8) can be supported.\r
150\r
151Arguments:\r
152\r
153 This - Protocol instance pointer.\r
68246fa8 154\r
40834173 155 Controller - Handle of device to test.\r
68246fa8 156\r
40834173 157 RemainingDevicePath - Not used.\r
158\r
159Returns:\r
160\r
161 EFI_SUCCESS - This driver supports this device.\r
68246fa8 162\r
40834173 163 other - This driver does not support this device.\r
164\r
165--*/\r
166{\r
167 EFI_STATUS Status;\r
168 EFI_PCI_IO_PROTOCOL *PciIo;\r
169 PCI_TYPE00 Pci;\r
170\r
171 Status = gBS->OpenProtocol (\r
172 Controller,\r
173 &gEfiDevicePathProtocolGuid,\r
174 NULL,\r
175 This->DriverBindingHandle,\r
176 Controller,\r
177 EFI_OPEN_PROTOCOL_TEST_PROTOCOL\r
178 );\r
179 if (EFI_ERROR (Status)) {\r
180 return Status;\r
181 }\r
182\r
183 Status = gBS->OpenProtocol (\r
184 Controller,\r
185 &gEfiPciIoProtocolGuid,\r
186 (VOID **) &PciIo,\r
187 This->DriverBindingHandle,\r
188 Controller,\r
189 EFI_OPEN_PROTOCOL_BY_DRIVER\r
190 );\r
191 if (EFI_ERROR (Status)) {\r
192 return Status;\r
193 }\r
194\r
195 Status = PciIo->Pci.Read (\r
196 PciIo,\r
197 EfiPciIoWidthUint8,\r
198 0,\r
199 sizeof (PCI_CONFIG_HEADER),\r
200 &Pci\r
201 );\r
202\r
203 if (!EFI_ERROR (Status)) {\r
204 Status = EFI_UNSUPPORTED;\r
205\r
206 if (Pci.Hdr.ClassCode[2] == 0x02 && Pci.Hdr.VendorId == PCI_VENDOR_ID_INTEL) {\r
207 switch (Pci.Hdr.DeviceId) {\r
208 case D100_DEVICE_ID:\r
209 case D102_DEVICE_ID:\r
210 case ICH3_DEVICE_ID_1:\r
211 case ICH3_DEVICE_ID_2:\r
212 case ICH3_DEVICE_ID_3:\r
213 case ICH3_DEVICE_ID_4:\r
214 case ICH3_DEVICE_ID_5:\r
215 case ICH3_DEVICE_ID_6:\r
216 case ICH3_DEVICE_ID_7:\r
217 case ICH3_DEVICE_ID_8:\r
218 case 0x1039:\r
219 case 0x103A:\r
220 case 0x103B:\r
221 case 0x103C:\r
222 case 0x103D:\r
223 case 0x103E:\r
224 case 0x1050:\r
225 case 0x1051:\r
226 case 0x1052:\r
227 case 0x1053:\r
228 case 0x1054:\r
229 case 0x1055:\r
230 case 0x1056:\r
231 case 0x1057:\r
232 case 0x1059:\r
233 case 0x1064:\r
234 Status = EFI_SUCCESS;\r
235 }\r
236 }\r
237 }\r
238\r
239 gBS->CloseProtocol (\r
240 Controller,\r
241 &gEfiPciIoProtocolGuid,\r
242 This->DriverBindingHandle,\r
243 Controller\r
244 );\r
245\r
246 return Status;\r
247}\r
248\r
249EFI_STATUS\r
250EFIAPI\r
251UndiDriverStart (\r
252 IN EFI_DRIVER_BINDING_PROTOCOL *This,\r
253 IN EFI_HANDLE Controller,\r
254 IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath\r
255 )\r
256/*++\r
257\r
258Routine Description:\r
259\r
260 Start this driver on Controller by opening PciIo and DevicePath protocol.\r
261 Initialize PXE structures, create a copy of the Controller Device Path with the\r
262 NIC's MAC address appended to it, install the NetworkInterfaceIdentifier protocol\r
263 on the newly created Device Path.\r
264\r
265Arguments:\r
266\r
267 This - Protocol instance pointer.\r
68246fa8 268\r
40834173 269 Controller - Handle of device to work with.\r
68246fa8 270\r
40834173 271 RemainingDevicePath - Not used, always produce all possible children.\r
272\r
273Returns:\r
274\r
275 EFI_SUCCESS - This driver is added to Controller.\r
68246fa8 276\r
40834173 277 other - This driver does not support this device.\r
278\r
279--*/\r
280{\r
281 EFI_STATUS Status;\r
282 EFI_DEVICE_PATH_PROTOCOL *UndiDevicePath;\r
283 PCI_CONFIG_HEADER *CfgHdr;\r
284 UNDI32_DEV *UNDI32Device;\r
285 UINT16 NewCommand;\r
286 UINT8 *TmpPxePointer;\r
287 EFI_PCI_IO_PROTOCOL *PciIoFncs;\r
68246fa8 288 UINTN Len;\r
96f6af14 289 UINT64 Supports;\r
6a6d955c 290 BOOLEAN PciAttributesSaved;\r
40834173 291\r
292 Status = gBS->OpenProtocol (\r
293 Controller,\r
294 &gEfiPciIoProtocolGuid,\r
295 (VOID **) &PciIoFncs,\r
296 This->DriverBindingHandle,\r
297 Controller,\r
298 EFI_OPEN_PROTOCOL_BY_DRIVER\r
299 );\r
300\r
301 if (EFI_ERROR (Status)) {\r
302 return Status;\r
303 }\r
304\r
305 Status = gBS->OpenProtocol (\r
306 Controller,\r
307 &gEfiDevicePathProtocolGuid,\r
308 (VOID **) &UndiDevicePath,\r
309 This->DriverBindingHandle,\r
310 Controller,\r
311 EFI_OPEN_PROTOCOL_BY_DRIVER\r
312 );\r
313\r
314 if (EFI_ERROR (Status)) {\r
315 gBS->CloseProtocol (\r
316 Controller,\r
317 &gEfiPciIoProtocolGuid,\r
318 This->DriverBindingHandle,\r
319 Controller\r
320 );\r
321\r
322 return Status;\r
323 }\r
324\r
6a6d955c 325 PciAttributesSaved = FALSE;\r
326\r
40834173 327 Status = gBS->AllocatePool (\r
328 EfiRuntimeServicesData,\r
329 sizeof (UNDI32_DEV),\r
330 (VOID **) &UNDI32Device\r
331 );\r
332\r
333 if (EFI_ERROR (Status)) {\r
334 goto UndiError;\r
335 }\r
336\r
337 ZeroMem ((CHAR8 *) UNDI32Device, sizeof (UNDI32_DEV));\r
338\r
68246fa8 339 //\r
340 // Get original PCI attributes\r
341 //\r
342 Status = PciIoFncs->Attributes (\r
343 PciIoFncs,\r
344 EfiPciIoAttributeOperationGet,\r
345 0,\r
346 &UNDI32Device->NicInfo.OriginalPciAttributes\r
347 );\r
348\r
349 if (EFI_ERROR (Status)) {\r
6a6d955c 350 goto UndiErrorDeleteDevice;\r
68246fa8 351 }\r
6a6d955c 352 PciAttributesSaved = TRUE;\r
68246fa8 353\r
40834173 354 //\r
355 // allocate and initialize both (old and new) the !pxe structures here,\r
356 // there should only be one copy of each of these structure for any number\r
357 // of NICs this undi supports. Also, these structures need to be on a\r
358 // paragraph boundary as per the spec. so, while allocating space for these,\r
359 // make sure that there is space for 2 !pxe structures (old and new) and a\r
360 // 32 bytes padding for alignment adjustment (in case)\r
361 //\r
362 TmpPxePointer = NULL;\r
363 if (pxe_31 == NULL) {\r
364 Status = gBS->AllocatePool (\r
365 EfiRuntimeServicesData,\r
366 (sizeof (PXE_SW_UNDI) + sizeof (PXE_SW_UNDI) + 32),\r
367 (VOID **) &TmpPxePointer\r
368 );\r
369\r
370 if (EFI_ERROR (Status)) {\r
371 goto UndiErrorDeleteDevice;\r
372 }\r
373\r
374 ZeroMem (\r
375 TmpPxePointer,\r
376 sizeof (PXE_SW_UNDI) + sizeof (PXE_SW_UNDI) + 32\r
377 );\r
378 //\r
379 // check for paragraph alignment here, assuming that the pointer is\r
380 // already 8 byte aligned.\r
381 //\r
382 if (((UINTN) TmpPxePointer & 0x0F) != 0) {\r
383 pxe_31 = (PXE_SW_UNDI *) ((UINTN) (TmpPxePointer + 8));\r
384 } else {\r
385 pxe_31 = (PXE_SW_UNDI *) TmpPxePointer;\r
386 }\r
40834173 387\r
41057d77 388 PxeStructInit (pxe_31);\r
40834173 389 }\r
390\r
40834173 391 UNDI32Device->NIIProtocol_31.ID = (UINT64) (UINTN) (pxe_31);\r
392\r
393 Status = PciIoFncs->Attributes (\r
394 PciIoFncs,\r
96f6af14
LG
395 EfiPciIoAttributeOperationSupported,\r
396 0,\r
397 &Supports\r
40834173 398 );\r
96f6af14
LG
399 if (!EFI_ERROR (Status)) {\r
400 Supports &= EFI_PCI_DEVICE_ENABLE;\r
401 Status = PciIoFncs->Attributes (\r
402 PciIoFncs,\r
403 EfiPciIoAttributeOperationEnable,\r
404 Supports,\r
405 NULL\r
406 );\r
407 }\r
40834173 408 //\r
409 // Read all the registers from device's PCI Configuration space\r
410 //\r
411 Status = PciIoFncs->Pci.Read (\r
412 PciIoFncs,\r
413 EfiPciIoWidthUint32,\r
414 0,\r
415 MAX_PCI_CONFIG_LEN,\r
416 &UNDI32Device->NicInfo.Config\r
417 );\r
418\r
419 CfgHdr = (PCI_CONFIG_HEADER *) &(UNDI32Device->NicInfo.Config[0]);\r
420\r
421 //\r
422 // make sure that this device is a PCI bus master\r
423 //\r
424\r
425 NewCommand = (UINT16) (CfgHdr->Command | PCI_COMMAND_MASTER | PCI_COMMAND_IO);\r
426 if (CfgHdr->Command != NewCommand) {\r
427 PciIoFncs->Pci.Write (\r
428 PciIoFncs,\r
429 EfiPciIoWidthUint16,\r
430 PCI_COMMAND,\r
431 1,\r
432 &NewCommand\r
433 );\r
434 CfgHdr->Command = NewCommand;\r
435 }\r
436\r
437 //\r
438 // make sure that the latency timer is at least 32\r
439 //\r
440 if (CfgHdr->LatencyTimer < 32) {\r
441 CfgHdr->LatencyTimer = 32;\r
442 PciIoFncs->Pci.Write (\r
443 PciIoFncs,\r
444 EfiPciIoWidthUint8,\r
445 PCI_LATENCY_TIMER,\r
446 1,\r
447 &CfgHdr->LatencyTimer\r
448 );\r
449 }\r
450 //\r
451 // the IfNum index for the current interface will be the total number\r
452 // of interfaces initialized so far\r
453 //\r
40834173 454 UNDI32Device->NIIProtocol_31.IfNum = pxe_31->IFcnt;\r
455\r
40834173 456 PxeUpdate (&UNDI32Device->NicInfo, pxe_31);\r
457\r
41057d77 458 UNDI32Device->NicInfo.Io_Function = PciIoFncs;\r
459 UNDI32DeviceList[UNDI32Device->NIIProtocol_31.IfNum] = UNDI32Device;\r
460 UNDI32Device->Undi32BaseDevPath = UndiDevicePath;\r
40834173 461\r
462 Status = AppendMac2DevPath (\r
463 &UNDI32Device->Undi32DevPath,\r
464 UNDI32Device->Undi32BaseDevPath,\r
465 &UNDI32Device->NicInfo\r
466 );\r
467\r
468 if (Status != 0) {\r
469 goto UndiErrorDeletePxe;\r
470 }\r
471\r
472 UNDI32Device->Signature = UNDI_DEV_SIGNATURE;\r
473\r
40834173 474 UNDI32Device->NIIProtocol_31.Revision = EFI_NETWORK_INTERFACE_IDENTIFIER_PROTOCOL_REVISION_31;\r
475 UNDI32Device->NIIProtocol_31.Type = EfiNetworkInterfaceUndi;\r
476 UNDI32Device->NIIProtocol_31.MajorVer = PXE_ROMID_MAJORVER;\r
477 UNDI32Device->NIIProtocol_31.MinorVer = PXE_ROMID_MINORVER_31;\r
478 UNDI32Device->NIIProtocol_31.ImageSize = 0;\r
479 UNDI32Device->NIIProtocol_31.ImageAddr = 0;\r
480 UNDI32Device->NIIProtocol_31.Ipv6Supported = FALSE;\r
481\r
482 UNDI32Device->NIIProtocol_31.StringId[0] = 'U';\r
483 UNDI32Device->NIIProtocol_31.StringId[1] = 'N';\r
484 UNDI32Device->NIIProtocol_31.StringId[2] = 'D';\r
485 UNDI32Device->NIIProtocol_31.StringId[3] = 'I';\r
486\r
487 UNDI32Device->DeviceHandle = NULL;\r
488\r
489 //\r
490 // install both the 3.0 and 3.1 NII protocols.\r
491 //\r
492 Status = gBS->InstallMultipleProtocolInterfaces (\r
493 &UNDI32Device->DeviceHandle,\r
494 &gEfiNetworkInterfaceIdentifierProtocolGuid_31,\r
495 &UNDI32Device->NIIProtocol_31,\r
40834173 496 &gEfiDevicePathProtocolGuid,\r
497 UNDI32Device->Undi32DevPath,\r
498 NULL\r
499 );\r
500\r
501 if (EFI_ERROR (Status)) {\r
502 goto UndiErrorDeleteDevicePath;\r
503 }\r
504\r
505 //\r
68246fa8 506 // if the table exists, free it and alloc again, or alloc it directly\r
40834173 507 //\r
68246fa8 508 if (UndiDataPointer != NULL) {\r
509 Status = gBS->FreePool(UndiDataPointer);\r
40834173 510 }\r
511 if (EFI_ERROR (Status)) {\r
512 goto UndiErrorDeleteDevicePath;\r
513 }\r
514\r
68246fa8 515 Len = (pxe_31->IFcnt * sizeof (NII_ENTRY)) + sizeof (UndiDataPointer);\r
516 Status = gBS->AllocatePool (EfiRuntimeServicesData, Len, (VOID **) &UndiDataPointer);\r
40834173 517\r
518 if (EFI_ERROR (Status)) {\r
519 goto UndiErrorAllocDataPointer;\r
520 }\r
68246fa8 521\r
40834173 522 //\r
523 // Open For Child Device\r
524 //\r
525 Status = gBS->OpenProtocol (\r
526 Controller,\r
527 &gEfiPciIoProtocolGuid,\r
528 (VOID **) &PciIoFncs,\r
529 This->DriverBindingHandle,\r
530 UNDI32Device->DeviceHandle,\r
531 EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER\r
532 );\r
533\r
534 return EFI_SUCCESS;\r
535UndiErrorAllocDataPointer:\r
536 gBS->UninstallMultipleProtocolInterfaces (\r
537 &UNDI32Device->DeviceHandle,\r
538 &gEfiNetworkInterfaceIdentifierProtocolGuid_31,\r
539 &UNDI32Device->NIIProtocol_31,\r
40834173 540 &gEfiDevicePathProtocolGuid,\r
541 UNDI32Device->Undi32DevPath,\r
542 NULL\r
543 );\r
544\r
545UndiErrorDeleteDevicePath:\r
41057d77 546 UNDI32DeviceList[UNDI32Device->NIIProtocol_31.IfNum] = NULL;\r
40834173 547 gBS->FreePool (UNDI32Device->Undi32DevPath);\r
548\r
549UndiErrorDeletePxe:\r
40834173 550 PxeUpdate (NULL, pxe_31);\r
551 if (TmpPxePointer != NULL) {\r
552 gBS->FreePool (TmpPxePointer);\r
553\r
554 }\r
555\r
556UndiErrorDeleteDevice:\r
6a6d955c 557 if (PciAttributesSaved == TRUE) {\r
558 //\r
559 // Restore original PCI attributes\r
560 //\r
561 PciIoFncs->Attributes (\r
562 PciIoFncs,\r
563 EfiPciIoAttributeOperationSet,\r
564 UNDI32Device->NicInfo.OriginalPciAttributes,\r
565 NULL\r
566 );\r
567 }\r
68246fa8 568\r
40834173 569 gBS->FreePool (UNDI32Device);\r
570\r
571UndiError:\r
572 gBS->CloseProtocol (\r
573 Controller,\r
574 &gEfiDevicePathProtocolGuid,\r
575 This->DriverBindingHandle,\r
576 Controller\r
577 );\r
578\r
579 gBS->CloseProtocol (\r
580 Controller,\r
581 &gEfiPciIoProtocolGuid,\r
582 This->DriverBindingHandle,\r
583 Controller\r
584 );\r
585\r
586 return Status;\r
587}\r
588\r
589EFI_STATUS\r
590EFIAPI\r
591UndiDriverStop (\r
592 IN EFI_DRIVER_BINDING_PROTOCOL *This,\r
593 IN EFI_HANDLE Controller,\r
594 IN UINTN NumberOfChildren,\r
595 IN EFI_HANDLE *ChildHandleBuffer\r
596 )\r
597/*++\r
598\r
599Routine Description:\r
600 Stop this driver on Controller by removing NetworkInterfaceIdentifier protocol and\r
601 closing the DevicePath and PciIo protocols on Controller.\r
602\r
603Arguments:\r
604 This - Protocol instance pointer.\r
605 Controller - Handle of device to stop driver on.\r
606 NumberOfChildren - How many children need to be stopped.\r
607 ChildHandleBuffer - Not used.\r
608\r
609Returns:\r
610 EFI_SUCCESS - This driver is removed Controller.\r
611 other - This driver was not removed from this device.\r
612\r
613--*/\r
614// TODO: EFI_DEVICE_ERROR - add return value to function comment\r
615{\r
616 EFI_STATUS Status;\r
617 BOOLEAN AllChildrenStopped;\r
618 UINTN Index;\r
619 UNDI32_DEV *UNDI32Device;\r
620 EFI_NETWORK_INTERFACE_IDENTIFIER_PROTOCOL *NIIProtocol;\r
621 EFI_PCI_IO_PROTOCOL *PciIo;\r
622\r
623 //\r
624 // Complete all outstanding transactions to Controller.\r
625 // Don't allow any new transaction to Controller to be started.\r
626 //\r
627 if (NumberOfChildren == 0) {\r
628\r
629 //\r
630 // Close the bus driver\r
631 //\r
632 Status = gBS->CloseProtocol (\r
633 Controller,\r
634 &gEfiDevicePathProtocolGuid,\r
635 This->DriverBindingHandle,\r
636 Controller\r
637 );\r
638\r
639 Status = gBS->CloseProtocol (\r
640 Controller,\r
641 &gEfiPciIoProtocolGuid,\r
642 This->DriverBindingHandle,\r
643 Controller\r
644 );\r
645\r
646 return Status;\r
647 }\r
648\r
649 AllChildrenStopped = TRUE;\r
650\r
651 for (Index = 0; Index < NumberOfChildren; Index++) {\r
652\r
653 Status = gBS->OpenProtocol (\r
654 ChildHandleBuffer[Index],\r
41057d77 655 &gEfiNetworkInterfaceIdentifierProtocolGuid_31,\r
40834173 656 (VOID **) &NIIProtocol,\r
657 This->DriverBindingHandle,\r
658 Controller,\r
659 EFI_OPEN_PROTOCOL_GET_PROTOCOL\r
660 );\r
661 if (!EFI_ERROR (Status)) {\r
662\r
663 UNDI32Device = UNDI_DEV_FROM_THIS (NIIProtocol);\r
664\r
68246fa8 665 //\r
666 // Restore original PCI attributes\r
667 //\r
668 Status = UNDI32Device->NicInfo.Io_Function->Attributes (\r
669 UNDI32Device->NicInfo.Io_Function,\r
670 EfiPciIoAttributeOperationSet,\r
671 UNDI32Device->NicInfo.OriginalPciAttributes,\r
672 NULL\r
673 );\r
674 ASSERT_EFI_ERROR (Status);\r
675\r
40834173 676 Status = gBS->CloseProtocol (\r
677 Controller,\r
678 &gEfiPciIoProtocolGuid,\r
679 This->DriverBindingHandle,\r
680 ChildHandleBuffer[Index]\r
681 );\r
682\r
683 Status = gBS->UninstallMultipleProtocolInterfaces (\r
684 ChildHandleBuffer[Index],\r
685 &gEfiDevicePathProtocolGuid,\r
686 UNDI32Device->Undi32DevPath,\r
687 &gEfiNetworkInterfaceIdentifierProtocolGuid_31,\r
688 &UNDI32Device->NIIProtocol_31,\r
40834173 689 NULL\r
690 );\r
691\r
692 if (EFI_ERROR (Status)) {\r
693 gBS->OpenProtocol (\r
694 Controller,\r
695 &gEfiPciIoProtocolGuid,\r
696 (VOID **) &PciIo,\r
697 This->DriverBindingHandle,\r
698 ChildHandleBuffer[Index],\r
699 EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER\r
700 );\r
701 } else {\r
702 gBS->FreePool (UNDI32Device->Undi32DevPath);\r
703 gBS->FreePool (UNDI32Device);\r
704 }\r
705 }\r
706\r
707 if (EFI_ERROR (Status)) {\r
708 AllChildrenStopped = FALSE;\r
709 }\r
710 }\r
711\r
712 if (!AllChildrenStopped) {\r
713 return EFI_DEVICE_ERROR;\r
714 }\r
715\r
716 return EFI_SUCCESS;\r
717\r
718}\r
719\r
720VOID\r
721TmpDelay (\r
722 IN UINT64 UnqId,\r
723 IN UINTN MicroSeconds\r
724 )\r
725/*++\r
726\r
727Routine Description:\r
728\r
729 Use the EFI boot services to produce a pause. This is also the routine which\r
730 gets replaced during RunTime by the O/S in the NIC_DATA_INSTANCE so it can\r
731 do it's own pause.\r
732\r
733Arguments:\r
734\r
735 UnqId - Runtime O/S routine might use this, this temp routine does not use it\r
68246fa8 736\r
40834173 737 MicroSeconds - Determines the length of pause.\r
738\r
739Returns:\r
740\r
741 none\r
742\r
743--*/\r
744{\r
745 gBS->Stall ((UINT32) MicroSeconds);\r
746}\r
747\r
748VOID\r
749TmpMemIo (\r
750 IN UINT64 UnqId,\r
751 IN UINT8 ReadWrite,\r
752 IN UINT8 Len,\r
753 IN UINT64 Port,\r
754 IN UINT64 BuffAddr\r
755 )\r
756/*++\r
757\r
758Routine Description:\r
759\r
760 Use the PCI IO abstraction to issue memory or I/O reads and writes. This is also the routine which\r
761 gets replaced during RunTime by the O/S in the NIC_DATA_INSTANCE so it can do it's own I/O abstractions.\r
762\r
763Arguments:\r
764\r
765 UnqId - Runtime O/S routine may use this field, this temp routine does not.\r
68246fa8 766\r
40834173 767 ReadWrite - Determine if it is an I/O or Memory Read/Write Operation.\r
68246fa8 768\r
40834173 769 Len - Determines the width of the data operation.\r
68246fa8 770\r
40834173 771 Port - What port to Read/Write from.\r
68246fa8 772\r
40834173 773 BuffAddr - Address to read to or write from.\r
774\r
775Returns:\r
776\r
777 none\r
778\r
779--*/\r
780{\r
781 EFI_PCI_IO_PROTOCOL_WIDTH Width;\r
782 NIC_DATA_INSTANCE *AdapterInfo;\r
783\r
784 Width = (EFI_PCI_IO_PROTOCOL_WIDTH) 0;\r
785 AdapterInfo = (NIC_DATA_INSTANCE *) (UINTN) UnqId;\r
786 switch (Len) {\r
787 case 2:\r
788 Width = (EFI_PCI_IO_PROTOCOL_WIDTH) 1;\r
789 break;\r
790\r
791 case 4:\r
792 Width = (EFI_PCI_IO_PROTOCOL_WIDTH) 2;\r
793 break;\r
794\r
795 case 8:\r
796 Width = (EFI_PCI_IO_PROTOCOL_WIDTH) 3;\r
797 break;\r
798 }\r
799\r
800 switch (ReadWrite) {\r
801 case PXE_IO_READ:\r
802 AdapterInfo->Io_Function->Io.Read (\r
803 AdapterInfo->Io_Function,\r
804 Width,\r
805 1,\r
806 Port,\r
807 1,\r
808 (VOID *) (UINTN) (BuffAddr)\r
809 );\r
810 break;\r
811\r
812 case PXE_IO_WRITE:\r
813 AdapterInfo->Io_Function->Io.Write (\r
814 AdapterInfo->Io_Function,\r
815 Width,\r
816 1,\r
817 Port,\r
818 1,\r
819 (VOID *) (UINTN) (BuffAddr)\r
820 );\r
821 break;\r
822\r
823 case PXE_MEM_READ:\r
824 AdapterInfo->Io_Function->Mem.Read (\r
825 AdapterInfo->Io_Function,\r
826 Width,\r
827 0,\r
828 Port,\r
829 1,\r
830 (VOID *) (UINTN) (BuffAddr)\r
831 );\r
832 break;\r
833\r
834 case PXE_MEM_WRITE:\r
835 AdapterInfo->Io_Function->Mem.Write (\r
836 AdapterInfo->Io_Function,\r
837 Width,\r
838 0,\r
839 Port,\r
840 1,\r
841 (VOID *) (UINTN) (BuffAddr)\r
842 );\r
843 break;\r
844 }\r
845\r
846 return ;\r
847}\r
848\r
849EFI_STATUS\r
850AppendMac2DevPath (\r
851 IN OUT EFI_DEVICE_PATH_PROTOCOL **DevPtr,\r
852 IN EFI_DEVICE_PATH_PROTOCOL *BaseDevPtr,\r
853 IN NIC_DATA_INSTANCE *AdapterInfo\r
854 )\r
855/*++\r
856\r
857Routine Description:\r
858\r
859 Using the NIC data structure information, read the EEPROM to get the MAC address and then allocate space\r
860 for a new devicepath (**DevPtr) which will contain the original device path the NIC was found on (*BaseDevPtr)\r
861 and an added MAC node.\r
862\r
863Arguments:\r
864\r
865 DevPtr - Pointer which will point to the newly created device path with the MAC node attached.\r
68246fa8 866\r
40834173 867 BaseDevPtr - Pointer to the device path which the UNDI device driver is latching on to.\r
68246fa8 868\r
40834173 869 AdapterInfo - Pointer to the NIC data structure information which the UNDI driver is layering on..\r
870\r
871Returns:\r
872\r
873 EFI_SUCCESS - A MAC address was successfully appended to the Base Device Path.\r
68246fa8 874\r
40834173 875 other - Not enough resources available to create new Device Path node.\r
876\r
877--*/\r
878{\r
879 EFI_MAC_ADDRESS MACAddress;\r
880 PCI_CONFIG_HEADER *CfgHdr;\r
881 INT32 Val;\r
882 INT32 Index;\r
883 INT32 Index2;\r
884 UINT8 AddrLen;\r
885 MAC_ADDR_DEVICE_PATH MacAddrNode;\r
886 EFI_DEVICE_PATH_PROTOCOL *EndNode;\r
887 UINT8 *DevicePtr;\r
888 UINT16 TotalPathLen;\r
889 UINT16 BasePathLen;\r
890 EFI_STATUS Status;\r
891\r
892 //\r
893 // set the environment ready (similar to UNDI_Start call) so that we can\r
894 // execute the other UNDI_ calls to get the mac address\r
895 // we are using undi 3.1 style\r
896 //\r
897 AdapterInfo->Delay = TmpDelay;\r
898 AdapterInfo->Virt2Phys = (VOID *) 0;\r
899 AdapterInfo->Block = (VOID *) 0;\r
900 AdapterInfo->Map_Mem = (VOID *) 0;\r
901 AdapterInfo->UnMap_Mem = (VOID *) 0;\r
902 AdapterInfo->Sync_Mem = (VOID *) 0;\r
903 AdapterInfo->Mem_Io = TmpMemIo;\r
904 //\r
905 // these tmp call-backs follow 3.1 undi style\r
906 // i.e. they have the unique_id parameter.\r
907 //\r
908 AdapterInfo->VersionFlag = 0x31;\r
909 AdapterInfo->Unique_ID = (UINT64) (UINTN) AdapterInfo;\r
910\r
911 //\r
912 // undi init portion\r
913 //\r
914 CfgHdr = (PCI_CONFIG_HEADER *) &(AdapterInfo->Config[0]);\r
915 AdapterInfo->ioaddr = 0;\r
916 AdapterInfo->RevID = CfgHdr->RevID;\r
917\r
918 AddrLen = E100bGetEepromAddrLen (AdapterInfo);\r
919\r
920 for (Index = 0, Index2 = 0; Index < 3; Index++) {\r
921 Val = E100bReadEeprom (AdapterInfo, Index, AddrLen);\r
922 MACAddress.Addr[Index2++] = (UINT8) Val;\r
923 MACAddress.Addr[Index2++] = (UINT8) (Val >> 8);\r
924 }\r
925\r
926 SetMem (MACAddress.Addr + Index2, sizeof (EFI_MAC_ADDRESS) - Index2, 0);\r
927 //for (; Index2 < sizeof (EFI_MAC_ADDRESS); Index2++) {\r
928 // MACAddress.Addr[Index2] = 0;\r
929 //}\r
930 //\r
931 // stop undi\r
932 //\r
933 AdapterInfo->Delay = (VOID *) 0;\r
934 AdapterInfo->Mem_Io = (VOID *) 0;\r
935\r
936 //\r
937 // fill the mac address node first\r
938 //\r
939 ZeroMem ((CHAR8 *) &MacAddrNode, sizeof MacAddrNode);\r
940 CopyMem (\r
941 (CHAR8 *) &MacAddrNode.MacAddress,\r
942 (CHAR8 *) &MACAddress,\r
943 sizeof (EFI_MAC_ADDRESS)\r
944 );\r
945\r
946 MacAddrNode.Header.Type = MESSAGING_DEVICE_PATH;\r
947 MacAddrNode.Header.SubType = MSG_MAC_ADDR_DP;\r
948 MacAddrNode.Header.Length[0] = sizeof (MacAddrNode);\r
949 MacAddrNode.Header.Length[1] = 0;\r
950\r
951 //\r
952 // find the size of the base dev path.\r
953 //\r
954 EndNode = BaseDevPtr;\r
955\r
956 while (!IsDevicePathEnd (EndNode)) {\r
957 EndNode = NextDevicePathNode (EndNode);\r
958 }\r
959\r
960 BasePathLen = (UINT16) ((UINTN) (EndNode) - (UINTN) (BaseDevPtr));\r
961\r
962 //\r
963 // create space for full dev path\r
964 //\r
965 TotalPathLen = (UINT16) (BasePathLen + sizeof (MacAddrNode) + sizeof (EFI_DEVICE_PATH_PROTOCOL));\r
966\r
967 Status = gBS->AllocatePool (\r
968 EfiRuntimeServicesData,\r
969 TotalPathLen,\r
970 (VOID **) &DevicePtr\r
971 );\r
972\r
973 if (Status != EFI_SUCCESS) {\r
974 return Status;\r
975 }\r
976 //\r
977 // copy the base path, mac addr and end_dev_path nodes\r
978 //\r
979 *DevPtr = (EFI_DEVICE_PATH_PROTOCOL *) DevicePtr;\r
980 CopyMem (DevicePtr, (CHAR8 *) BaseDevPtr, BasePathLen);\r
981 DevicePtr += BasePathLen;\r
982 CopyMem (DevicePtr, (CHAR8 *) &MacAddrNode, sizeof (MacAddrNode));\r
983 DevicePtr += sizeof (MacAddrNode);\r
984 CopyMem (DevicePtr, (CHAR8 *) EndNode, sizeof (EFI_DEVICE_PATH_PROTOCOL));\r
985\r
986 return EFI_SUCCESS;\r
987}\r
988\r
989EFI_STATUS\r
990InstallConfigTable (\r
991 IN VOID\r
992 )\r
993/*++\r
994\r
995Routine Description:\r
996\r
997 Install a GUID/Pointer pair into the system's configuration table.\r
998\r
999Arguments:\r
1000\r
1001 none\r
1002\r
1003Returns:\r
1004\r
1005 EFI_SUCCESS - Install a GUID/Pointer pair into the system's configuration table.\r
68246fa8 1006\r
40834173 1007 other - Did not successfully install the GUID/Pointer pair into the configuration table.\r
1008\r
1009--*/\r
1010// TODO: VOID - add argument and description to function comment\r
1011{\r
1012 EFI_STATUS Status;\r
1013 EFI_CONFIGURATION_TABLE *CfgPtr;\r
1014 NII_TABLE *TmpData;\r
1015 UINT16 Index;\r
1016 NII_TABLE *UndiData;\r
1017\r
1018 if (pxe_31 == NULL) {\r
1019 return EFI_SUCCESS;\r
1020 }\r
1021\r
68246fa8 1022 if(UndiDataPointer == NULL) {\r
40834173 1023 return EFI_SUCCESS;\r
1024 }\r
68246fa8 1025\r
1026 UndiData = (NII_TABLE *)UndiDataPointer;\r
1027\r
40834173 1028 UndiData->NumEntries = pxe_31->IFcnt;\r
1029 UndiData->NextLink = NULL;\r
1030\r
1031 for (Index = 0; Index < pxe_31->IFcnt; Index++) {\r
1032 UndiData->NiiEntry[Index].InterfacePointer = &UNDI32DeviceList[Index]->NIIProtocol_31;\r
1033 UndiData->NiiEntry[Index].DevicePathPointer = UNDI32DeviceList[Index]->Undi32DevPath;\r
1034 }\r
1035\r
1036 //\r
1037 // see if there is an entry in the config table already\r
1038 //\r
1039 CfgPtr = gST->ConfigurationTable;\r
1040\r
1041 for (Index = 0; Index < gST->NumberOfTableEntries; Index++) {\r
1042 Status = CompareGuid (\r
1043 &CfgPtr->VendorGuid,\r
1044 &gEfiNetworkInterfaceIdentifierProtocolGuid_31\r
1045 );\r
1046 if (Status != EFI_SUCCESS) {\r
1047 break;\r
1048 }\r
1049\r
1050 CfgPtr++;\r
1051 }\r
1052\r
1053 if (Index < gST->NumberOfTableEntries) {\r
1054 TmpData = (NII_TABLE *) CfgPtr->VendorTable;\r
1055\r
1056 //\r
1057 // go to the last link\r
1058 //\r
1059 while (TmpData->NextLink != NULL) {\r
1060 TmpData = TmpData->NextLink;\r
1061 }\r
1062\r
1063 TmpData->NextLink = UndiData;\r
1064\r
1065 //\r
1066 // 1st one in chain\r
1067 //\r
1068 UndiData = (NII_TABLE *) CfgPtr->VendorTable;\r
1069 }\r
1070\r
1071 //\r
1072 // create an entry in the configuration table for our GUID\r
1073 //\r
1074 Status = gBS->InstallConfigurationTable (\r
1075 &gEfiNetworkInterfaceIdentifierProtocolGuid_31,\r
1076 UndiData\r
1077 );\r
1078 return Status;\r
1079}\r
1080\r
1081/**\r
68246fa8 1082\r
40834173 1083 Install driver binding protocol of UNDI.\r
68246fa8 1084\r
1085 @param[in] ImageHandle The firmware allocated handle for the EFI image.\r
40834173 1086 @param[in] SystemTable A pointer to the EFI System Table.\r
68246fa8 1087\r
40834173 1088 @retval EFI_SUCCESS The entry point is executed successfully.\r
1089 @retval other Some error occurs when executing this entry point.\r
1090\r
1091**/\r
1092EFI_STATUS\r
1093EFIAPI\r
1094InitializeUndi(\r
1095 IN EFI_HANDLE ImageHandle,\r
1096 IN EFI_SYSTEM_TABLE *SystemTable\r
1097 )\r
1098{\r
1099 EFI_EVENT Event;\r
1100 EFI_STATUS Status;\r
1101\r
1102 Status = EfiLibInstallDriverBinding (\r
1103 ImageHandle,\r
1104 SystemTable,\r
1105 &gUndiDriverBinding,\r
1106 ImageHandle\r
1107 );\r
1108 ASSERT_EFI_ERROR (Status);\r
1109\r
1110 Status = gBS->CreateEvent (\r
1111 EVT_SIGNAL_EXIT_BOOT_SERVICES,\r
1112 TPL_NOTIFY,\r
1113 UndiNotifyExitBs,\r
1114 NULL,\r
1115 &Event\r
1116 );\r
1117 ASSERT_EFI_ERROR (Status);\r
1118\r
1119 Status = gBS->CreateEvent (\r
1120 EVT_SIGNAL_VIRTUAL_ADDRESS_CHANGE,\r
1121 TPL_NOTIFY,\r
1122 UndiNotifyVirtual,\r
1123 NULL,\r
1124 &Event\r
1125 );\r
1126 ASSERT_EFI_ERROR (Status);\r
1127\r
1128 return Status;\r
1129}\r