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