]> git.proxmox.com Git - mirror_edk2.git/blame_incremental - MdeModulePkg/Bus/Pci/UndiRuntimeDxe/Init.c
Fixed potential issues to release resources when error occurs.
[mirror_edk2.git] / MdeModulePkg / Bus / Pci / UndiRuntimeDxe / Init.c
... / ...
CommitLineData
1/*++\r
2\r
3Copyright (c) 2006 - 2007, Intel Corporation\r
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
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
25#include <Library/BaseLib.h>\r
26//\r
27// Global Variables\r
28//\r
29\r
30PXE_SW_UNDI *pxe_31 = NULL; // 3.1 entry\r
31UNDI32_DEV *UNDI32DeviceList[MAX_NIC_INTERFACES];\r
32NII_TABLE *UndiDataPointer = NULL;\r
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
105 When EFI is shuting down the boot services, we need to install a\r
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
154\r
155 Controller - Handle of device to test.\r
156\r
157 RemainingDevicePath - Not used.\r
158\r
159Returns:\r
160\r
161 EFI_SUCCESS - This driver supports this device.\r
162\r
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
268\r
269 Controller - Handle of device to work with.\r
270\r
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
276\r
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
288 UINTN Len;\r
289 UINT64 Supports;\r
290 BOOLEAN PciAttributesSaved;\r
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
325 PciAttributesSaved = FALSE;\r
326\r
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
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
350 goto UndiErrorDeleteDevice;\r
351 }\r
352 PciAttributesSaved = TRUE;\r
353\r
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
387\r
388 PxeStructInit (pxe_31);\r
389 }\r
390\r
391 UNDI32Device->NIIProtocol_31.ID = (UINT64) (UINTN) (pxe_31);\r
392\r
393 Status = PciIoFncs->Attributes (\r
394 PciIoFncs,\r
395 EfiPciIoAttributeOperationSupported,\r
396 0,\r
397 &Supports\r
398 );\r
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
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
454 UNDI32Device->NIIProtocol_31.IfNum = pxe_31->IFcnt;\r
455\r
456 PxeUpdate (&UNDI32Device->NicInfo, pxe_31);\r
457\r
458 UNDI32Device->NicInfo.Io_Function = PciIoFncs;\r
459 UNDI32DeviceList[UNDI32Device->NIIProtocol_31.IfNum] = UNDI32Device;\r
460 UNDI32Device->Undi32BaseDevPath = UndiDevicePath;\r
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
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
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
506 // if the table exists, free it and alloc again, or alloc it directly\r
507 //\r
508 if (UndiDataPointer != NULL) {\r
509 Status = gBS->FreePool(UndiDataPointer);\r
510 }\r
511 if (EFI_ERROR (Status)) {\r
512 goto UndiErrorDeleteDevicePath;\r
513 }\r
514\r
515 Len = (pxe_31->IFcnt * sizeof (NII_ENTRY)) + sizeof (UndiDataPointer);\r
516 Status = gBS->AllocatePool (EfiRuntimeServicesData, Len, (VOID **) &UndiDataPointer);\r
517\r
518 if (EFI_ERROR (Status)) {\r
519 goto UndiErrorAllocDataPointer;\r
520 }\r
521\r
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
540 &gEfiDevicePathProtocolGuid,\r
541 UNDI32Device->Undi32DevPath,\r
542 NULL\r
543 );\r
544\r
545UndiErrorDeleteDevicePath:\r
546 UNDI32DeviceList[UNDI32Device->NIIProtocol_31.IfNum] = NULL;\r
547 gBS->FreePool (UNDI32Device->Undi32DevPath);\r
548\r
549UndiErrorDeletePxe:\r
550 PxeUpdate (NULL, pxe_31);\r
551 if (TmpPxePointer != NULL) {\r
552 gBS->FreePool (TmpPxePointer);\r
553\r
554 }\r
555\r
556UndiErrorDeleteDevice:\r
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
568\r
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
655 &gEfiNetworkInterfaceIdentifierProtocolGuid_31,\r
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
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
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
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
736\r
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
766\r
767 ReadWrite - Determine if it is an I/O or Memory Read/Write Operation.\r
768\r
769 Len - Determines the width of the data operation.\r
770\r
771 Port - What port to Read/Write from.\r
772\r
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
866\r
867 BaseDevPtr - Pointer to the device path which the UNDI device driver is latching on to.\r
868\r
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
874\r
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
1006\r
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
1022 if(UndiDataPointer == NULL) {\r
1023 return EFI_SUCCESS;\r
1024 }\r
1025\r
1026 UndiData = (NII_TABLE *)UndiDataPointer;\r
1027\r
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
1082\r
1083 Install driver binding protocol of UNDI.\r
1084\r
1085 @param[in] ImageHandle The firmware allocated handle for the EFI image.\r
1086 @param[in] SystemTable A pointer to the EFI System Table.\r
1087\r
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